1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 FsCtrl.c 8 9 Abstract: 10 11 This module implements the File System Control routines for Cdfs called 12 by the Fsd/Fsp dispatch drivers. 13 14 15 --*/ 16 17 #include "cdprocs.h" 18 19 // 20 // The Bug check file id for this module 21 // 22 23 #define BugCheckFileId (CDFS_BUG_CHECK_FSCTRL) 24 25 // 26 // Local constants 27 // 28 29 BOOLEAN CdDisable = FALSE; 30 BOOLEAN CdNoJoliet = FALSE; 31 32 // 33 // Local support routines 34 // 35 36 _Requires_lock_held_(_Global_critical_region_) 37 NTSTATUS 38 CdUserFsctl ( 39 _Inout_ PIRP_CONTEXT IrpContext, 40 _Inout_ PIRP Irp 41 ); 42 43 VOID 44 CdReMountOldVcb ( 45 _In_ PIRP_CONTEXT IrpContext, 46 _Inout_ PVCB OldVcb, 47 _Inout_ PVCB NewVcb, 48 _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo 49 ); 50 51 _Requires_lock_held_(_Global_critical_region_) 52 NTSTATUS 53 CdMountVolume ( 54 _Inout_ PIRP_CONTEXT IrpContext, 55 _Inout_ PIRP Irp 56 ); 57 58 _Requires_lock_held_(_Global_critical_region_) 59 NTSTATUS 60 CdVerifyVolume ( 61 _Inout_ PIRP_CONTEXT IrpContext, 62 _Inout_ PIRP Irp 63 ); 64 65 _Requires_lock_held_(_Global_critical_region_) 66 NTSTATUS 67 CdOplockRequest ( 68 _Inout_ PIRP_CONTEXT IrpContext, 69 _Inout_ PIRP Irp 70 ); 71 72 _Requires_lock_held_(_Global_critical_region_) 73 NTSTATUS 74 CdLockVolume ( 75 _Inout_ PIRP_CONTEXT IrpContext, 76 _Inout_ PIRP Irp 77 ); 78 79 _Requires_lock_held_(_Global_critical_region_) 80 NTSTATUS 81 CdUnlockVolume ( 82 _Inout_ PIRP_CONTEXT IrpContext, 83 _Inout_ PIRP Irp 84 ); 85 86 _Requires_lock_held_(_Global_critical_region_) 87 NTSTATUS 88 CdDismountVolume ( 89 _Inout_ PIRP_CONTEXT IrpContext, 90 _Inout_ PIRP Irp 91 ); 92 93 NTSTATUS 94 CdIsVolumeDirty ( 95 _Inout_ PIRP_CONTEXT IrpContext, 96 _Inout_ PIRP Irp 97 ); 98 99 NTSTATUS 100 CdIsVolumeMounted ( 101 _Inout_ PIRP_CONTEXT IrpContext, 102 _Inout_ PIRP Irp 103 ); 104 105 NTSTATUS 106 CdIsPathnameValid ( 107 _Inout_ PIRP_CONTEXT IrpContext, 108 _Inout_ PIRP Irp 109 ); 110 111 _Requires_lock_held_(_Global_critical_region_) 112 NTSTATUS 113 CdInvalidateVolumes ( 114 _Inout_ PIRP_CONTEXT IrpContext, 115 _Inout_ PIRP Irp 116 ); 117 118 NTSTATUS 119 CdAllowExtendedDasdIo ( 120 _Inout_ PIRP_CONTEXT IrpContext, 121 _Inout_ PIRP Irp 122 ); 123 124 _Requires_lock_held_(_Global_critical_region_) 125 VOID 126 CdScanForDismountedVcb ( 127 _Inout_ PIRP_CONTEXT IrpContext 128 ); 129 130 _Success_(return != FALSE) 131 BOOLEAN 132 CdFindPrimaryVd ( 133 _In_ PIRP_CONTEXT IrpContext, 134 _Inout_ PVCB Vcb, 135 _Out_writes_bytes_(SECTOR_SIZE) PCHAR RawIsoVd, 136 _In_ ULONG BlockFactor, 137 _In_ BOOLEAN ReturnOnError, 138 _In_ BOOLEAN VerifyVolume 139 ); 140 141 _Success_(return != FALSE) BOOLEAN 142 CdIsRemount ( 143 _In_ PIRP_CONTEXT IrpContext, 144 _In_ PVCB Vcb, 145 _Out_ PVCB *OldVcb 146 ); 147 148 VOID 149 CdFindActiveVolDescriptor ( 150 _In_ PIRP_CONTEXT IrpContext, 151 _In_ PVCB Vcb, 152 _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE )) PCHAR RawIsoVd, 153 _In_ BOOLEAN VerifyVolume 154 ); 155 156 #ifdef ALLOC_PRAGMA 157 #pragma alloc_text(PAGE, CdCommonFsControl) 158 #pragma alloc_text(PAGE, CdDismountVolume) 159 #pragma alloc_text(PAGE, CdFindActiveVolDescriptor) 160 #pragma alloc_text(PAGE, CdFindPrimaryVd) 161 #pragma alloc_text(PAGE, CdIsPathnameValid) 162 #pragma alloc_text(PAGE, CdIsRemount) 163 #pragma alloc_text(PAGE, CdIsVolumeDirty) 164 #pragma alloc_text(PAGE, CdIsVolumeMounted) 165 #pragma alloc_text(PAGE, CdLockVolume) 166 #pragma alloc_text(PAGE, CdMountVolume) 167 #pragma alloc_text(PAGE, CdOplockRequest) 168 #pragma alloc_text(PAGE, CdAllowExtendedDasdIo) 169 #pragma alloc_text(PAGE, CdScanForDismountedVcb) 170 #pragma alloc_text(PAGE, CdUnlockVolume) 171 #pragma alloc_text(PAGE, CdUserFsctl) 172 #pragma alloc_text(PAGE, CdVerifyVolume) 173 #endif 174 175 176 // 177 // Local support routine 178 // 179 180 _Requires_lock_held_(_Global_critical_region_) 181 _Requires_lock_held_(Vcb->VcbResource) 182 NTSTATUS 183 CdLockVolumeInternal ( 184 _In_ PIRP_CONTEXT IrpContext, 185 _Inout_ PVCB Vcb, 186 _In_opt_ PFILE_OBJECT FileObject 187 ) 188 189 /*++ 190 191 Routine Description: 192 193 This routine performs the actual lock volume operation. It will be called 194 by anyone wishing to try to protect the volume for a long duration. PNP 195 operations are such a user. 196 197 The volume must be held exclusive by the caller. 198 199 Arguments: 200 201 Vcb - The volume being locked. 202 203 FileObject - File corresponding to the handle locking the volume. If this 204 is not specified, a system lock is assumed. 205 206 Return Value: 207 208 NTSTATUS - The return status for the operation 209 210 --*/ 211 212 { 213 NTSTATUS Status; 214 KIRQL SavedIrql; 215 NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY); 216 ULONG RemainingUserReferences = (FileObject? 1: 0); 217 218 // 219 // The cleanup count for the volume only reflects the fileobject that 220 // will lock the volume. Otherwise, we must fail the request. 221 // 222 // Since the only cleanup is for the provided fileobject, we will try 223 // to get rid of all of the other user references. If there is only one 224 // remaining after the purge then we can allow the volume to be locked. 225 // 226 227 CdPurgeVolume( IrpContext, Vcb, FALSE ); 228 229 // 230 // Now back out of our synchronization and wait for the lazy writer 231 // to finish off any lazy closes that could have been outstanding. 232 // 233 // Since we purged, we know that the lazy writer will issue all 234 // possible lazy closes in the next tick - if we hadn't, an otherwise 235 // unopened file with a large amount of dirty data could have hung 236 // around for a while as the data trickled out to the disk. 237 // 238 // This is even more important now since we send notification to 239 // alert other folks that this style of check is about to happen so 240 // that they can close their handles. We don't want to enter a fast 241 // race with the lazy writer tearing down his references to the file. 242 // 243 244 CdReleaseVcb( IrpContext, Vcb ); 245 246 Status = CcWaitForCurrentLazyWriterActivity(); 247 248 // 249 // This is intentional. If we were able to get the Vcb before, just 250 // wait for it and take advantage of knowing that it is OK to leave 251 // the flag up. 252 // 253 254 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 255 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 256 257 if (!NT_SUCCESS( Status )) { 258 259 return Status; 260 } 261 262 CdFspClose( Vcb ); 263 264 // 265 // If the volume is already explicitly locked then fail. We use the 266 // Vpb locked flag as an 'explicit lock' flag in the same way as Fat. 267 // 268 269 IoAcquireVpbSpinLock( &SavedIrql ); 270 271 if (!FlagOn( Vcb->Vpb->Flags, VPB_LOCKED ) && 272 (Vcb->VcbCleanup == RemainingUserReferences) && 273 (Vcb->VcbUserReference == CDFS_RESIDUAL_USER_REFERENCE + RemainingUserReferences)) { 274 275 SetFlag( Vcb->VcbState, VCB_STATE_LOCKED ); 276 SetFlag( Vcb->Vpb->Flags, VPB_LOCKED); 277 Vcb->VolumeLockFileObject = FileObject; 278 FinalStatus = STATUS_SUCCESS; 279 } 280 281 IoReleaseVpbSpinLock( SavedIrql ); 282 283 return FinalStatus; 284 } 285 286 287 NTSTATUS 288 CdUnlockVolumeInternal ( 289 _In_ PIRP_CONTEXT IrpContext, 290 _Inout_ PVCB Vcb, 291 _In_opt_ PFILE_OBJECT FileObject 292 ) 293 294 /*++ 295 296 Routine Description: 297 298 This routine performs the actual unlock volume operation. 299 300 The volume must be held exclusive by the caller. 301 302 Arguments: 303 304 Vcb - The volume being locked. 305 306 FileObject - File corresponding to the handle locking the volume. If this 307 is not specified, a system lock is assumed. 308 309 Return Value: 310 311 NTSTATUS - The return status for the operation 312 313 Attempting to remove a system lock that did not exist is OK. 314 315 --*/ 316 317 { 318 NTSTATUS Status = STATUS_NOT_LOCKED; 319 KIRQL SavedIrql; 320 321 UNREFERENCED_PARAMETER( IrpContext ); 322 323 // 324 // Note that we check the VPB_LOCKED flag here rather than the Vcb 325 // lock flag. The Vpb flag is only set for an explicit lock request, not 326 // for the implicit lock obtained on a volume open with zero share mode. 327 // 328 329 IoAcquireVpbSpinLock( &SavedIrql ); 330 331 if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && 332 (FileObject == Vcb->VolumeLockFileObject)) { 333 334 ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED ); 335 ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED); 336 Vcb->VolumeLockFileObject = NULL; 337 Status = STATUS_SUCCESS; 338 } 339 340 IoReleaseVpbSpinLock( SavedIrql ); 341 342 return Status; 343 } 344 345 346 347 _Requires_lock_held_(_Global_critical_region_) 348 NTSTATUS 349 CdCommonFsControl ( 350 _Inout_ PIRP_CONTEXT IrpContext, 351 _Inout_ PIRP Irp 352 ) 353 354 /*++ 355 356 Routine Description: 357 358 This is the common routine for doing FileSystem control operations called 359 by both the fsd and fsp threads 360 361 Arguments: 362 363 Irp - Supplies the Irp to process 364 365 Return Value: 366 367 NTSTATUS - The return status for the operation 368 369 --*/ 370 371 { 372 NTSTATUS Status; 373 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 374 375 PAGED_CODE(); 376 377 // 378 // We know this is a file system control so we'll case on the 379 // minor function, and call a internal worker routine to complete 380 // the irp. 381 // 382 383 switch (IrpSp->MinorFunction) { 384 385 case IRP_MN_USER_FS_REQUEST: 386 387 Status = CdUserFsctl( IrpContext, Irp ); 388 break; 389 390 case IRP_MN_MOUNT_VOLUME: 391 392 Status = CdMountVolume( IrpContext, Irp ); 393 break; 394 395 case IRP_MN_VERIFY_VOLUME: 396 397 Status = CdVerifyVolume( IrpContext, Irp ); 398 break; 399 400 default: 401 402 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 403 Status = STATUS_INVALID_DEVICE_REQUEST; 404 break; 405 } 406 407 return Status; 408 } 409 410 411 // 412 // Local support routine 413 // 414 415 _Requires_lock_held_(_Global_critical_region_) 416 NTSTATUS 417 CdUserFsctl ( 418 _Inout_ PIRP_CONTEXT IrpContext, 419 _Inout_ PIRP Irp 420 ) 421 /*++ 422 423 Routine Description: 424 425 This is the common routine for implementing the user's requests made 426 through NtFsControlFile. 427 428 Arguments: 429 430 Irp - Supplies the Irp being processed 431 432 Return Value: 433 434 NTSTATUS - The return status for the operation 435 436 --*/ 437 438 { 439 NTSTATUS Status; 440 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 441 442 PAGED_CODE(); 443 444 // 445 // Case on the control code. 446 // 447 448 switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) { 449 450 case FSCTL_REQUEST_OPLOCK_LEVEL_1 : 451 case FSCTL_REQUEST_OPLOCK_LEVEL_2 : 452 case FSCTL_REQUEST_BATCH_OPLOCK : 453 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE : 454 case FSCTL_OPBATCH_ACK_CLOSE_PENDING : 455 case FSCTL_OPLOCK_BREAK_NOTIFY : 456 case FSCTL_OPLOCK_BREAK_ACK_NO_2 : 457 case FSCTL_REQUEST_FILTER_OPLOCK : 458 459 Status = CdOplockRequest( IrpContext, Irp ); 460 break; 461 462 case FSCTL_LOCK_VOLUME : 463 464 Status = CdLockVolume( IrpContext, Irp ); 465 break; 466 467 case FSCTL_UNLOCK_VOLUME : 468 469 Status = CdUnlockVolume( IrpContext, Irp ); 470 break; 471 472 case FSCTL_DISMOUNT_VOLUME : 473 474 Status = CdDismountVolume( IrpContext, Irp ); 475 break; 476 477 case FSCTL_IS_VOLUME_DIRTY : 478 479 Status = CdIsVolumeDirty( IrpContext, Irp ); 480 break; 481 482 case FSCTL_IS_VOLUME_MOUNTED : 483 484 Status = CdIsVolumeMounted( IrpContext, Irp ); 485 break; 486 487 case FSCTL_IS_PATHNAME_VALID : 488 489 Status = CdIsPathnameValid( IrpContext, Irp ); 490 break; 491 492 case FSCTL_INVALIDATE_VOLUMES : 493 494 Status = CdInvalidateVolumes( IrpContext, Irp ); 495 break; 496 497 case FSCTL_ALLOW_EXTENDED_DASD_IO: 498 499 Status = CdAllowExtendedDasdIo( IrpContext, Irp ); 500 break; 501 502 // 503 // We don't support any of the known or unknown requests. 504 // 505 506 default: 507 508 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 509 Status = STATUS_INVALID_DEVICE_REQUEST; 510 break; 511 } 512 513 return Status; 514 } 515 516 517 VOID 518 CdReMountOldVcb ( 519 _In_ PIRP_CONTEXT IrpContext, 520 _Inout_ PVCB OldVcb, 521 _Inout_ PVCB NewVcb, 522 _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo 523 ) 524 { 525 KIRQL SavedIrql; 526 ULONG Index; 527 PUCHAR Buffer; 528 529 UNREFERENCED_PARAMETER( IrpContext ); 530 531 ObDereferenceObject( OldVcb->TargetDeviceObject ); 532 533 IoAcquireVpbSpinLock( &SavedIrql ); 534 535 #ifdef _MSC_VER 536 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed") 537 #endif 538 NewVcb->Vpb->RealDevice->Vpb = OldVcb->Vpb; 539 540 OldVcb->Vpb->RealDevice = NewVcb->Vpb->RealDevice; 541 OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo; 542 543 CdUpdateVcbCondition( OldVcb, VcbMounted); 544 CdUpdateMediaChangeCount( OldVcb, NewVcb->MediaChangeCount); 545 546 ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE); 547 548 Buffer = OldVcb->SectorCacheBuffer = NewVcb->SectorCacheBuffer; 549 NewVcb->SectorCacheBuffer = NULL; 550 551 if (NULL != Buffer) { 552 553 for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) { 554 555 OldVcb->SecCacheChunks[ Index].Buffer = Buffer; 556 OldVcb->SecCacheChunks[ Index].BaseLbn = (ULONG)-1; 557 558 Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE; 559 } 560 } 561 562 IoReleaseVpbSpinLock( SavedIrql ); 563 } 564 565 566 // 567 // Local support routine 568 // 569 570 _Requires_lock_held_(_Global_critical_region_) 571 NTSTATUS 572 CdMountVolume ( 573 _Inout_ PIRP_CONTEXT IrpContext, 574 _Inout_ PIRP Irp 575 ) 576 577 /*++ 578 579 Routine Description: 580 581 This routine performs the mount volume operation. It is responsible for 582 either completing of enqueuing the input Irp. 583 584 Its job is to verify that the volume denoted in the IRP is a Cdrom volume, 585 and create the VCB and root DCB structures. The algorithm it 586 uses is essentially as follows: 587 588 1. Create a new Vcb Structure, and initialize it enough to do I/O 589 through the on-disk volume descriptors. 590 591 2. Read the disk and check if it is a Cdrom volume. 592 593 3. If it is not a Cdrom volume then delete the Vcb and 594 complete the IRP back with an appropriate status. 595 596 4. Check if the volume was previously mounted and if it was then do a 597 remount operation. This involves deleting the VCB, hook in the 598 old VCB, and complete the IRP. 599 600 5. Otherwise create a Vcb and root DCB for each valid volume descriptor. 601 602 Arguments: 603 604 Irp - Supplies the Irp to process 605 606 Return Value: 607 608 NTSTATUS - The return status for the operation 609 610 --*/ 611 612 { 613 NTSTATUS Status; 614 615 PVOLUME_DEVICE_OBJECT VolDo = NULL; 616 PVCB Vcb = NULL; 617 PVCB OldVcb; 618 UCHAR StackSize; 619 620 BOOLEAN FoundPvd = FALSE; 621 BOOLEAN SetDoVerifyOnFail; 622 623 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 624 PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject; 625 PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; 626 627 PFILE_OBJECT FileObjectToNotify = NULL; 628 629 ULONG BlockFactor; 630 DISK_GEOMETRY DiskGeometry; 631 632 IO_SCSI_CAPABILITIES Capabilities; 633 634 IO_STATUS_BLOCK Iosb; 635 636 PCHAR RawIsoVd = NULL; 637 638 PCDROM_TOC_LARGE CdromToc = NULL; 639 ULONG TocLength = 0; 640 ULONG TocTrackCount = 0; 641 ULONG TocDiskFlags = 0; 642 ULONG MediaChangeCount = 0; 643 644 #ifdef __REACTOS__ 645 DEVICE_TYPE FilesystemDeviceType; 646 #endif 647 648 #ifdef CDFS_TELEMETRY_DATA 649 GUID VolumeGuid; 650 GUID VolumeCorrelationId = { 0 }; 651 #endif 652 653 PAGED_CODE(); 654 655 // 656 // Check that we are talking to a Cdrom device. This request should 657 // always be waitable. 658 // 659 660 #ifdef __REACTOS__ 661 if (IrpSp->DeviceObject == CdData.HddFileSystemDeviceObject) { 662 FilesystemDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; 663 } else { 664 #endif 665 NT_ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ); 666 #ifdef __REACTOS__ 667 FilesystemDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; 668 } 669 #endif 670 NT_ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )); 671 672 #ifdef CDFS_TELEMETRY_DATA 673 // 674 // We don't want a bogus VolumeGuid to show up in our telemetry 675 // 676 677 RtlZeroMemory( &VolumeGuid, sizeof(GUID) ); 678 679 #endif 680 681 // 682 // Update the real device in the IrpContext from the Vpb. There was no available 683 // file object when the IrpContext was created. 684 // 685 686 IrpContext->RealDevice = Vpb->RealDevice; 687 688 SetDoVerifyOnFail = CdRealDevNeedsVerify( IrpContext->RealDevice); 689 690 // 691 // Check if we have disabled the mount process. 692 // 693 694 if (CdDisable) { 695 696 CdCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME ); 697 return STATUS_UNRECOGNIZED_VOLUME; 698 } 699 700 // 701 // If we've shutdown disallow further mounts. 702 // 703 704 if (FlagOn( CdData.Flags, CD_FLAGS_SHUTDOWN )) { 705 706 CdCompleteRequest( IrpContext, Irp, STATUS_SYSTEM_SHUTDOWN ); 707 return STATUS_SYSTEM_SHUTDOWN; 708 } 709 710 // 711 // Do a CheckVerify here to lift the MediaChange ticker from the driver 712 // 713 714 Status = CdPerformDevIoCtrl( IrpContext, 715 #ifndef __REACTOS__ 716 IOCTL_CDROM_CHECK_VERIFY, 717 #else 718 (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ? IOCTL_DISK_CHECK_VERIFY : IOCTL_CDROM_CHECK_VERIFY), 719 #endif 720 DeviceObjectWeTalkTo, 721 &MediaChangeCount, 722 sizeof(ULONG), 723 FALSE, 724 TRUE, 725 &Iosb ); 726 727 if (!NT_SUCCESS( Status )) { 728 729 CdCompleteRequest( IrpContext, Irp, Status ); 730 return Status; 731 } 732 733 if (Iosb.Information != sizeof(ULONG)) { 734 735 // 736 // Be safe about the count in case the driver didn't fill it in 737 // 738 739 MediaChangeCount = 0; 740 } 741 742 // 743 // Now let's make Jeff delirious and call to get the disk geometry. This 744 // will fix the case where the first change line is swallowed. 745 // 746 747 Status = CdPerformDevIoCtrl( IrpContext, 748 #ifndef __REACTOS__ 749 IOCTL_CDROM_GET_DRIVE_GEOMETRY, 750 #else 751 (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ? IOCTL_DISK_GET_DRIVE_GEOMETRY : IOCTL_CDROM_GET_DRIVE_GEOMETRY), 752 #endif 753 DeviceObjectWeTalkTo, 754 &DiskGeometry, 755 sizeof( DISK_GEOMETRY ), 756 FALSE, 757 TRUE, 758 NULL ); 759 760 // 761 // Return insufficient sources to our caller. 762 // 763 764 if (Status == STATUS_INSUFFICIENT_RESOURCES) { 765 766 CdCompleteRequest( IrpContext, Irp, Status ); 767 return Status; 768 } 769 770 // 771 // Now check the block factor for addressing the volume descriptors. 772 // If the call for the disk geometry failed then assume there is one 773 // block per sector. 774 // 775 776 BlockFactor = 1; 777 778 if (NT_SUCCESS( Status ) && 779 (DiskGeometry.BytesPerSector != 0) && 780 (DiskGeometry.BytesPerSector < SECTOR_SIZE)) { 781 782 BlockFactor = SECTOR_SIZE / DiskGeometry.BytesPerSector; 783 } 784 785 // 786 // Acquire the global resource to do mount operations. 787 // 788 789 CdAcquireCdData( IrpContext ); 790 791 // 792 // Use a try-finally to facilitate cleanup. 793 // 794 795 _SEH2_TRY { 796 797 // 798 // Allocate a buffer to query the TOC. 799 // 800 801 CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool, 802 sizeof( CDROM_TOC_LARGE ), 803 TAG_CDROM_TOC ); 804 805 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE )); 806 807 // 808 // Do a quick check to see if there any Vcb's which can be removed. 809 // 810 811 CdScanForDismountedVcb( IrpContext ); 812 813 // 814 // Get our device object and alignment requirement. 815 // 816 817 Status = IoCreateDevice( CdData.DriverObject, 818 sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ), 819 NULL, 820 #ifndef __REACTOS__ 821 FILE_DEVICE_CD_ROM_FILE_SYSTEM, 822 #else 823 FilesystemDeviceType, 824 #endif 825 0, 826 FALSE, 827 (PDEVICE_OBJECT *) &VolDo ); 828 829 if (!NT_SUCCESS( Status )) { try_leave( Status ); } 830 831 // 832 // Our alignment requirement is the larger of the processor alignment requirement 833 // already in the volume device object and that in the DeviceObjectWeTalkTo 834 // 835 836 if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) { 837 838 VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement; 839 } 840 841 // 842 // We must initialize the stack size in our device object before 843 // the following reads, because the I/O system has not done it yet. 844 // 845 846 ((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1); 847 StackSize = ((PDEVICE_OBJECT) VolDo)->StackSize; 848 849 ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING ); 850 851 // 852 // Initialize the overflow queue for the volume 853 // 854 855 VolDo->OverflowQueueCount = 0; 856 InitializeListHead( &VolDo->OverflowQueue ); 857 858 VolDo->PostedRequestCount = 0; 859 KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock ); 860 861 // 862 // Let's query for the Toc now and handle any error we get from this operation. 863 // 864 865 Status = CdProcessToc( IrpContext, 866 DeviceObjectWeTalkTo, 867 CdromToc, 868 &TocLength, 869 &TocTrackCount, 870 &TocDiskFlags ); 871 872 // 873 // If we failed to read the TOC, then bail out. Probably blank media. 874 // 875 876 if (Status != STATUS_SUCCESS) { 877 878 #ifdef __REACTOS__ 879 880 // 881 // Don't bail out if that was a disk based ISO image, it is legit 882 // 883 884 if (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) { 885 CdFreePool( &CdromToc ); 886 Status = STATUS_SUCCESS; 887 } else { 888 #endif 889 try_leave( Status ); 890 #ifdef __REACTOS__ 891 } 892 #endif 893 } 894 895 // 896 // Now before we can initialize the Vcb we need to set up the 897 // device object field in the VPB to point to our new volume device 898 // object. 899 // 900 901 Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo; 902 903 // 904 // Initialize the Vcb. This routine will raise on an allocation 905 // failure. 906 // 907 908 CdInitializeVcb( IrpContext, 909 &VolDo->Vcb, 910 DeviceObjectWeTalkTo, 911 Vpb, 912 CdromToc, 913 TocLength, 914 TocTrackCount, 915 TocDiskFlags, 916 BlockFactor, 917 MediaChangeCount ); 918 919 // 920 // Show that we initialized the Vcb and can cleanup with the Vcb. 921 // 922 923 Vcb = &VolDo->Vcb; 924 VolDo = NULL; 925 Vpb = NULL; 926 CdromToc = NULL; 927 928 #ifdef CDFS_TELEMETRY_DATA 929 930 // 931 // Initialize the volume guid. 932 // 933 934 if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb->TargetDeviceObject, &VolumeGuid ))) { 935 936 // 937 // We got a GUID, set it in the Telemetry structure 938 // 939 940 RtlCopyMemory( &CdTelemetryData.VolumeGuid, &VolumeGuid, sizeof(GUID) ); 941 } 942 943 // 944 // Initialize the correlation ID. 945 // 946 947 if (NT_SUCCESS( FsRtlVolumeDeviceToCorrelationId( Vcb->TargetDeviceObject, &VolumeCorrelationId ) )) { 948 949 // 950 // Stash a copy away in the VCB. 951 // 952 953 RtlCopyMemory( &Vcb->VolumeCorrelationId, &VolumeCorrelationId, sizeof( GUID ) ); 954 } 955 956 #endif // CDFS_TELEMETRY_DATA 957 958 // Lock object is acquired and released using internal state 959 _Analysis_suppress_lock_checking_(Vcb->VcbResource); 960 961 // 962 // Store the Vcb in the IrpContext as we didn't have one before. 963 // 964 965 IrpContext->Vcb = Vcb; 966 967 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 968 969 // 970 // Let's reference the Vpb to make sure we are the one to 971 // have the last dereference. 972 // 973 974 Vcb->Vpb->ReferenceCount += 1; 975 976 // 977 // Clear the verify bit for the start of mount. 978 // 979 980 CdMarkRealDevVerifyOk( Vcb->Vpb->RealDevice); 981 982 if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) { 983 984 // 985 // Allocate a buffer to read in the volume descriptors. We allocate a full 986 // page to make sure we don't hit any alignment problems. 987 // 988 989 RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool, 990 ROUND_TO_PAGES( SECTOR_SIZE ), 991 TAG_VOL_DESC ); 992 993 // 994 // Try to find the primary volume descriptor. 995 // 996 997 FoundPvd = CdFindPrimaryVd( IrpContext, 998 Vcb, 999 RawIsoVd, 1000 BlockFactor, 1001 TRUE, 1002 FALSE ); 1003 1004 if (!FoundPvd) { 1005 1006 // 1007 // We failed to find a valid VD in the data track, but there were also 1008 // audio tracks on this disc, so we'll try to mount it as an audio CD. 1009 // Since we're always last in the mount order, we won't be preventing 1010 // any other FS from trying to mount the data track. However if the 1011 // data track was at the start of the disc, then we abort, to avoid 1012 // having to filter it from our synthesised directory listing later. We 1013 // already filtered off any data track at the end. 1014 // 1015 1016 if (!(TocDiskFlags & CDROM_DISK_AUDIO_TRACK) || 1017 BooleanFlagOn( Vcb->CdromToc->TrackData[0].Control, TOC_DATA_TRACK)) { 1018 1019 try_leave( Status = STATUS_UNRECOGNIZED_VOLUME); 1020 } 1021 1022 SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA ); 1023 1024 CdFreePool( &RawIsoVd ); 1025 RawIsoVd = NULL; 1026 } 1027 } 1028 1029 // 1030 // Look and see if there is a secondary volume descriptor we want to 1031 // use. 1032 // 1033 1034 if (FoundPvd) { 1035 1036 // 1037 // Store the primary volume descriptor in the second half of 1038 // RawIsoVd. Then if our search for a secondary fails we can 1039 // recover this immediately. 1040 // 1041 1042 RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ), 1043 RawIsoVd, 1044 SECTOR_SIZE ); 1045 1046 // 1047 // We have the initial volume descriptor. Locate a secondary 1048 // volume descriptor if present. 1049 // 1050 1051 CdFindActiveVolDescriptor( IrpContext, 1052 Vcb, 1053 RawIsoVd, 1054 FALSE); 1055 } 1056 1057 // 1058 // Allocate a block cache to speed directory operations. We can't 1059 // use the cache if there is any chance the volume has link blocks 1060 // in the data area (i.e. was packet written and then finalized to 1061 // Joliet/9660). So we simply only allow the cache to operate on 1062 // media with a single track - since we're really targetting pressed 1063 // installation media here. We can't be more precise, since D/CD-ROM 1064 // drives don't support READ_TRACK_INFO, which is the only way for 1065 // certain to know whether or not a track was packet written. 1066 // 1067 1068 if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK) && 1069 #ifndef __REACTOS__ 1070 ((Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack) == 0)) { 1071 #else 1072 ((FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || 1073 ((Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack) == 0))) { 1074 #endif 1075 1076 ULONG Index; 1077 PUCHAR Buffer; 1078 1079 Buffer = 1080 Vcb->SectorCacheBuffer = FsRtlAllocatePool( CdPagedPool, 1081 CD_SEC_CACHE_CHUNKS * 1082 CD_SEC_CHUNK_BLOCKS * 1083 SECTOR_SIZE); 1084 1085 for (Index = 0; Index < (ULONG)CD_SEC_CACHE_CHUNKS; Index++) { 1086 1087 Vcb->SecCacheChunks[ Index].Buffer = Buffer; 1088 Vcb->SecCacheChunks[ Index].BaseLbn = (ULONG)-1; 1089 1090 Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE; 1091 } 1092 1093 Vcb->SectorCacheIrp = IoAllocateIrp( StackSize, FALSE); 1094 1095 if (Vcb->SectorCacheIrp == NULL) { 1096 1097 try_leave( Status = STATUS_INSUFFICIENT_RESOURCES ); 1098 } 1099 1100 IoInitializeIrp( Vcb->SectorCacheIrp, 1101 IoSizeOfIrp( StackSize), 1102 (CCHAR)StackSize); 1103 1104 KeInitializeEvent( &Vcb->SectorCacheEvent, SynchronizationEvent, FALSE); 1105 ExInitializeResourceLite( &Vcb->SectorCacheResource); 1106 } 1107 1108 // 1109 // Check if this is a remount operation. If so then clean up 1110 // the data structures passed in and created here. 1111 // 1112 1113 if (CdIsRemount( IrpContext, Vcb, &OldVcb )) { 1114 1115 NT_ASSERT( NULL != OldVcb->SwapVpb ); 1116 1117 // 1118 // Link the old Vcb to point to the new device object that we 1119 // should be talking to, dereferencing the previous. Call a 1120 // nonpaged routine to do this since we take the Vpb spinlock. 1121 // 1122 1123 CdReMountOldVcb( IrpContext, 1124 OldVcb, 1125 Vcb, 1126 DeviceObjectWeTalkTo); 1127 1128 // 1129 // See if we will need to provide notification of the remount. This is the readonly 1130 // filesystem's form of dismount/mount notification - we promise that whenever a 1131 // volume is "dismounted", that a mount notification will occur when it is revalidated. 1132 // Note that we do not send mount on normal remounts - that would duplicate the media 1133 // arrival notification of the device driver. 1134 // 1135 1136 if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) { 1137 1138 ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT ); 1139 1140 FileObjectToNotify = OldVcb->RootIndexFcb->FileObject; 1141 ObReferenceObject( FileObjectToNotify ); 1142 } 1143 1144 try_leave( Status = STATUS_SUCCESS ); 1145 } 1146 1147 // 1148 // This is a new mount. Go ahead and initialize the 1149 // Vcb from the volume descriptor. 1150 // 1151 1152 CdUpdateVcbFromVolDescriptor( IrpContext, 1153 Vcb, 1154 RawIsoVd ); 1155 1156 // 1157 // Drop an extra reference on the root dir file so we'll be able to send 1158 // notification. 1159 // 1160 1161 if (Vcb->RootIndexFcb) { 1162 1163 FileObjectToNotify = Vcb->RootIndexFcb->FileObject; 1164 ObReferenceObject( FileObjectToNotify ); 1165 } 1166 1167 // 1168 // Now check the maximum transfer limits on the device in case we 1169 // get raw reads on this volume. 1170 // 1171 1172 Status = CdPerformDevIoCtrl( IrpContext, 1173 IOCTL_SCSI_GET_CAPABILITIES, 1174 DeviceObjectWeTalkTo, 1175 &Capabilities, 1176 sizeof( IO_SCSI_CAPABILITIES ), 1177 FALSE, 1178 TRUE, 1179 NULL ); 1180 1181 if (NT_SUCCESS(Status)) { 1182 1183 Vcb->MaximumTransferRawSectors = Capabilities.MaximumTransferLength / RAW_SECTOR_SIZE; 1184 Vcb->MaximumPhysicalPages = Capabilities.MaximumPhysicalPages; 1185 1186 } else { 1187 1188 // 1189 // This should never happen, but we can safely assume 64k and 16 pages. 1190 // 1191 1192 Vcb->MaximumTransferRawSectors = (64 * 1024) / RAW_SECTOR_SIZE; 1193 Vcb->MaximumPhysicalPages = 16; 1194 } 1195 1196 // 1197 // The new mount is complete. Remove the additional references on this 1198 // Vcb and the device we are mounted on top of. 1199 // 1200 1201 Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE; 1202 NT_ASSERT( Vcb->VcbReference == CDFS_RESIDUAL_REFERENCE ); 1203 1204 ObDereferenceObject( Vcb->TargetDeviceObject ); 1205 1206 CdUpdateVcbCondition( Vcb, VcbMounted); 1207 1208 CdReleaseVcb( IrpContext, Vcb ); 1209 Vcb = NULL; 1210 1211 Status = STATUS_SUCCESS; 1212 1213 } _SEH2_FINALLY { 1214 1215 // 1216 // Free the TOC buffer if not in the Vcb. 1217 // 1218 1219 if (CdromToc != NULL) { 1220 1221 CdFreePool( &CdromToc ); 1222 } 1223 1224 // 1225 // Free the sector buffer if allocated. 1226 // 1227 1228 if (RawIsoVd != NULL) { 1229 1230 CdFreePool( &RawIsoVd ); 1231 } 1232 1233 // 1234 // If we are not mounting the device, then set the verify bit again. 1235 // 1236 1237 if ((_SEH2_AbnormalTermination() || (Status != STATUS_SUCCESS)) && 1238 SetDoVerifyOnFail) { 1239 1240 CdMarkRealDevForVerify( IrpContext->RealDevice); 1241 } 1242 1243 // 1244 // If we didn't complete the mount then cleanup any remaining structures. 1245 // 1246 1247 if (Vpb != NULL) { Vpb->DeviceObject = NULL; } 1248 1249 if (Vcb != NULL) { 1250 1251 // 1252 // Make sure there is no Vcb in the IrpContext since it could go away 1253 // 1254 1255 IrpContext->Vcb = NULL; 1256 1257 Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE; 1258 1259 if (CdDismountVcb( IrpContext, Vcb )) { 1260 1261 CdReleaseVcb( IrpContext, Vcb ); 1262 } 1263 1264 } else if (VolDo != NULL) { 1265 1266 IoDeleteDevice( (PDEVICE_OBJECT) VolDo ); 1267 } 1268 1269 // 1270 // Release the global resource. 1271 // 1272 1273 CdReleaseCdData( IrpContext ); 1274 } _SEH2_END; 1275 1276 // 1277 // Now send mount notification. 1278 // 1279 1280 if (FileObjectToNotify) { 1281 1282 FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT ); 1283 ObDereferenceObject( FileObjectToNotify ); 1284 } 1285 1286 #ifdef CDFS_TELEMETRY_DATA 1287 1288 // 1289 // Send Telemetry 1290 // 1291 1292 CdTelemetryMountSafe( &VolumeCorrelationId, STATUS_SUCCESS, Vcb ); 1293 1294 #endif 1295 1296 // 1297 // Complete the request if no exception. 1298 // 1299 1300 CdCompleteRequest( IrpContext, Irp, Status ); 1301 return Status; 1302 } 1303 1304 1305 // 1306 // Local support routine 1307 // 1308 1309 _Requires_lock_held_(_Global_critical_region_) 1310 NTSTATUS 1311 CdVerifyVolume ( 1312 _Inout_ PIRP_CONTEXT IrpContext, 1313 _Inout_ PIRP Irp 1314 ) 1315 1316 /*++ 1317 1318 Routine Description: 1319 1320 This routine performs the verify volume operation. It is responsible for 1321 either completing of enqueuing the input Irp. 1322 1323 Arguments: 1324 1325 Irp - Supplies the Irp to process 1326 1327 Return Value: 1328 1329 NTSTATUS - The return status for the operation 1330 1331 --*/ 1332 1333 { 1334 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1335 PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb; 1336 PVCB Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->Parameters.VerifyVolume.DeviceObject)->Vcb; 1337 1338 PCHAR RawIsoVd = NULL; 1339 1340 PCDROM_TOC_LARGE CdromToc = NULL; 1341 ULONG TocLength = 0; 1342 ULONG TocTrackCount = 0; 1343 ULONG TocDiskFlags = 0; 1344 1345 ULONG MediaChangeCount = Vcb->MediaChangeCount; 1346 1347 PFILE_OBJECT FileObjectToNotify = NULL; 1348 1349 BOOLEAN ReturnError; 1350 BOOLEAN ReleaseVcb = FALSE; 1351 1352 IO_STATUS_BLOCK Iosb; 1353 1354 STRING AnsiLabel; 1355 UNICODE_STRING UnicodeLabel; 1356 1357 WCHAR VolumeLabel[ VOLUME_ID_LENGTH ]; 1358 ULONG VolumeLabelLength; 1359 1360 ULONG Index; 1361 1362 NTSTATUS Status = STATUS_SUCCESS; 1363 1364 PAGED_CODE(); 1365 1366 // 1367 // We check that we are talking to a Cdrom device. 1368 // 1369 1370 NT_ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ); 1371 NT_ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )); 1372 1373 // 1374 // Update the real device in the IrpContext from the Vpb. There was no available 1375 // file object when the IrpContext was created. 1376 // 1377 1378 IrpContext->RealDevice = Vpb->RealDevice; 1379 1380 // 1381 // Acquire the global resource to synchronise against mounts and teardown, 1382 // finally clause releases. 1383 // 1384 1385 CdAcquireCdData( IrpContext ); 1386 1387 _SEH2_TRY { 1388 1389 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 1390 ReleaseVcb = TRUE; 1391 1392 // 1393 // Check to see if the volume is eligible for verification. 1394 // 1395 1396 if ((Vcb->VcbCondition == VcbInvalid) || 1397 (Vcb->VcbCondition == VcbDismountInProgress)) { 1398 1399 try_return( Status = STATUS_WRONG_VOLUME ); 1400 } 1401 1402 // 1403 // Verify that there is a disk here. 1404 // 1405 1406 Status = CdPerformDevIoCtrl( IrpContext, 1407 IOCTL_CDROM_CHECK_VERIFY, 1408 Vcb->TargetDeviceObject, 1409 &MediaChangeCount, 1410 sizeof(ULONG), 1411 FALSE, 1412 TRUE, 1413 &Iosb ); 1414 1415 if (!NT_SUCCESS( Status )) { 1416 1417 // 1418 // If we will allow a raw mount then return WRONG_VOLUME to 1419 // allow the volume to be mounted by raw. 1420 // 1421 1422 if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) { 1423 1424 Status = STATUS_WRONG_VOLUME; 1425 } 1426 1427 try_return( Status ); 1428 } 1429 1430 if (Iosb.Information != sizeof(ULONG)) { 1431 1432 // 1433 // Be safe about the count in case the driver didn't fill it in 1434 // 1435 1436 MediaChangeCount = 0; 1437 } 1438 1439 // 1440 // Verify that the device actually saw a change. If the driver does not 1441 // support the MCC, then we must verify the volume in any case. 1442 // 1443 1444 if (MediaChangeCount == 0 || 1445 (Vcb->MediaChangeCount != MediaChangeCount)) { 1446 1447 // 1448 // Allocate a buffer to query the TOC. 1449 // 1450 1451 CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool, 1452 sizeof( CDROM_TOC_LARGE ), 1453 TAG_CDROM_TOC ); 1454 1455 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE )); 1456 1457 // 1458 // Let's query for the Toc now and handle any error we get from this operation. 1459 // 1460 1461 Status = CdProcessToc( IrpContext, 1462 Vcb->TargetDeviceObject, 1463 CdromToc, 1464 &TocLength, 1465 &TocTrackCount, 1466 &TocDiskFlags ); 1467 1468 // 1469 // If we failed to read the TOC, then give up now. Drives will fail 1470 // a TOC read on, for example, erased CD-RW media. 1471 // 1472 1473 if (Status != STATUS_SUCCESS) { 1474 1475 // 1476 // For any errors other than no media and not ready, commute the 1477 // status to ensure that the current VPB is kicked off the device 1478 // below - there is probably blank media in the drive, since we got 1479 // further than the check verify. 1480 // 1481 1482 if (!CdIsRawDevice( IrpContext, Status )) { 1483 1484 Status = STATUS_WRONG_VOLUME; 1485 } 1486 1487 try_return( Status ); 1488 1489 // 1490 // We got a TOC. Verify that it matches the previous Toc. 1491 // 1492 1493 } else if ((Vcb->TocLength != TocLength) || 1494 (Vcb->TrackCount != TocTrackCount) || 1495 (Vcb->DiskFlags != TocDiskFlags) || 1496 !RtlEqualMemory( CdromToc, 1497 Vcb->CdromToc, 1498 TocLength )) { 1499 1500 try_return( Status = STATUS_WRONG_VOLUME ); 1501 } 1502 1503 // 1504 // If the disk to verify is an audio disk then we already have a 1505 // match. Otherwise we need to check the volume descriptor. 1506 // 1507 1508 if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) { 1509 1510 // 1511 // Allocate a buffer for the sector buffer. 1512 // 1513 1514 RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool, 1515 ROUND_TO_PAGES( 2 * SECTOR_SIZE ), 1516 TAG_VOL_DESC ); 1517 1518 // 1519 // Read the primary volume descriptor for this volume. If we 1520 // get an io error and this verify was a the result of DASD open, 1521 // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently 1522 // expect a music disk then this request should fail. 1523 // 1524 1525 ReturnError = FALSE; 1526 1527 if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) { 1528 1529 ReturnError = TRUE; 1530 } 1531 1532 if (!CdFindPrimaryVd( IrpContext, 1533 Vcb, 1534 RawIsoVd, 1535 Vcb->BlockFactor, 1536 ReturnError, 1537 TRUE )) { 1538 1539 // 1540 // If the previous Vcb did not represent a raw disk 1541 // then show this volume was dismounted. 1542 // 1543 1544 try_return( Status = STATUS_WRONG_VOLUME ); 1545 1546 } 1547 else { 1548 1549 // 1550 // Look for a supplementary VD. 1551 // 1552 // Store the primary volume descriptor in the second half of 1553 // RawIsoVd. Then if our search for a secondary fails we can 1554 // recover this immediately. 1555 // 1556 1557 RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ), 1558 RawIsoVd, 1559 SECTOR_SIZE ); 1560 1561 // 1562 // We have the initial volume descriptor. Locate a secondary 1563 // volume descriptor if present. 1564 // 1565 1566 CdFindActiveVolDescriptor( IrpContext, 1567 Vcb, 1568 RawIsoVd, 1569 TRUE); 1570 // 1571 // Compare the serial numbers. If they don't match, set the 1572 // status to wrong volume. 1573 // 1574 1575 if (Vpb->SerialNumber != CdSerial32( RawIsoVd, SECTOR_SIZE )) { 1576 1577 try_return( Status = STATUS_WRONG_VOLUME ); 1578 } 1579 1580 // 1581 // Verify the volume labels. 1582 // 1583 1584 if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) { 1585 1586 // 1587 // Compute the length of the volume name 1588 // 1589 1590 AnsiLabel.Buffer = (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ); 1591 AnsiLabel.MaximumLength = AnsiLabel.Length = (ULONG)VOLUME_ID_LENGTH; 1592 1593 UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR ); 1594 UnicodeLabel.Buffer = VolumeLabel; 1595 1596 // 1597 // Convert this to unicode. If we get any error then use a name 1598 // length of zero. 1599 // 1600 1601 VolumeLabelLength = 0; 1602 1603 if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel, 1604 &AnsiLabel, 1605 FALSE ))) { 1606 1607 VolumeLabelLength = UnicodeLabel.Length; 1608 } 1609 1610 // 1611 // We need to convert from big-endian to little endian. 1612 // 1613 1614 } else { 1615 1616 CdConvertBigToLittleEndian( IrpContext, 1617 (PCHAR) CdRvdVolId( RawIsoVd, Vcb->VcbState ), 1618 VOLUME_ID_LENGTH, 1619 (PCHAR) VolumeLabel ); 1620 1621 VolumeLabelLength = VOLUME_ID_LENGTH; 1622 } 1623 1624 // 1625 // Strip the trailing spaces or zeroes from the name. 1626 // 1627 1628 Index = VolumeLabelLength / sizeof( WCHAR ); 1629 1630 while (Index > 0) { 1631 1632 if ((VolumeLabel[ Index - 1 ] != L'\0') && 1633 (VolumeLabel[ Index - 1 ] != L' ')) { 1634 1635 break; 1636 } 1637 1638 Index -= 1; 1639 } 1640 1641 // 1642 // Now set the final length for the name. 1643 // 1644 1645 VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR )); 1646 1647 // 1648 // Now check that the label matches. 1649 // 1650 if ((Vpb->VolumeLabelLength != VolumeLabelLength) || 1651 !RtlEqualMemory( Vpb->VolumeLabel, 1652 VolumeLabel, 1653 VolumeLabelLength )) { 1654 1655 try_return( Status = STATUS_WRONG_VOLUME ); 1656 } 1657 } 1658 } 1659 } 1660 1661 // 1662 // The volume is OK, clear the verify bit. 1663 // 1664 1665 CdUpdateVcbCondition( Vcb, VcbMounted); 1666 1667 CdMarkRealDevVerifyOk( Vpb->RealDevice); 1668 1669 // 1670 // See if we will need to provide notification of the remount. This is the readonly 1671 // filesystem's form of dismount/mount notification. 1672 // 1673 1674 if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) { 1675 1676 ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT ); 1677 1678 FileObjectToNotify = Vcb->RootIndexFcb->FileObject; 1679 ObReferenceObject( FileObjectToNotify ); 1680 } 1681 1682 try_exit: NOTHING; 1683 1684 // 1685 // Update the media change count to note that we have verified the volume 1686 // at this value - regardless of the outcome. 1687 // 1688 1689 CdUpdateMediaChangeCount( Vcb, MediaChangeCount); 1690 1691 // 1692 // If the volume was already unmounted, nothing more to do. 1693 // 1694 1695 if (Vcb->VcbCondition == VcbNotMounted) { 1696 1697 Status = STATUS_WRONG_VOLUME; 1698 1699 // 1700 // If we got the wrong volume then free any remaining XA sector in 1701 // the current Vcb. Also mark the Vcb as not mounted. 1702 // 1703 1704 } else if ((Vcb->VcbCondition == VcbMounted) && (Status == STATUS_WRONG_VOLUME)) { 1705 1706 CdUpdateVcbCondition( Vcb, VcbNotMounted); 1707 1708 if (Vcb->XASector != NULL) { 1709 1710 CdFreePool( &Vcb->XASector ); 1711 Vcb->XASector = 0; 1712 Vcb->XADiskOffset = 0; 1713 } 1714 1715 CdFreeDirCache( IrpContext); 1716 1717 // 1718 // Now, if there are no user handles to the volume, try to spark 1719 // teardown by purging the volume. 1720 // 1721 1722 if (Vcb->VcbCleanup == 0) { 1723 1724 if (NT_SUCCESS( CdPurgeVolume( IrpContext, Vcb, FALSE ))) { 1725 1726 ReleaseVcb = CdCheckForDismount( IrpContext, Vcb, FALSE ); 1727 } 1728 } 1729 } 1730 1731 } _SEH2_FINALLY { 1732 1733 // 1734 // Free the TOC buffer if allocated. 1735 // 1736 1737 if (CdromToc != NULL) { 1738 1739 CdFreePool( &CdromToc ); 1740 } 1741 1742 if (RawIsoVd != NULL) { 1743 1744 CdFreePool( &RawIsoVd ); 1745 } 1746 1747 if (ReleaseVcb) { 1748 1749 CdReleaseVcb( IrpContext, Vcb ); 1750 } 1751 else { 1752 _Analysis_assume_lock_not_held_(Vcb->VcbResource); 1753 } 1754 1755 CdReleaseCdData( IrpContext ); 1756 } _SEH2_END; 1757 1758 // 1759 // Now send mount notification. 1760 // 1761 1762 if (FileObjectToNotify) { 1763 1764 FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT ); 1765 ObDereferenceObject( FileObjectToNotify ); 1766 } 1767 1768 // 1769 // Complete the request if no exception. 1770 // 1771 1772 CdCompleteRequest( IrpContext, Irp, Status ); 1773 return Status; 1774 } 1775 1776 1777 // 1778 // Local support routine 1779 // 1780 1781 _Requires_lock_held_(_Global_critical_region_) 1782 NTSTATUS 1783 CdOplockRequest ( 1784 _Inout_ PIRP_CONTEXT IrpContext, 1785 _Inout_ PIRP Irp 1786 ) 1787 1788 /*++ 1789 1790 Routine Description: 1791 1792 This is the common routine to handle oplock requests made via the 1793 NtFsControlFile call. 1794 1795 Arguments: 1796 1797 Irp - Supplies the Irp being processed 1798 1799 Return Value: 1800 1801 NTSTATUS - The return status for the operation 1802 1803 --*/ 1804 1805 { 1806 NTSTATUS Status = STATUS_SUCCESS; 1807 PFCB Fcb; 1808 PCCB Ccb; 1809 1810 ULONG OplockCount = 0; 1811 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1812 1813 PAGED_CODE(); 1814 1815 // 1816 // We only permit oplock requests on files. 1817 // 1818 1819 if (CdDecodeFileObject( IrpContext, 1820 IrpSp->FileObject, 1821 &Fcb, 1822 &Ccb ) != UserFileOpen ) { 1823 1824 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 1825 return STATUS_INVALID_PARAMETER; 1826 } 1827 1828 // 1829 // Make this a waitable Irpcontext so we don't fail to acquire 1830 // the resources. 1831 // 1832 1833 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 1834 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 1835 1836 // 1837 // Switch on the function control code. We grab the Fcb exclusively 1838 // for oplock requests, shared for oplock break acknowledgement. 1839 // 1840 1841 switch (IrpSp->Parameters.FileSystemControl.FsControlCode) { 1842 1843 case FSCTL_REQUEST_OPLOCK_LEVEL_1 : 1844 case FSCTL_REQUEST_OPLOCK_LEVEL_2 : 1845 case FSCTL_REQUEST_BATCH_OPLOCK : 1846 case FSCTL_REQUEST_FILTER_OPLOCK : 1847 1848 CdAcquireFcbExclusive( IrpContext, Fcb, FALSE ); 1849 1850 if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { 1851 1852 if (Fcb->FileLock != NULL) { 1853 1854 #if (NTDDI_VERSION >= NTDDI_WIN7) 1855 OplockCount = (ULONG) FsRtlAreThereCurrentOrInProgressFileLocks( Fcb->FileLock ); 1856 #else 1857 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock ); 1858 #endif 1859 } 1860 1861 } else { 1862 1863 OplockCount = Fcb->FcbCleanup; 1864 } 1865 1866 break; 1867 1868 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: 1869 case FSCTL_OPBATCH_ACK_CLOSE_PENDING: 1870 case FSCTL_OPLOCK_BREAK_NOTIFY: 1871 case FSCTL_OPLOCK_BREAK_ACK_NO_2: 1872 1873 CdAcquireFcbShared( IrpContext, Fcb, FALSE ); 1874 break; 1875 1876 default: 1877 1878 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 1879 return STATUS_INVALID_PARAMETER; 1880 } 1881 1882 // 1883 // Use a try finally to free the Fcb. 1884 // 1885 1886 _SEH2_TRY { 1887 1888 // 1889 // Verify the Fcb. 1890 // 1891 1892 CdVerifyFcbOperation( IrpContext, Fcb ); 1893 1894 // 1895 // Call the FsRtl routine to grant/acknowledge oplock. 1896 // 1897 1898 Status = FsRtlOplockFsctrl( CdGetFcbOplock(Fcb), 1899 Irp, 1900 OplockCount ); 1901 1902 // 1903 // Set the flag indicating if Fast I/O is possible 1904 // 1905 1906 CdLockFcb( IrpContext, Fcb ); 1907 Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb ); 1908 CdUnlockFcb( IrpContext, Fcb ); 1909 1910 // 1911 // The oplock package will complete the Irp. 1912 // 1913 1914 Irp = NULL; 1915 1916 } _SEH2_FINALLY { 1917 1918 // 1919 // Release all of our resources 1920 // 1921 1922 CdReleaseFcb( IrpContext, Fcb ); 1923 } _SEH2_END; 1924 1925 // 1926 // Complete the request if there was no exception. 1927 // 1928 1929 CdCompleteRequest( IrpContext, Irp, Status ); 1930 return Status; 1931 } 1932 1933 1934 // 1935 // Local support routine 1936 // 1937 1938 _Requires_lock_held_(_Global_critical_region_) 1939 NTSTATUS 1940 CdLockVolume ( 1941 _Inout_ PIRP_CONTEXT IrpContext, 1942 _Inout_ PIRP Irp 1943 ) 1944 1945 /*++ 1946 1947 Routine Description: 1948 1949 This routine performs the lock volume operation. It is responsible for 1950 either completing of enqueuing the input Irp. 1951 1952 Arguments: 1953 1954 Irp - Supplies the Irp to process 1955 1956 Return Value: 1957 1958 NTSTATUS - The return status for the operation 1959 1960 --*/ 1961 1962 { 1963 NTSTATUS Status = STATUS_SUCCESS; 1964 1965 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1966 1967 PVCB Vcb; 1968 PFCB Fcb; 1969 PCCB Ccb; 1970 1971 PAGED_CODE(); 1972 1973 // 1974 // Decode the file object, the only type of opens we accept are 1975 // user volume opens. 1976 // 1977 1978 if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) { 1979 1980 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 1981 1982 return STATUS_INVALID_PARAMETER; 1983 } 1984 1985 // 1986 // Send our notification so that folks that like to hold handles on 1987 // volumes can get out of the way. 1988 // 1989 1990 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK ); 1991 1992 // 1993 // Acquire exclusive access to the Vcb. 1994 // 1995 1996 Vcb = Fcb->Vcb; 1997 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 1998 1999 _SEH2_TRY { 2000 2001 // 2002 // Verify the Vcb. 2003 // 2004 2005 CdVerifyVcb( IrpContext, Vcb ); 2006 2007 Status = CdLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 2008 2009 } _SEH2_FINALLY { 2010 2011 // 2012 // Release the Vcb. 2013 // 2014 2015 CdReleaseVcb( IrpContext, Vcb ); 2016 2017 if (_SEH2_AbnormalTermination() || !NT_SUCCESS( Status )) { 2018 2019 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED ); 2020 } 2021 } _SEH2_END; 2022 2023 // 2024 // Complete the request if there haven't been any exceptions. 2025 // 2026 2027 CdCompleteRequest( IrpContext, Irp, Status ); 2028 return Status; 2029 } 2030 2031 2032 // 2033 // Local support routine 2034 // 2035 2036 _Requires_lock_held_(_Global_critical_region_) 2037 NTSTATUS 2038 CdUnlockVolume ( 2039 _Inout_ PIRP_CONTEXT IrpContext, 2040 _Inout_ PIRP Irp 2041 ) 2042 2043 /*++ 2044 2045 Routine Description: 2046 2047 This routine performs the unlock volume operation. It is responsible for 2048 either completing of enqueuing the input Irp. 2049 2050 Arguments: 2051 2052 Irp - Supplies the Irp to process 2053 2054 Return Value: 2055 2056 NTSTATUS - The return status for the operation 2057 2058 --*/ 2059 2060 { 2061 NTSTATUS Status; 2062 2063 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2064 2065 PVCB Vcb; 2066 PFCB Fcb; 2067 PCCB Ccb; 2068 2069 PAGED_CODE(); 2070 2071 // 2072 // Decode the file object, the only type of opens we accept are 2073 // user volume opens. 2074 // 2075 2076 if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) { 2077 2078 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2079 return STATUS_INVALID_PARAMETER; 2080 } 2081 2082 // 2083 // Acquire exclusive access to the Vcb. 2084 // 2085 2086 Vcb = Fcb->Vcb; 2087 2088 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 2089 2090 // 2091 // We won't check for a valid Vcb for this request. An unlock will always 2092 // succeed on a locked volume. 2093 // 2094 2095 Status = CdUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 2096 2097 // 2098 // Release all of our resources 2099 // 2100 2101 CdReleaseVcb( IrpContext, Vcb ); 2102 2103 // 2104 // Send notification that the volume is avaliable. 2105 // 2106 2107 if (NT_SUCCESS( Status )) { 2108 2109 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK ); 2110 } 2111 2112 // 2113 // Complete the request if there haven't been any exceptions. 2114 // 2115 2116 CdCompleteRequest( IrpContext, Irp, Status ); 2117 return Status; 2118 } 2119 2120 2121 2122 // 2123 // Local support routine 2124 // 2125 2126 _Requires_lock_held_(_Global_critical_region_) 2127 NTSTATUS 2128 CdDismountVolume ( 2129 _Inout_ PIRP_CONTEXT IrpContext, 2130 _Inout_ PIRP Irp 2131 ) 2132 2133 /*++ 2134 2135 Routine Description: 2136 2137 This routine performs the dismount volume operation. It is responsible for 2138 either completing of enqueuing the input Irp. We only dismount a volume which 2139 has been locked. The intent here is that someone has locked the volume (they are the 2140 only remaining handle). We set the verify bit here and the user will close his handle. 2141 We will dismount a volume with no user's handles in the verify path. 2142 2143 Arguments: 2144 2145 Irp - Supplies the Irp to process 2146 2147 Return Value: 2148 2149 NTSTATUS - The return status for the operation 2150 2151 --*/ 2152 2153 { 2154 NTSTATUS Status; 2155 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2156 2157 PVCB Vcb; 2158 PFCB Fcb; 2159 PCCB Ccb; 2160 2161 PAGED_CODE(); 2162 2163 if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) { 2164 2165 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2166 return STATUS_INVALID_PARAMETER; 2167 } 2168 2169 Vcb = Fcb->Vcb; 2170 2171 // 2172 // Send dismount notification. 2173 // 2174 2175 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT ); 2176 2177 // 2178 // Make this request waitable. 2179 // 2180 2181 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 2182 2183 // 2184 // Acquire exclusive access to the Vcb, and take the global resource to 2185 // sync. against mounts, verifies etc. 2186 // 2187 2188 CdAcquireCdData( IrpContext ); 2189 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 2190 2191 // 2192 // Mark the volume as needs to be verified, but only do it if 2193 // the vcb is locked by this handle and the volume is currently mounted. 2194 // 2195 2196 if (Vcb->VcbCondition != VcbMounted) { 2197 2198 Status = STATUS_VOLUME_DISMOUNTED; 2199 2200 } else { 2201 2202 // 2203 // Invalidate the volume right now. 2204 // 2205 // The intent here is to make every subsequent operation 2206 // on the volume fail and grease the rails toward dismount. 2207 // By definition there is no going back from a SURPRISE. 2208 // 2209 2210 CdLockVcb( IrpContext, Vcb ); 2211 2212 if (Vcb->VcbCondition != VcbDismountInProgress) { 2213 2214 CdUpdateVcbCondition( Vcb, VcbInvalid ); 2215 } 2216 2217 SetFlag( Vcb->VcbState, VCB_STATE_DISMOUNTED ); 2218 2219 CdUnlockVcb( IrpContext, Vcb ); 2220 2221 2222 // 2223 // Set flag to tell the close path that we want to force dismount 2224 // the volume when this handle is closed. 2225 // 2226 2227 SetFlag( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE); 2228 2229 Status = STATUS_SUCCESS; 2230 } 2231 2232 // 2233 // Release all of our resources 2234 // 2235 2236 CdReleaseVcb( IrpContext, Vcb ); 2237 CdReleaseCdData( IrpContext ); 2238 2239 #if (NTDDI_VERSION >= NTDDI_WIN8) 2240 2241 FsRtlDismountComplete( Vcb->TargetDeviceObject, Status ); 2242 2243 #endif 2244 2245 // 2246 // Complete the request if there haven't been any exceptions. 2247 // 2248 2249 CdCompleteRequest( IrpContext, Irp, Status ); 2250 return Status; 2251 } 2252 2253 2254 // 2255 // Local support routine 2256 // 2257 2258 NTSTATUS 2259 CdIsVolumeDirty ( 2260 _Inout_ PIRP_CONTEXT IrpContext, 2261 _Inout_ PIRP Irp 2262 ) 2263 2264 /*++ 2265 2266 Routine Description: 2267 2268 This routine determines if a volume is currently dirty. 2269 2270 Arguments: 2271 2272 Irp - Supplies the Irp to process 2273 2274 Return Value: 2275 2276 NTSTATUS - The return status for the operation 2277 2278 --*/ 2279 2280 { 2281 PIO_STACK_LOCATION IrpSp; 2282 2283 TYPE_OF_OPEN TypeOfOpen; 2284 PFCB Fcb; 2285 PCCB Ccb; 2286 2287 PULONG VolumeState; 2288 2289 PAGED_CODE(); 2290 2291 // 2292 // Get the current stack location and extract the output 2293 // buffer information. 2294 // 2295 2296 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2297 2298 // 2299 // Get a pointer to the output buffer. 2300 // 2301 2302 if (Irp->AssociatedIrp.SystemBuffer != NULL) { 2303 2304 VolumeState = Irp->AssociatedIrp.SystemBuffer; 2305 2306 } else { 2307 2308 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER ); 2309 return STATUS_INVALID_USER_BUFFER; 2310 } 2311 2312 // 2313 // Make sure the output buffer is large enough and then initialize 2314 // the answer to be that the volume isn't dirty. 2315 // 2316 2317 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) { 2318 2319 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2320 return STATUS_INVALID_PARAMETER; 2321 } 2322 2323 *VolumeState = 0; 2324 2325 // 2326 // Decode the file object 2327 // 2328 2329 TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); 2330 2331 if (TypeOfOpen != UserVolumeOpen) { 2332 2333 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2334 return STATUS_INVALID_PARAMETER; 2335 } 2336 2337 if (Fcb->Vcb->VcbCondition != VcbMounted) { 2338 2339 CdCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED ); 2340 return STATUS_VOLUME_DISMOUNTED; 2341 } 2342 2343 // 2344 // Now set up to return the clean state. CDs obviously can never be dirty 2345 // but we want to make sure we have enforced the full semantics of this call. 2346 // 2347 2348 Irp->IoStatus.Information = sizeof( ULONG ); 2349 2350 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 2351 return STATUS_SUCCESS; 2352 } 2353 2354 2355 // 2356 // Local support routine 2357 // 2358 2359 NTSTATUS 2360 CdIsVolumeMounted ( 2361 _Inout_ PIRP_CONTEXT IrpContext, 2362 _Inout_ PIRP Irp 2363 ) 2364 2365 /*++ 2366 2367 Routine Description: 2368 2369 This routine determines if a volume is currently mounted. 2370 2371 Arguments: 2372 2373 Irp - Supplies the Irp to process 2374 2375 Return Value: 2376 2377 NTSTATUS - The return status for the operation 2378 2379 --*/ 2380 2381 { 2382 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2383 2384 PFCB Fcb; 2385 PCCB Ccb; 2386 2387 PAGED_CODE(); 2388 2389 // 2390 // Decode the file object. 2391 // 2392 2393 CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); 2394 2395 if (Fcb != NULL) { 2396 2397 // 2398 // Disable PopUps, we want to return any error. 2399 // 2400 2401 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS ); 2402 2403 // 2404 // Verify the Vcb. This will raise in the error condition. 2405 // 2406 2407 CdVerifyVcb( IrpContext, Fcb->Vcb ); 2408 } 2409 2410 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 2411 2412 return STATUS_SUCCESS; 2413 } 2414 2415 2416 // 2417 // Local support routine 2418 // 2419 2420 NTSTATUS 2421 CdIsPathnameValid ( 2422 _Inout_ PIRP_CONTEXT IrpContext, 2423 _Inout_ PIRP Irp 2424 ) 2425 2426 /*++ 2427 2428 Routine Description: 2429 2430 This routine determines if pathname is a valid CDFS pathname. 2431 We always succeed this request. 2432 2433 Arguments: 2434 2435 Irp - Supplies the Irp to process. 2436 2437 Return Value: 2438 2439 None 2440 2441 --*/ 2442 2443 { 2444 PAGED_CODE(); 2445 2446 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 2447 return STATUS_SUCCESS; 2448 } 2449 2450 2451 // 2452 // Local support routine 2453 // 2454 2455 _Requires_lock_held_(_Global_critical_region_) 2456 NTSTATUS 2457 CdInvalidateVolumes ( 2458 _Inout_ PIRP_CONTEXT IrpContext, 2459 _Inout_ PIRP Irp 2460 ) 2461 2462 /*++ 2463 2464 Routine Description: 2465 2466 This routine searches for all the volumes mounted on the same real device 2467 of the current DASD handle, and marks them all bad. The only operation 2468 that can be done on such handles is cleanup and close. 2469 2470 Arguments: 2471 2472 Irp - Supplies the Irp to process 2473 2474 Return Value: 2475 2476 NTSTATUS - The return status for the operation 2477 2478 --*/ 2479 2480 { 2481 NTSTATUS Status; 2482 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2483 KIRQL SavedIrql; 2484 2485 BOOLEAN UnlockVcb = FALSE; 2486 2487 LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0}; 2488 2489 HANDLE Handle; 2490 2491 PVCB Vcb; 2492 2493 PLIST_ENTRY Links; 2494 2495 PFILE_OBJECT FileToMarkBad; 2496 PDEVICE_OBJECT DeviceToMarkBad; 2497 2498 // 2499 // We only allow the invalidate call to come in on our file system devices. 2500 // 2501 2502 #ifndef __REACTOS__ 2503 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) { 2504 #else 2505 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject && 2506 IrpSp->DeviceObject != CdData.HddFileSystemDeviceObject) { 2507 #endif 2508 2509 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 2510 2511 return STATUS_INVALID_DEVICE_REQUEST; 2512 } 2513 2514 // 2515 // Check for the correct security access. 2516 // The caller must have the SeTcbPrivilege. 2517 // 2518 2519 if (!SeSinglePrivilegeCheck( TcbPrivilege, Irp->RequestorMode )) { 2520 2521 CdCompleteRequest( IrpContext, Irp, STATUS_PRIVILEGE_NOT_HELD ); 2522 2523 return STATUS_PRIVILEGE_NOT_HELD; 2524 } 2525 2526 // 2527 // Try to get a pointer to the device object from the handle passed in. 2528 // 2529 2530 #if defined(_WIN64) && BUILD_WOW64_ENABLED 2531 2532 if (IoIs32bitProcess( Irp )) { 2533 2534 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( UINT32 )) { 2535 2536 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2537 return STATUS_INVALID_PARAMETER; 2538 } 2539 2540 Handle = (HANDLE) LongToHandle( *((PUINT32) Irp->AssociatedIrp.SystemBuffer) ); 2541 2542 } else 2543 2544 #endif 2545 2546 { 2547 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) { 2548 2549 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 2550 return STATUS_INVALID_PARAMETER; 2551 } 2552 2553 Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer); 2554 } 2555 2556 Status = ObReferenceObjectByHandle( Handle, 2557 0, 2558 *IoFileObjectType, 2559 KernelMode, 2560 (PVOID*)&FileToMarkBad, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */ 2561 NULL ); 2562 2563 if (!NT_SUCCESS(Status)) { 2564 2565 CdCompleteRequest( IrpContext, Irp, Status ); 2566 return Status; 2567 } 2568 2569 // 2570 // Grab the DeviceObject from the FileObject. 2571 // 2572 2573 DeviceToMarkBad = FileToMarkBad->DeviceObject; 2574 2575 // 2576 // We only needed the device object involved, not a reference to the file. 2577 // 2578 2579 ObDereferenceObject( FileToMarkBad ); 2580 2581 // 2582 // Make sure this request can wait. 2583 // 2584 2585 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 2586 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 2587 2588 // 2589 // Synchronise with pnp/mount/verify paths. 2590 // 2591 2592 CdAcquireCdData( IrpContext ); 2593 2594 // 2595 // Nothing can go wrong now. 2596 // 2597 2598 // 2599 // Now walk through all the mounted Vcb's looking for candidates to 2600 // mark invalid. 2601 // 2602 // On volumes we mark invalid, check for dismount possibility (which is 2603 // why we have to get the next link so early). 2604 // 2605 2606 Links = CdData.VcbQueue.Flink; 2607 2608 while (Links != &CdData.VcbQueue) { 2609 2610 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks); 2611 2612 Links = Links->Flink; 2613 2614 // 2615 // If we get a match, mark the volume Bad, and also check to 2616 // see if the volume should go away. 2617 // 2618 2619 CdLockVcb( IrpContext, Vcb ); 2620 2621 if (Vcb->Vpb->RealDevice == DeviceToMarkBad) { 2622 2623 // 2624 // Take the VPB spinlock, and look to see if this volume is the 2625 // one currently mounted on the actual device. If it is, pull it 2626 // off immediately. 2627 // 2628 2629 IoAcquireVpbSpinLock( &SavedIrql ); 2630 2631 #ifdef _MSC_VER 2632 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed") 2633 #endif 2634 if (DeviceToMarkBad->Vpb == Vcb->Vpb) { 2635 2636 PVPB NewVpb = Vcb->SwapVpb; 2637 2638 NT_ASSERT( FlagOn( Vcb->Vpb->Flags, VPB_MOUNTED)); 2639 NT_ASSERT( NULL != NewVpb); 2640 2641 RtlZeroMemory( NewVpb, sizeof( VPB ) ); 2642 2643 NewVpb->Type = IO_TYPE_VPB; 2644 NewVpb->Size = sizeof( VPB ); 2645 NewVpb->RealDevice = DeviceToMarkBad; 2646 2647 #ifdef _MSC_VER 2648 #pragma prefast(push) 2649 #pragma prefast(disable: 28175, "this is a filesystem driver, touching the vpb is allowed") 2650 #endif 2651 NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING ); 2652 DeviceToMarkBad->Vpb = NewVpb; 2653 #ifdef _MSC_VER 2654 #pragma prefast(pop) 2655 #endif 2656 2657 Vcb->SwapVpb = NULL; 2658 } 2659 2660 IoReleaseVpbSpinLock( SavedIrql ); 2661 2662 if (Vcb->VcbCondition != VcbDismountInProgress) { 2663 2664 CdUpdateVcbCondition( Vcb, VcbInvalid); 2665 } 2666 2667 CdUnlockVcb( IrpContext, Vcb ); 2668 2669 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE); 2670 2671 CdPurgeVolume( IrpContext, Vcb, FALSE ); 2672 2673 UnlockVcb = CdCheckForDismount( IrpContext, Vcb, FALSE ); 2674 2675 // 2676 // prefast: if UnlockVcb is false, then the VCB was already deleted, so we better not touch the Vcb. 2677 // tell Prefast something nice so it stops complaining about us leaking it. 2678 // 2679 2680 __analysis_assert( UnlockVcb == TRUE ); 2681 2682 if (UnlockVcb) { 2683 2684 CdReleaseVcb( IrpContext, Vcb); 2685 } 2686 2687 } else { 2688 2689 CdUnlockVcb( IrpContext, Vcb ); 2690 } 2691 } 2692 2693 CdReleaseCdData( IrpContext ); 2694 2695 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 2696 return STATUS_SUCCESS; 2697 } 2698 2699 2700 // 2701 // Local support routine 2702 // 2703 2704 NTSTATUS 2705 CdAllowExtendedDasdIo ( 2706 _Inout_ PIRP_CONTEXT IrpContext, 2707 _Inout_ PIRP Irp 2708 ) 2709 2710 /*++ 2711 2712 Routine Description: 2713 2714 This routine marks the CCB to indicate that the handle 2715 may be used to read past the end of the volume file. The 2716 handle must be a dasd handle. 2717 2718 Arguments: 2719 2720 Irp - Supplies the Irp to process 2721 2722 Return Value: 2723 2724 NTSTATUS - The return status for the operation 2725 2726 --*/ 2727 2728 { 2729 NTSTATUS Status; 2730 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2731 2732 PFCB Fcb; 2733 PCCB Ccb; 2734 2735 PAGED_CODE(); 2736 2737 // 2738 // Decode the file object, the only type of opens we accept are 2739 // user volume opens. 2740 // 2741 2742 if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) { 2743 2744 Status = STATUS_INVALID_PARAMETER; 2745 } 2746 else { 2747 2748 SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO ); 2749 Status = STATUS_SUCCESS; 2750 } 2751 2752 CdCompleteRequest( IrpContext, Irp, Status ); 2753 return Status; 2754 } 2755 2756 2757 // 2758 // Local support routine 2759 // 2760 2761 _Requires_lock_held_(_Global_critical_region_) 2762 VOID 2763 CdScanForDismountedVcb ( 2764 _Inout_ PIRP_CONTEXT IrpContext 2765 ) 2766 2767 /*++ 2768 2769 Routine Description: 2770 2771 This routine walks through the list of Vcb's looking for any which may 2772 now be deleted. They may have been left on the list because there were 2773 outstanding references. 2774 2775 Arguments: 2776 2777 Return Value: 2778 2779 None 2780 2781 --*/ 2782 2783 { 2784 PVCB Vcb; 2785 PLIST_ENTRY Links; 2786 2787 PAGED_CODE(); 2788 2789 // 2790 // Walk through all of the Vcb's attached to the global data. 2791 // 2792 2793 Links = CdData.VcbQueue.Flink; 2794 2795 while (Links != &CdData.VcbQueue) { 2796 2797 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks ); 2798 2799 // 2800 // Move to the next link now since the current Vcb may be deleted. 2801 // 2802 2803 Links = Links->Flink; 2804 2805 // 2806 // If dismount is already underway then check if this Vcb can 2807 // go away. 2808 // 2809 2810 if ((Vcb->VcbCondition == VcbDismountInProgress) || 2811 (Vcb->VcbCondition == VcbInvalid) || 2812 ((Vcb->VcbCondition == VcbNotMounted) && (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE))) { 2813 2814 CdCheckForDismount( IrpContext, Vcb, FALSE ); 2815 } 2816 } 2817 2818 return; 2819 } 2820 2821 2822 // 2823 // Local support routine 2824 // 2825 _Success_(return != FALSE) 2826 BOOLEAN 2827 CdFindPrimaryVd ( 2828 _In_ PIRP_CONTEXT IrpContext, 2829 _Inout_ PVCB Vcb, 2830 _Out_writes_bytes_(SECTOR_SIZE) PCHAR RawIsoVd, 2831 _In_ ULONG BlockFactor, 2832 _In_ BOOLEAN ReturnOnError, 2833 _In_ BOOLEAN VerifyVolume 2834 ) 2835 2836 /*++ 2837 2838 Routine Description: 2839 2840 This routine is called to walk through the volume descriptors looking 2841 for a primary volume descriptor. When/if a primary is found a 32-bit 2842 serial number is generated and stored into the Vpb. We also store the 2843 location of the primary volume descriptor in the Vcb. 2844 2845 Arguments: 2846 2847 Vcb - Pointer to the VCB for the volume. 2848 2849 RawIsoVd - Pointer to a sector buffer which will contain the primary 2850 volume descriptor on exit, if successful. 2851 2852 BlockFactor - Block factor used by the current device for the TableOfContents. 2853 2854 ReturnOnError - Indicates that we should raise on I/O errors rather than 2855 returning a FALSE value. 2856 2857 VerifyVolume - Indicates if we were called from the verify path. We 2858 do a few things different in this path. We don't update the Vcb in 2859 the verify path. 2860 2861 Return Value: 2862 2863 BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE 2864 otherwise. 2865 2866 --*/ 2867 2868 { 2869 NTSTATUS Status; 2870 ULONG ThisPass = 1; 2871 BOOLEAN FoundVd = FALSE; 2872 2873 ULONG BaseSector; 2874 ULONG SectorOffset; 2875 2876 PCDROM_TOC_LARGE CdromToc; 2877 2878 ULONG VolumeFlags; 2879 2880 PAGED_CODE(); 2881 2882 // 2883 // If there are no data tracks, don't even bother hunting for descriptors. 2884 // 2885 // This explicitly breaks various non-BlueBook compliant CDs that scribble 2886 // an ISO filesystem on media claiming only audio tracks. Since these 2887 // disks can cause serious problems in some CDROM units, fail fast. I admit 2888 // that it is possible that someone can still record the descriptors in the 2889 // audio track, record a data track (but fail to record descriptors there) 2890 // and still have the disk work. As this form of error worked in NT 4.0, and 2891 // since these disks really do exist, I don't want to change them. 2892 // 2893 // If we wished to support all such media (we don't), it would be neccesary 2894 // to clear this flag on finding ISO or HSG descriptors below. 2895 // 2896 2897 if (FlagOn(Vcb->VcbState, VCB_STATE_AUDIO_DISK)) { 2898 2899 return FALSE; 2900 } 2901 2902 // 2903 // We will make at most two passes through the volume descriptor sequence. 2904 // 2905 // On the first pass we will query for the last session. Using this 2906 // as a starting offset we will attempt to mount the volume. On any failure 2907 // we will go to the second pass and try without using any multi-session 2908 // information. 2909 // 2910 // On the second pass we will start offset from sector zero. 2911 // 2912 2913 while (!FoundVd && (ThisPass <= 2)) { 2914 2915 // 2916 // If we aren't at pass 1 then we start at sector 0. Otherwise we 2917 // try to look up the multi-session information. 2918 // 2919 2920 BaseSector = 0; 2921 2922 if (ThisPass == 1) { 2923 2924 CdromToc = NULL; 2925 2926 // 2927 // Check for whether this device supports XA and multi-session. 2928 // 2929 2930 _SEH2_TRY { 2931 2932 // 2933 // Allocate a buffer for the last session information. 2934 // 2935 2936 CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool, 2937 sizeof( CDROM_TOC_LARGE ), 2938 TAG_CDROM_TOC ); 2939 2940 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE )); 2941 2942 // 2943 // Query the last session information from the driver. 2944 // 2945 2946 Status = CdPerformDevIoCtrl( IrpContext, 2947 IOCTL_CDROM_GET_LAST_SESSION, 2948 Vcb->TargetDeviceObject, 2949 CdromToc, 2950 sizeof( CDROM_TOC_LARGE ), 2951 FALSE, 2952 TRUE, 2953 NULL ); 2954 2955 // 2956 // Raise an exception if there was an allocation failure. 2957 // 2958 2959 if (Status == STATUS_INSUFFICIENT_RESOURCES) { 2960 2961 CdRaiseStatus( IrpContext, Status ); 2962 } 2963 2964 // 2965 // We don't handle any errors yet. We will hit that below 2966 // as we try to scan the disk. If we have last session information 2967 // then modify the base sector. 2968 // 2969 2970 if (NT_SUCCESS( Status ) && 2971 (CdromToc->FirstTrack != CdromToc->LastTrack)) { 2972 2973 PCHAR Source, Dest; 2974 ULONG Count; 2975 2976 Count = 4; 2977 2978 // 2979 // The track address is BigEndian, we need to flip the bytes. 2980 // 2981 2982 Source = (PCHAR) &CdromToc->TrackData[0].Address[3]; 2983 Dest = (PCHAR) &BaseSector; 2984 2985 do { 2986 2987 *Dest++ = *Source--; 2988 2989 } while (--Count); 2990 2991 // 2992 // Now adjust the base sector by the block factor of the 2993 // device. 2994 // 2995 2996 BaseSector /= BlockFactor; 2997 2998 // 2999 // Make this look like the second pass since we are only using the 3000 // first session. No reason to retry on error. 3001 // 3002 3003 } else { 3004 3005 ThisPass += 1; 3006 } 3007 3008 } _SEH2_FINALLY { 3009 3010 if (CdromToc != NULL) { CdFreePool( &CdromToc ); } 3011 } _SEH2_END; 3012 } 3013 3014 // 3015 // Compute the starting sector offset from the start of the session. 3016 // 3017 3018 SectorOffset = FIRST_VD_SECTOR; 3019 3020 // 3021 // Start by assuming we have neither Hsg or Iso volumes. 3022 // 3023 3024 VolumeFlags = 0; 3025 3026 // 3027 // Loop until either error encountered, primary volume descriptor is 3028 // found or a terminal volume descriptor is found. 3029 // 3030 3031 while (TRUE) { 3032 3033 // 3034 // Attempt to read the desired sector. Exit directly if operation 3035 // not completed. 3036 // 3037 // If this is pass 1 we will ignore errors in read sectors and just 3038 // go to the next pass. 3039 // 3040 3041 if (!CdReadSectors( IrpContext, 3042 LlBytesFromSectors( BaseSector + SectorOffset ), 3043 SECTOR_SIZE, 3044 (BOOLEAN) ((ThisPass == 1) || ReturnOnError), 3045 RawIsoVd, 3046 Vcb->TargetDeviceObject )) { 3047 3048 break; 3049 } 3050 3051 // 3052 // Check if either an ISO or HSG volume. 3053 // 3054 3055 if (RtlEqualMemory( CdIsoId, 3056 CdRvdId( RawIsoVd, VCB_STATE_ISO ), 3057 VOL_ID_LEN )) { 3058 3059 SetFlag( VolumeFlags, VCB_STATE_ISO ); 3060 3061 } else if (RtlEqualMemory( CdHsgId, 3062 CdRvdId( RawIsoVd, VCB_STATE_HSG ), 3063 VOL_ID_LEN )) { 3064 3065 SetFlag( VolumeFlags, VCB_STATE_HSG ); 3066 3067 // 3068 // We have neither so break out of the loop. 3069 // 3070 3071 } else { 3072 3073 break; 3074 } 3075 3076 // 3077 // Break out if the version number is incorrect or this is 3078 // a terminator. 3079 // 3080 3081 if ((CdRvdVersion( RawIsoVd, VolumeFlags ) != VERSION_1) || 3082 (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_TERMINATOR)) { 3083 3084 break; 3085 } 3086 3087 // 3088 // If this is a primary volume descriptor then our search is over. 3089 // 3090 3091 if (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_PRIMARY) { 3092 3093 // 3094 // If we are not in the verify path then initialize the 3095 // fields in the Vcb with basic information from this 3096 // descriptor. 3097 // 3098 3099 if (!VerifyVolume) { 3100 3101 // 3102 // Set the flag for the volume type. 3103 // 3104 3105 SetFlag( Vcb->VcbState, VolumeFlags ); 3106 3107 // 3108 // Store the base sector and sector offset for the 3109 // primary volume descriptor. 3110 // 3111 3112 Vcb->BaseSector = BaseSector; 3113 Vcb->VdSectorOffset = SectorOffset; 3114 Vcb->PrimaryVdSectorOffset = SectorOffset; 3115 } 3116 3117 FoundVd = TRUE; 3118 break; 3119 } 3120 3121 // 3122 // Indicate that we're at the next sector. 3123 // 3124 3125 SectorOffset += 1; 3126 } 3127 3128 ThisPass += 1; 3129 } 3130 3131 return FoundVd; 3132 } 3133 3134 3135 // 3136 // Local support routine 3137 // 3138 3139 _Success_(return != FALSE) BOOLEAN 3140 CdIsRemount ( 3141 _In_ PIRP_CONTEXT IrpContext, 3142 _In_ PVCB Vcb, 3143 _Out_ PVCB *OldVcb 3144 ) 3145 /*++ 3146 3147 Routine Description: 3148 3149 This routine walks through the links of the Vcb chain in the global 3150 data structure. The remount condition is met when the following 3151 conditions are all met: 3152 3153 If the new Vcb is a device only Mvcb and there is a previous 3154 device only Mvcb. 3155 3156 Otherwise following conditions must be matched. 3157 3158 1 - The 32 serial in the current VPB matches that in a previous 3159 VPB. 3160 3161 2 - The volume label in the Vpb matches that in the previous 3162 Vpb. 3163 3164 3 - The system pointer to the real device object in the current 3165 VPB matches that in the same previous VPB. 3166 3167 4 - Finally the previous Vcb cannot be invalid or have a dismount 3168 underway. 3169 3170 If a VPB is found which matches these conditions, then the address of 3171 the VCB for that VPB is returned via the pointer Vcb. 3172 3173 Skip over the current Vcb. 3174 3175 Arguments: 3176 3177 Vcb - This is the Vcb we are checking for a remount. 3178 3179 OldVcb - A pointer to the address to store the address for the Vcb 3180 for the volume if this is a remount. (This is a pointer to 3181 a pointer) 3182 3183 Return Value: 3184 3185 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise. 3186 3187 --*/ 3188 3189 { 3190 PLIST_ENTRY Link; 3191 3192 PVPB Vpb = Vcb->Vpb; 3193 PVPB OldVpb; 3194 3195 BOOLEAN Remount = FALSE; 3196 3197 PAGED_CODE(); 3198 3199 UNREFERENCED_PARAMETER( IrpContext ); 3200 3201 // 3202 // Check whether we are looking for a device only Mvcb. 3203 // 3204 3205 for (Link = CdData.VcbQueue.Flink; 3206 Link != &CdData.VcbQueue; 3207 Link = Link->Flink) { 3208 3209 *OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks ); 3210 3211 // 3212 // Skip ourselves. 3213 // 3214 3215 if (Vcb == *OldVcb) { continue; } 3216 3217 // 3218 // Look at the Vpb and state of the previous Vcb. 3219 // 3220 3221 OldVpb = (*OldVcb)->Vpb; 3222 3223 if ((OldVpb != Vpb) && 3224 (OldVpb->RealDevice == Vpb->RealDevice) && 3225 ((*OldVcb)->VcbCondition == VcbNotMounted)) { 3226 3227 // 3228 // If the current disk is a raw disk then it can match a previous music or 3229 // raw disk. 3230 // 3231 3232 if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) { 3233 3234 if (FlagOn( (*OldVcb)->VcbState, VCB_STATE_AUDIO_DISK )) { 3235 3236 // 3237 // If we have both TOC then fail the remount if the lengths 3238 // are different or they don't match. 3239 // 3240 3241 if ((Vcb->TocLength != (*OldVcb)->TocLength) || 3242 ((Vcb->TocLength != 0) && 3243 !RtlEqualMemory( Vcb->CdromToc, 3244 (*OldVcb)->CdromToc, 3245 Vcb->TocLength ))) { 3246 3247 continue; 3248 } 3249 3250 Remount = TRUE; 3251 break; 3252 } 3253 3254 // 3255 // The current disk is not a raw disk. Go ahead and compare 3256 // serial numbers, volume label and TOC. 3257 // 3258 3259 } 3260 else if ((OldVpb->SerialNumber == Vpb->SerialNumber) && 3261 (Vcb->TocLength == (*OldVcb)->TocLength) && 3262 ((Vcb->TocLength == 0) || RtlEqualMemory( Vcb->CdromToc, 3263 (*OldVcb)->CdromToc, 3264 Vcb->TocLength )) && 3265 (Vpb->VolumeLabelLength == OldVpb->VolumeLabelLength) && 3266 (RtlEqualMemory( OldVpb->VolumeLabel, 3267 Vpb->VolumeLabel, 3268 Vpb->VolumeLabelLength ))) { 3269 // 3270 // Remember the old Vcb. Then set the return value to 3271 // TRUE and break. 3272 // 3273 3274 Remount = TRUE; 3275 break; 3276 } 3277 } 3278 } 3279 3280 return Remount; 3281 } 3282 3283 3284 // 3285 // Local support routine 3286 // 3287 3288 VOID 3289 CdFindActiveVolDescriptor ( 3290 _In_ PIRP_CONTEXT IrpContext, 3291 _In_ PVCB Vcb, 3292 _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE )) PCHAR RawIsoVd, 3293 _In_ BOOLEAN VerifyVolume 3294 ) 3295 3296 /*++ 3297 3298 Routine Description: 3299 3300 This routine is called to search for a valid secondary volume descriptor that 3301 we will support. Right now we only support Joliet escape sequences for 3302 the secondary descriptor. 3303 3304 If we don't find the secondary descriptor then we will reread the primary. 3305 3306 This routine will update the serial number and volume label in the Vpb. 3307 3308 Arguments: 3309 3310 Vcb - This is the Vcb for the volume being mounted. 3311 3312 RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but 3313 on input should contain the PVD (ISO) in the SECOND 'sector' of the 3314 buffer. 3315 3316 VerifyVolume - indicates we are being called by the verify path, and should 3317 not modify the Vcb fields. 3318 3319 Return Value: 3320 3321 None 3322 3323 --*/ 3324 3325 { 3326 BOOLEAN FoundSecondaryVd = FALSE; 3327 ULONG SectorOffset = FIRST_VD_SECTOR; 3328 3329 ULONG Length; 3330 3331 ULONG Index; 3332 3333 PAGED_CODE(); 3334 3335 // 3336 // We only look for secondary volume descriptors on an Iso disk. 3337 // 3338 3339 if ((FlagOn( Vcb->VcbState, VCB_STATE_ISO) || VerifyVolume) && !CdNoJoliet) { 3340 3341 // 3342 // Scan the volume descriptors from the beginning looking for a valid 3343 // secondary or a terminator. 3344 // 3345 3346 SectorOffset = FIRST_VD_SECTOR; 3347 3348 while (TRUE) { 3349 3350 // 3351 // Read the next sector. We should never have an error in this 3352 // path. 3353 // 3354 3355 CdReadSectors( IrpContext, 3356 LlBytesFromSectors( Vcb->BaseSector + SectorOffset ), 3357 SECTOR_SIZE, 3358 FALSE, 3359 RawIsoVd, 3360 Vcb->TargetDeviceObject ); 3361 3362 // 3363 // Break out if the version number or standard Id is incorrect. 3364 // Also break out if this is a terminator. 3365 // 3366 3367 if (!RtlEqualMemory( CdIsoId, CdRvdId( RawIsoVd, VCB_STATE_JOLIET ), VOL_ID_LEN ) || 3368 (CdRvdVersion( RawIsoVd, VCB_STATE_JOLIET ) != VERSION_1) || 3369 (CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_TERMINATOR)) { 3370 3371 break; 3372 } 3373 3374 // 3375 // We have a match if this is a secondary descriptor with a matching 3376 // escape sequence. 3377 // 3378 3379 if ((CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_SECONDARY) && 3380 (RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ), 3381 CdJolietEscape[0], 3382 ESC_SEQ_LEN ) || 3383 RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ), 3384 CdJolietEscape[1], 3385 ESC_SEQ_LEN ) || 3386 RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ), 3387 CdJolietEscape[2], 3388 ESC_SEQ_LEN ))) { 3389 3390 if (!VerifyVolume) { 3391 3392 // 3393 // Update the Vcb with the new volume descriptor. 3394 // 3395 3396 ClearFlag( Vcb->VcbState, VCB_STATE_ISO ); 3397 SetFlag( Vcb->VcbState, VCB_STATE_JOLIET ); 3398 3399 Vcb->VdSectorOffset = SectorOffset; 3400 } 3401 3402 FoundSecondaryVd = TRUE; 3403 break; 3404 } 3405 3406 // 3407 // Otherwise move on to the next sector. 3408 // 3409 3410 SectorOffset += 1; 3411 } 3412 3413 // 3414 // If we didn't find the secondary then recover the original volume 3415 // descriptor stored in the second half of the RawIsoVd. 3416 // 3417 3418 if (!FoundSecondaryVd) { 3419 3420 RtlCopyMemory( RawIsoVd, 3421 Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ), 3422 SECTOR_SIZE ); 3423 } 3424 } 3425 3426 // 3427 // If we're in the verify path, our work is done, since we don't want 3428 // to update any Vcb/Vpb values. 3429 // 3430 3431 if (VerifyVolume) { 3432 3433 return; 3434 } 3435 3436 // 3437 // Compute the serial number and volume label from the volume descriptor. 3438 // 3439 3440 Vcb->Vpb->SerialNumber = CdSerial32( RawIsoVd, SECTOR_SIZE ); 3441 3442 // 3443 // Make sure the CD label will fit in the Vpb. 3444 // 3445 3446 NT_ASSERT( VOLUME_ID_LENGTH * sizeof( WCHAR ) <= MAXIMUM_VOLUME_LABEL_LENGTH ); 3447 3448 // 3449 // If this is not a Unicode label we must convert it to unicode. 3450 // 3451 3452 if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) { 3453 3454 // 3455 // Convert the label to unicode. If we get any error then use a name 3456 // length of zero. 3457 // 3458 3459 Vcb->Vpb->VolumeLabelLength = 0; 3460 3461 if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb->Vpb->VolumeLabel[0], 3462 MAXIMUM_VOLUME_LABEL_LENGTH, 3463 &Length, 3464 (PCH)CdRvdVolId( RawIsoVd, Vcb->VcbState ), 3465 VOLUME_ID_LENGTH ))) { 3466 3467 Vcb->Vpb->VolumeLabelLength = (USHORT) Length; 3468 } 3469 3470 // 3471 // We need to convert from big-endian to little endian. 3472 // 3473 3474 } else { 3475 3476 CdConvertBigToLittleEndian( IrpContext, 3477 (PCHAR) CdRvdVolId( RawIsoVd, Vcb->VcbState ), 3478 VOLUME_ID_LENGTH, 3479 (PCHAR) Vcb->Vpb->VolumeLabel ); 3480 3481 Vcb->Vpb->VolumeLabelLength = VOLUME_ID_LENGTH * sizeof( WCHAR ); 3482 } 3483 3484 // 3485 // Strip the trailing spaces or zeroes from the name. 3486 // 3487 3488 Index = Vcb->Vpb->VolumeLabelLength / sizeof( WCHAR ); 3489 3490 while (Index > 0) { 3491 3492 if ((Vcb->Vpb->VolumeLabel[ Index - 1 ] != L'\0') && 3493 (Vcb->Vpb->VolumeLabel[ Index - 1 ] != L' ')) { 3494 3495 break; 3496 } 3497 3498 Index -= 1; 3499 } 3500 3501 // 3502 // Now set the final length for the name. 3503 // 3504 3505 Vcb->Vpb->VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR )); 3506 } 3507 3508 3509 3510