Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3146 lines
78 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Cdfs called
  7. by the Fsd/Fsp dispatch drivers.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Brian Andrew [BrianAn] 01-July-1995
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "CdProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (CDFS_BUG_CHECK_FSCTRL)
  19. //
  20. // Local constants
  21. //
  22. BOOLEAN CdDisable = FALSE;
  23. //
  24. // Local support routines
  25. //
  26. NTSTATUS
  27. CdUserFsctl (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PIRP Irp
  30. );
  31. VOID
  32. CdReMountOldVcb(
  33. IN PIRP_CONTEXT IrpContext,
  34. IN PVCB OldVcb,
  35. IN PVCB NewVcb,
  36. IN PDEVICE_OBJECT DeviceObjectWeTalkTo
  37. );
  38. NTSTATUS
  39. CdMountVolume (
  40. IN PIRP_CONTEXT IrpContext,
  41. IN PIRP Irp
  42. );
  43. NTSTATUS
  44. CdVerifyVolume (
  45. IN PIRP_CONTEXT IrpContext,
  46. IN PIRP Irp
  47. );
  48. NTSTATUS
  49. CdOplockRequest (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PIRP Irp
  52. );
  53. NTSTATUS
  54. CdLockVolume (
  55. IN PIRP_CONTEXT IrpContext,
  56. IN PIRP Irp
  57. );
  58. NTSTATUS
  59. CdUnlockVolume (
  60. IN PIRP_CONTEXT IrpContext,
  61. IN PIRP Irp
  62. );
  63. NTSTATUS
  64. CdDismountVolume (
  65. IN PIRP_CONTEXT IrpContext,
  66. IN PIRP Irp
  67. );
  68. CdIsVolumeDirty (
  69. IN PIRP_CONTEXT IrpContext,
  70. IN PIRP Irp
  71. );
  72. NTSTATUS
  73. CdIsVolumeMounted (
  74. IN PIRP_CONTEXT IrpContext,
  75. IN PIRP Irp
  76. );
  77. NTSTATUS
  78. CdIsPathnameValid (
  79. IN PIRP_CONTEXT IrpContext,
  80. IN PIRP Irp
  81. );
  82. NTSTATUS
  83. CdInvalidateVolumes (
  84. IN PIRP_CONTEXT IrpContext,
  85. IN PIRP Irp
  86. );
  87. VOID
  88. CdScanForDismountedVcb (
  89. IN PIRP_CONTEXT IrpContext
  90. );
  91. BOOLEAN
  92. CdFindPrimaryVd (
  93. IN PIRP_CONTEXT IrpContext,
  94. IN PVCB Vcb,
  95. IN PCHAR RawIsoVd,
  96. IN ULONG BlockFactor,
  97. IN BOOLEAN ReturnOnError,
  98. IN BOOLEAN VerifyVolume
  99. );
  100. BOOLEAN
  101. CdIsRemount (
  102. IN PIRP_CONTEXT IrpContext,
  103. IN PVCB Vcb,
  104. OUT PVCB *OldVcb
  105. );
  106. VOID
  107. CdFindActiveVolDescriptor (
  108. IN PIRP_CONTEXT IrpContext,
  109. IN PVCB Vcb,
  110. IN OUT PCHAR RawIsoVd,
  111. IN BOOLEAN VerifyVolume
  112. );
  113. #ifdef ALLOC_PRAGMA
  114. #pragma alloc_text(PAGE, CdCommonFsControl)
  115. #pragma alloc_text(PAGE, CdDismountVolume)
  116. #pragma alloc_text(PAGE, CdFindActiveVolDescriptor)
  117. #pragma alloc_text(PAGE, CdFindPrimaryVd)
  118. #pragma alloc_text(PAGE, CdIsPathnameValid)
  119. #pragma alloc_text(PAGE, CdIsRemount)
  120. #pragma alloc_text(PAGE, CdIsVolumeDirty)
  121. #pragma alloc_text(PAGE, CdIsVolumeMounted)
  122. #pragma alloc_text(PAGE, CdLockVolume)
  123. #pragma alloc_text(PAGE, CdMountVolume)
  124. #pragma alloc_text(PAGE, CdOplockRequest)
  125. #pragma alloc_text(PAGE, CdScanForDismountedVcb)
  126. #pragma alloc_text(PAGE, CdUnlockVolume)
  127. #pragma alloc_text(PAGE, CdUserFsctl)
  128. #pragma alloc_text(PAGE, CdVerifyVolume)
  129. #endif
  130. //
  131. // Local support routine
  132. //
  133. NTSTATUS
  134. CdLockVolumeInternal (
  135. IN PIRP_CONTEXT IrpContext,
  136. IN PVCB Vcb,
  137. IN PFILE_OBJECT FileObject OPTIONAL
  138. )
  139. /*++
  140. Routine Description:
  141. This routine performs the actual lock volume operation. It will be called
  142. by anyone wishing to try to protect the volume for a long duration. PNP
  143. operations are such a user.
  144. The volume must be held exclusive by the caller.
  145. Arguments:
  146. Vcb - The volume being locked.
  147. FileObject - File corresponding to the handle locking the volume. If this
  148. is not specified, a system lock is assumed.
  149. Return Value:
  150. NTSTATUS - The return status for the operation
  151. --*/
  152. {
  153. NTSTATUS Status;
  154. KIRQL SavedIrql;
  155. NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY);
  156. ULONG RemainingUserReferences = (FileObject? 1: 0);
  157. //
  158. // The cleanup count for the volume only reflects the fileobject that
  159. // will lock the volume. Otherwise, we must fail the request.
  160. //
  161. // Since the only cleanup is for the provided fileobject, we will try
  162. // to get rid of all of the other user references. If there is only one
  163. // remaining after the purge then we can allow the volume to be locked.
  164. //
  165. CdPurgeVolume( IrpContext, Vcb, FALSE );
  166. //
  167. // Now back out of our synchronization and wait for the lazy writer
  168. // to finish off any lazy closes that could have been outstanding.
  169. //
  170. // Since we purged, we know that the lazy writer will issue all
  171. // possible lazy closes in the next tick - if we hadn't, an otherwise
  172. // unopened file with a large amount of dirty data could have hung
  173. // around for a while as the data trickled out to the disk.
  174. //
  175. // This is even more important now since we send notification to
  176. // alert other folks that this style of check is about to happen so
  177. // that they can close their handles. We don't want to enter a fast
  178. // race with the lazy writer tearing down his references to the file.
  179. //
  180. CdReleaseVcb( IrpContext, Vcb );
  181. Status = CcWaitForCurrentLazyWriterActivity();
  182. //
  183. // This is intentional. If we were able to get the Vcb before, just
  184. // wait for it and take advantage of knowing that it is OK to leave
  185. // the flag up.
  186. //
  187. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  188. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  189. if (!NT_SUCCESS( Status )) {
  190. return Status;
  191. }
  192. CdFspClose( Vcb );
  193. //
  194. // If the volume is already explicitly locked then fail. We use the
  195. // Vpb locked flag as an 'explicit lock' flag in the same way as Fat.
  196. //
  197. IoAcquireVpbSpinLock( &SavedIrql );
  198. if (!FlagOn( Vcb->Vpb->Flags, VPB_LOCKED ) &&
  199. (Vcb->VcbCleanup == RemainingUserReferences) &&
  200. (Vcb->VcbUserReference == CDFS_RESIDUAL_USER_REFERENCE + RemainingUserReferences)) {
  201. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  202. SetFlag( Vcb->Vpb->Flags, VPB_LOCKED);
  203. Vcb->VolumeLockFileObject = FileObject;
  204. FinalStatus = STATUS_SUCCESS;
  205. }
  206. IoReleaseVpbSpinLock( SavedIrql );
  207. return FinalStatus;
  208. }
  209. NTSTATUS
  210. CdUnlockVolumeInternal (
  211. IN PIRP_CONTEXT IrpContext,
  212. IN PVCB Vcb,
  213. IN PFILE_OBJECT FileObject OPTIONAL
  214. )
  215. /*++
  216. Routine Description:
  217. This routine performs the actual unlock volume operation.
  218. The volume must be held exclusive by the caller.
  219. Arguments:
  220. Vcb - The volume being locked.
  221. FileObject - File corresponding to the handle locking the volume. If this
  222. is not specified, a system lock is assumed.
  223. Return Value:
  224. NTSTATUS - The return status for the operation
  225. Attempting to remove a system lock that did not exist is OK.
  226. --*/
  227. {
  228. NTSTATUS Status = STATUS_NOT_LOCKED;
  229. KIRQL SavedIrql;
  230. //
  231. // Note that we check the VPB_LOCKED flag here rather than the Vcb
  232. // lock flag. The Vpb flag is only set for an explicit lock request, not
  233. // for the implicit lock obtained on a volume open with zero share mode.
  234. //
  235. IoAcquireVpbSpinLock( &SavedIrql );
  236. if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) &&
  237. (FileObject == Vcb->VolumeLockFileObject)) {
  238. ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  239. ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED);
  240. Vcb->VolumeLockFileObject = NULL;
  241. Status = STATUS_SUCCESS;
  242. }
  243. IoReleaseVpbSpinLock( SavedIrql );
  244. return Status;
  245. }
  246. NTSTATUS
  247. CdCommonFsControl (
  248. IN PIRP_CONTEXT IrpContext,
  249. IN PIRP Irp
  250. )
  251. /*++
  252. Routine Description:
  253. This is the common routine for doing FileSystem control operations called
  254. by both the fsd and fsp threads
  255. Arguments:
  256. Irp - Supplies the Irp to process
  257. Return Value:
  258. NTSTATUS - The return status for the operation
  259. --*/
  260. {
  261. NTSTATUS Status;
  262. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  263. //
  264. // Get a pointer to the current Irp stack location
  265. //
  266. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  267. PAGED_CODE();
  268. //
  269. // We know this is a file system control so we'll case on the
  270. // minor function, and call a internal worker routine to complete
  271. // the irp.
  272. //
  273. switch (IrpSp->MinorFunction) {
  274. case IRP_MN_USER_FS_REQUEST:
  275. Status = CdUserFsctl( IrpContext, Irp );
  276. break;
  277. case IRP_MN_MOUNT_VOLUME:
  278. Status = CdMountVolume( IrpContext, Irp );
  279. break;
  280. case IRP_MN_VERIFY_VOLUME:
  281. Status = CdVerifyVolume( IrpContext, Irp );
  282. break;
  283. default:
  284. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  285. Status = STATUS_INVALID_DEVICE_REQUEST;
  286. break;
  287. }
  288. return Status;
  289. }
  290. //
  291. // Local support routine
  292. //
  293. NTSTATUS
  294. CdUserFsctl (
  295. IN PIRP_CONTEXT IrpContext,
  296. IN PIRP Irp
  297. )
  298. /*++
  299. Routine Description:
  300. This is the common routine for implementing the user's requests made
  301. through NtFsControlFile.
  302. Arguments:
  303. Irp - Supplies the Irp being processed
  304. Return Value:
  305. NTSTATUS - The return status for the operation
  306. --*/
  307. {
  308. NTSTATUS Status;
  309. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  310. PAGED_CODE();
  311. //
  312. // Case on the control code.
  313. //
  314. switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) {
  315. case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
  316. case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
  317. case FSCTL_REQUEST_BATCH_OPLOCK :
  318. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
  319. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  320. case FSCTL_OPLOCK_BREAK_NOTIFY :
  321. case FSCTL_OPLOCK_BREAK_ACK_NO_2 :
  322. case FSCTL_REQUEST_FILTER_OPLOCK :
  323. Status = CdOplockRequest( IrpContext, Irp );
  324. break;
  325. case FSCTL_LOCK_VOLUME :
  326. Status = CdLockVolume( IrpContext, Irp );
  327. break;
  328. case FSCTL_UNLOCK_VOLUME :
  329. Status = CdUnlockVolume( IrpContext, Irp );
  330. break;
  331. case FSCTL_DISMOUNT_VOLUME :
  332. Status = CdDismountVolume( IrpContext, Irp );
  333. break;
  334. case FSCTL_IS_VOLUME_DIRTY :
  335. Status = CdIsVolumeDirty( IrpContext, Irp );
  336. break;
  337. case FSCTL_IS_VOLUME_MOUNTED :
  338. Status = CdIsVolumeMounted( IrpContext, Irp );
  339. break;
  340. case FSCTL_IS_PATHNAME_VALID :
  341. Status = CdIsPathnameValid( IrpContext, Irp );
  342. break;
  343. case FSCTL_INVALIDATE_VOLUMES :
  344. Status = CdInvalidateVolumes( IrpContext, Irp );
  345. break;
  346. //
  347. // We don't support any of the known or unknown requests.
  348. //
  349. default:
  350. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  351. Status = STATUS_INVALID_DEVICE_REQUEST;
  352. break;
  353. }
  354. return Status;
  355. }
  356. VOID
  357. CdReMountOldVcb(
  358. IN PIRP_CONTEXT IrpContext,
  359. IN PVCB OldVcb,
  360. IN PVCB NewVcb,
  361. IN PDEVICE_OBJECT DeviceObjectWeTalkTo
  362. )
  363. {
  364. KIRQL SavedIrql;
  365. ObDereferenceObject( OldVcb->TargetDeviceObject );
  366. IoAcquireVpbSpinLock( &SavedIrql );
  367. NewVcb->Vpb->RealDevice->Vpb = OldVcb->Vpb;
  368. OldVcb->Vpb->RealDevice = NewVcb->Vpb->RealDevice;
  369. OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo;
  370. CdUpdateVcbCondition( OldVcb, VcbMounted);
  371. CdUpdateMediaChangeCount( OldVcb, NewVcb->MediaChangeCount);
  372. ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
  373. IoReleaseVpbSpinLock( SavedIrql );
  374. }
  375. //
  376. // Local support routine
  377. //
  378. NTSTATUS
  379. CdMountVolume (
  380. IN PIRP_CONTEXT IrpContext,
  381. IN PIRP Irp
  382. )
  383. /*++
  384. Routine Description:
  385. This routine performs the mount volume operation. It is responsible for
  386. either completing of enqueuing the input Irp.
  387. Its job is to verify that the volume denoted in the IRP is a Cdrom volume,
  388. and create the VCB and root DCB structures. The algorithm it
  389. uses is essentially as follows:
  390. 1. Create a new Vcb Structure, and initialize it enough to do I/O
  391. through the on-disk volume descriptors.
  392. 2. Read the disk and check if it is a Cdrom volume.
  393. 3. If it is not a Cdrom volume then delete the Vcb and
  394. complete the IRP back with an appropriate status.
  395. 4. Check if the volume was previously mounted and if it was then do a
  396. remount operation. This involves deleting the VCB, hook in the
  397. old VCB, and complete the IRP.
  398. 5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
  399. Arguments:
  400. Irp - Supplies the Irp to process
  401. Return Value:
  402. NTSTATUS - The return status for the operation
  403. --*/
  404. {
  405. NTSTATUS Status;
  406. PVOLUME_DEVICE_OBJECT VolDo = NULL;
  407. PVCB Vcb = NULL;
  408. PVCB OldVcb;
  409. BOOLEAN FoundPvd = FALSE;
  410. BOOLEAN SetDoVerifyOnFail;
  411. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  412. PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
  413. PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
  414. PFILE_OBJECT FileObjectToNotify = NULL;
  415. ULONG BlockFactor;
  416. DISK_GEOMETRY DiskGeometry;
  417. IO_SCSI_CAPABILITIES Capabilities;
  418. IO_STATUS_BLOCK Iosb;
  419. PCHAR RawIsoVd = NULL;
  420. PCDROM_TOC CdromToc = NULL;
  421. ULONG TocLength = 0;
  422. ULONG TocTrackCount = 0;
  423. ULONG TocDiskFlags = 0;
  424. ULONG MediaChangeCount = 0;
  425. PAGED_CODE();
  426. //
  427. // Check that we are talking to a Cdrom device. This request should
  428. // always be waitable.
  429. //
  430. ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
  431. ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
  432. //
  433. // Update the real device in the IrpContext from the Vpb. There was no available
  434. // file object when the IrpContext was created.
  435. //
  436. IrpContext->RealDevice = Vpb->RealDevice;
  437. SetDoVerifyOnFail = CdRealDevNeedsVerify( IrpContext->RealDevice);
  438. //
  439. // Check if we have disabled the mount process.
  440. //
  441. if (CdDisable) {
  442. CdCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  443. return STATUS_UNRECOGNIZED_VOLUME;
  444. }
  445. //
  446. // Do a CheckVerify here to lift the MediaChange ticker from the driver
  447. //
  448. Status = CdPerformDevIoCtrl( IrpContext,
  449. IOCTL_CDROM_CHECK_VERIFY,
  450. DeviceObjectWeTalkTo,
  451. &MediaChangeCount,
  452. sizeof(ULONG),
  453. FALSE,
  454. TRUE,
  455. &Iosb );
  456. if (!NT_SUCCESS( Status )) {
  457. CdCompleteRequest( IrpContext, Irp, Status );
  458. return Status;
  459. }
  460. if (Iosb.Information != sizeof(ULONG)) {
  461. //
  462. // Be safe about the count in case the driver didn't fill it in
  463. //
  464. MediaChangeCount = 0;
  465. }
  466. //
  467. // Now let's make Jeff delirious and call to get the disk geometry. This
  468. // will fix the case where the first change line is swallowed.
  469. //
  470. Status = CdPerformDevIoCtrl( IrpContext,
  471. IOCTL_CDROM_GET_DRIVE_GEOMETRY,
  472. DeviceObjectWeTalkTo,
  473. &DiskGeometry,
  474. sizeof( DISK_GEOMETRY ),
  475. FALSE,
  476. TRUE,
  477. NULL );
  478. //
  479. // Return insufficient sources to our caller.
  480. //
  481. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  482. CdCompleteRequest( IrpContext, Irp, Status );
  483. return Status;
  484. }
  485. //
  486. // Now check the block factor for addressing the volume descriptors.
  487. // If the call for the disk geometry failed then assume there is one
  488. // block per sector.
  489. //
  490. BlockFactor = 1;
  491. if (NT_SUCCESS( Status ) &&
  492. (DiskGeometry.BytesPerSector != 0) &&
  493. (DiskGeometry.BytesPerSector < SECTOR_SIZE)) {
  494. BlockFactor = SECTOR_SIZE / DiskGeometry.BytesPerSector;
  495. }
  496. //
  497. // Acquire the global resource to do mount operations.
  498. //
  499. CdAcquireCdData( IrpContext );
  500. //
  501. // Use a try-finally to facilitate cleanup.
  502. //
  503. try {
  504. //
  505. // Allocate a buffer to query the TOC.
  506. //
  507. CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
  508. sizeof( CDROM_TOC ),
  509. TAG_CDROM_TOC );
  510. RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
  511. //
  512. // Do a quick check to see if there any Vcb's which can be removed.
  513. //
  514. CdScanForDismountedVcb( IrpContext );
  515. //
  516. // Get our device object and alignment requirement.
  517. //
  518. Status = IoCreateDevice( CdData.DriverObject,
  519. sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ),
  520. NULL,
  521. FILE_DEVICE_CD_ROM_FILE_SYSTEM,
  522. 0,
  523. FALSE,
  524. (PDEVICE_OBJECT *) &VolDo );
  525. if (!NT_SUCCESS( Status )) { try_leave( Status ); }
  526. //
  527. // Our alignment requirement is the larger of the processor alignment requirement
  528. // already in the volume device object and that in the DeviceObjectWeTalkTo
  529. //
  530. if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
  531. VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
  532. }
  533. //
  534. // We must initialize the stack size in our device object before
  535. // the following reads, because the I/O system has not done it yet.
  536. //
  537. ((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1);
  538. ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
  539. //
  540. // Initialize the overflow queue for the volume
  541. //
  542. VolDo->OverflowQueueCount = 0;
  543. InitializeListHead( &VolDo->OverflowQueue );
  544. VolDo->PostedRequestCount = 0;
  545. KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
  546. //
  547. // Let's query for the Toc now and handle any error we get from this operation.
  548. //
  549. Status = CdProcessToc( IrpContext,
  550. DeviceObjectWeTalkTo,
  551. CdromToc,
  552. &TocLength,
  553. &TocTrackCount,
  554. &TocDiskFlags );
  555. //
  556. // If we failed to read the TOC, then bail out. Probably blank media.
  557. //
  558. if (Status != STATUS_SUCCESS) {
  559. try_leave( Status );
  560. }
  561. //
  562. // Now before we can initialize the Vcb we need to set up the
  563. // device object field in the VPB to point to our new volume device
  564. // object.
  565. //
  566. Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
  567. //
  568. // Initialize the Vcb. This routine will raise on an allocation
  569. // failure.
  570. //
  571. CdInitializeVcb( IrpContext,
  572. &VolDo->Vcb,
  573. DeviceObjectWeTalkTo,
  574. Vpb,
  575. CdromToc,
  576. TocLength,
  577. TocTrackCount,
  578. TocDiskFlags,
  579. BlockFactor,
  580. MediaChangeCount );
  581. //
  582. // Show that we initialized the Vcb and can cleanup with the Vcb.
  583. //
  584. Vcb = &VolDo->Vcb;
  585. VolDo = NULL;
  586. Vpb = NULL;
  587. CdromToc = NULL;
  588. //
  589. // Store the Vcb in the IrpContext as we didn't have one before.
  590. //
  591. IrpContext->Vcb = Vcb;
  592. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  593. //
  594. // Let's reference the Vpb to make sure we are the one to
  595. // have the last dereference.
  596. //
  597. Vcb->Vpb->ReferenceCount += 1;
  598. //
  599. // Clear the verify bit for the start of mount.
  600. //
  601. CdMarkRealDevVerifyOk( Vcb->Vpb->RealDevice);
  602. if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
  603. //
  604. // Allocate a buffer to read in the volume descriptors. We allocate a full
  605. // page to make sure we don't hit any alignment problems.
  606. //
  607. RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
  608. ROUND_TO_PAGES( SECTOR_SIZE ),
  609. TAG_VOL_DESC );
  610. //
  611. // Try to find the primary volume descriptor.
  612. //
  613. FoundPvd = CdFindPrimaryVd( IrpContext,
  614. Vcb,
  615. RawIsoVd,
  616. BlockFactor,
  617. TRUE,
  618. FALSE );
  619. if (!FoundPvd) {
  620. //
  621. // We failed to find a valid VD in the data track, but there were also
  622. // audio tracks on this disc, so we'll try to mount it as an audio CD.
  623. // Since we're always last in the mount order, we won't be preventing
  624. // any other FS from trying to mount the data track. However if the
  625. // data track was at the start of the disc, then we abort, to avoid
  626. // having to filter it from our synthesised directory listing later. We
  627. // already filtered off any data track at the end.
  628. //
  629. if (!(TocDiskFlags & CDROM_DISK_AUDIO_TRACK) ||
  630. BooleanFlagOn( Vcb->CdromToc->TrackData[0].Control, TOC_DATA_TRACK)) {
  631. try_leave( Status = STATUS_UNRECOGNIZED_VOLUME);
  632. }
  633. SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
  634. ExFreePool( RawIsoVd );
  635. RawIsoVd = NULL;
  636. }
  637. }
  638. //
  639. // Look and see if there is a secondary volume descriptor we want to
  640. // use.
  641. //
  642. if (FoundPvd) {
  643. //
  644. // Store the primary volume descriptor in the second half of
  645. // RawIsoVd. Then if our search for a secondary fails we can
  646. // recover this immediately.
  647. //
  648. RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
  649. RawIsoVd,
  650. SECTOR_SIZE );
  651. //
  652. // We have the initial volume descriptor. Locate a secondary
  653. // volume descriptor if present.
  654. //
  655. CdFindActiveVolDescriptor( IrpContext,
  656. Vcb,
  657. RawIsoVd,
  658. FALSE);
  659. }
  660. //
  661. // Check if this is a remount operation. If so then clean up
  662. // the data structures passed in and created here.
  663. //
  664. if (CdIsRemount( IrpContext, Vcb, &OldVcb )) {
  665. KIRQL SavedIrql;
  666. ASSERT( NULL != OldVcb->SwapVpb );
  667. //
  668. // Link the old Vcb to point to the new device object that we
  669. // should be talking to, dereferencing the previous. Call a
  670. // nonpaged routine to do this since we take the Vpb spinlock.
  671. //
  672. CdReMountOldVcb( IrpContext,
  673. OldVcb,
  674. Vcb,
  675. DeviceObjectWeTalkTo);
  676. //
  677. // See if we will need to provide notification of the remount. This is the readonly
  678. // filesystem's form of dismount/mount notification - we promise that whenever a
  679. // volume is "dismounted", that a mount notification will occur when it is revalidated.
  680. // Note that we do not send mount on normal remounts - that would duplicate the media
  681. // arrival notification of the device driver.
  682. //
  683. if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
  684. ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
  685. FileObjectToNotify = OldVcb->RootIndexFcb->FileObject;
  686. ObReferenceObject( FileObjectToNotify );
  687. }
  688. try_leave( Status = STATUS_SUCCESS );
  689. }
  690. //
  691. // This is a new mount. Go ahead and initialize the
  692. // Vcb from the volume descriptor.
  693. //
  694. CdUpdateVcbFromVolDescriptor( IrpContext,
  695. Vcb,
  696. RawIsoVd );
  697. //
  698. // Drop an extra reference on the root dir file so we'll be able to send
  699. // notification.
  700. //
  701. if (Vcb->RootIndexFcb) {
  702. FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
  703. ObReferenceObject( FileObjectToNotify );
  704. }
  705. //
  706. // Now check the maximum transfer limits on the device in case we
  707. // get raw reads on this volume.
  708. //
  709. Status = CdPerformDevIoCtrl( IrpContext,
  710. IOCTL_SCSI_GET_CAPABILITIES,
  711. DeviceObjectWeTalkTo,
  712. &Capabilities,
  713. sizeof( IO_SCSI_CAPABILITIES ),
  714. FALSE,
  715. TRUE,
  716. NULL );
  717. if (NT_SUCCESS(Status)) {
  718. Vcb->MaximumTransferRawSectors = Capabilities.MaximumTransferLength / RAW_SECTOR_SIZE;
  719. Vcb->MaximumPhysicalPages = Capabilities.MaximumPhysicalPages;
  720. } else {
  721. //
  722. // This should never happen, but we can safely assume 64k and 16 pages.
  723. //
  724. Vcb->MaximumTransferRawSectors = (64 * 1024) / RAW_SECTOR_SIZE;
  725. Vcb->MaximumPhysicalPages = 16;
  726. }
  727. //
  728. // The new mount is complete. Remove the additional references on this
  729. // Vcb and the device we are mounted on top of.
  730. //
  731. Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
  732. ASSERT( Vcb->VcbReference == CDFS_RESIDUAL_REFERENCE );
  733. ObDereferenceObject( Vcb->TargetDeviceObject );
  734. CdUpdateVcbCondition( Vcb, VcbMounted);
  735. CdReleaseVcb( IrpContext, Vcb );
  736. Vcb = NULL;
  737. Status = STATUS_SUCCESS;
  738. } finally {
  739. //
  740. // Free the TOC buffer if not in the Vcb.
  741. //
  742. if (CdromToc != NULL) {
  743. ExFreePool( CdromToc );
  744. }
  745. //
  746. // Free the sector buffer if allocated.
  747. //
  748. if (RawIsoVd != NULL) {
  749. ExFreePool( RawIsoVd );
  750. }
  751. //
  752. // If we are not mounting the device, then set the verify bit again.
  753. //
  754. if ((AbnormalTermination() || (Status != STATUS_SUCCESS)) &&
  755. SetDoVerifyOnFail) {
  756. CdMarkRealDevForVerify( IrpContext->RealDevice);
  757. }
  758. //
  759. // If we didn't complete the mount then cleanup any remaining structures.
  760. //
  761. if (Vpb != NULL) { Vpb->DeviceObject = NULL; }
  762. if (Vcb != NULL) {
  763. //
  764. // Make sure there is no Vcb in the IrpContext since it could go away
  765. //
  766. IrpContext->Vcb = NULL;
  767. Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
  768. if (CdDismountVcb( IrpContext, Vcb )) {
  769. CdReleaseVcb( IrpContext, Vcb );
  770. }
  771. } else if (VolDo != NULL) {
  772. IoDeleteDevice( (PDEVICE_OBJECT) VolDo );
  773. }
  774. //
  775. // Release the global resource.
  776. //
  777. CdReleaseCdData( IrpContext );
  778. }
  779. //
  780. // Now send mount notification.
  781. //
  782. if (FileObjectToNotify) {
  783. FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
  784. ObDereferenceObject( FileObjectToNotify );
  785. }
  786. //
  787. // Complete the request if no exception.
  788. //
  789. CdCompleteRequest( IrpContext, Irp, Status );
  790. return Status;
  791. }
  792. //
  793. // Local support routine
  794. //
  795. NTSTATUS
  796. CdVerifyVolume (
  797. IN PIRP_CONTEXT IrpContext,
  798. IN PIRP Irp
  799. )
  800. /*++
  801. Routine Description:
  802. This routine performs the verify volume operation. It is responsible for
  803. either completing of enqueuing the input Irp.
  804. Arguments:
  805. Irp - Supplies the Irp to process
  806. Return Value:
  807. NTSTATUS - The return status for the operation
  808. --*/
  809. {
  810. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  811. PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
  812. PVCB Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->Parameters.VerifyVolume.DeviceObject)->Vcb;
  813. PCHAR RawIsoVd = NULL;
  814. PCDROM_TOC CdromToc = NULL;
  815. ULONG TocLength = 0;
  816. ULONG TocTrackCount = 0;
  817. ULONG TocDiskFlags = 0;
  818. ULONG MediaChangeCount = Vcb->MediaChangeCount;
  819. PFILE_OBJECT FileObjectToNotify = NULL;
  820. BOOLEAN ReturnError;
  821. BOOLEAN ReleaseVcb;
  822. IO_STATUS_BLOCK Iosb;
  823. STRING AnsiLabel;
  824. UNICODE_STRING UnicodeLabel;
  825. WCHAR VolumeLabel[ VOLUME_ID_LENGTH ];
  826. ULONG VolumeLabelLength;
  827. ULONG Index;
  828. NTSTATUS Status;
  829. PAGED_CODE();
  830. //
  831. // We check that we are talking to a Cdrom device.
  832. //
  833. ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
  834. ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
  835. //
  836. // Update the real device in the IrpContext from the Vpb. There was no available
  837. // file object when the IrpContext was created.
  838. //
  839. IrpContext->RealDevice = Vpb->RealDevice;
  840. //
  841. // Acquire the global resource to synchronise against mounts and teardown,
  842. // finally clause releases.
  843. //
  844. CdAcquireCdData( IrpContext );
  845. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  846. ReleaseVcb = TRUE;
  847. try {
  848. //
  849. // Verify that there is a disk here.
  850. //
  851. Status = CdPerformDevIoCtrl( IrpContext,
  852. IOCTL_CDROM_CHECK_VERIFY,
  853. Vcb->TargetDeviceObject,
  854. &MediaChangeCount,
  855. sizeof(ULONG),
  856. FALSE,
  857. TRUE,
  858. &Iosb );
  859. if (!NT_SUCCESS( Status )) {
  860. //
  861. // If we will allow a raw mount then return WRONG_VOLUME to
  862. // allow the volume to be mounted by raw.
  863. //
  864. if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
  865. Status = STATUS_WRONG_VOLUME;
  866. }
  867. try_return( Status );
  868. }
  869. if (Iosb.Information != sizeof(ULONG)) {
  870. //
  871. // Be safe about the count in case the driver didn't fill it in
  872. //
  873. MediaChangeCount = 0;
  874. }
  875. //
  876. // Verify that the device actually saw a change. If the driver does not
  877. // support the MCC, then we must verify the volume in any case.
  878. //
  879. if (MediaChangeCount == 0 ||
  880. (Vcb->MediaChangeCount != MediaChangeCount)) {
  881. //
  882. // Allocate a buffer to query the TOC.
  883. //
  884. CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
  885. sizeof( CDROM_TOC ),
  886. TAG_CDROM_TOC );
  887. RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
  888. //
  889. // Let's query for the Toc now and handle any error we get from this operation.
  890. //
  891. Status = CdProcessToc( IrpContext,
  892. Vcb->TargetDeviceObject,
  893. CdromToc,
  894. &TocLength,
  895. &TocTrackCount,
  896. &TocDiskFlags );
  897. //
  898. // If we failed to read the TOC, then give up now. Drives will fail
  899. // a TOC read on, for example, erased CD-RW media.
  900. //
  901. if (Status != STATUS_SUCCESS) {
  902. //
  903. // For any errors other than no media and not ready, commute the
  904. // status to ensure that the current VPB is kicked off the device
  905. // below - there is probably blank media in the drive, since we got
  906. // further than the check verify.
  907. //
  908. if (!CdIsRawDevice( IrpContext, Status )) {
  909. Status = STATUS_WRONG_VOLUME;
  910. }
  911. try_return( Status );
  912. //
  913. // We got a TOC. Verify that it matches the previous Toc.
  914. //
  915. } else if ((Vcb->TocLength != TocLength) ||
  916. (Vcb->TrackCount != TocTrackCount) ||
  917. (Vcb->DiskFlags != TocDiskFlags) ||
  918. !RtlEqualMemory( CdromToc,
  919. Vcb->CdromToc,
  920. TocLength )) {
  921. try_return( Status = STATUS_WRONG_VOLUME );
  922. }
  923. //
  924. // If the disk to verify is an audio disk then we already have a
  925. // match. Otherwise we need to check the volume descriptor.
  926. //
  927. if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
  928. //
  929. // Allocate a buffer for the sector buffer.
  930. //
  931. RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
  932. ROUND_TO_PAGES( 2 * SECTOR_SIZE ),
  933. TAG_VOL_DESC );
  934. //
  935. // Read the primary volume descriptor for this volume. If we
  936. // get an io error and this verify was a the result of DASD open,
  937. // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
  938. // expect a music disk then this request should fail.
  939. //
  940. ReturnError = FALSE;
  941. if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
  942. ReturnError = TRUE;
  943. }
  944. if (!CdFindPrimaryVd( IrpContext,
  945. Vcb,
  946. RawIsoVd,
  947. Vcb->BlockFactor,
  948. ReturnError,
  949. TRUE )) {
  950. //
  951. // If the previous Vcb did not represent a raw disk
  952. // then show this volume was dismounted.
  953. //
  954. try_return( Status = STATUS_WRONG_VOLUME );
  955. }
  956. else {
  957. //
  958. // Look for a supplementary VD.
  959. //
  960. // Store the primary volume descriptor in the second half of
  961. // RawIsoVd. Then if our search for a secondary fails we can
  962. // recover this immediately.
  963. //
  964. RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
  965. RawIsoVd,
  966. SECTOR_SIZE );
  967. //
  968. // We have the initial volume descriptor. Locate a secondary
  969. // volume descriptor if present.
  970. //
  971. CdFindActiveVolDescriptor( IrpContext,
  972. Vcb,
  973. RawIsoVd,
  974. TRUE);
  975. //
  976. // Compare the serial numbers. If they don't match, set the
  977. // status to wrong volume.
  978. //
  979. if (Vpb->SerialNumber != CdSerial32( RawIsoVd, SECTOR_SIZE )) {
  980. try_return( Status = STATUS_WRONG_VOLUME );
  981. }
  982. //
  983. // Verify the volume labels.
  984. //
  985. if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
  986. //
  987. // Compute the length of the volume name
  988. //
  989. AnsiLabel.Buffer = CdRvdVolId( RawIsoVd, Vcb->VcbState );
  990. AnsiLabel.MaximumLength = AnsiLabel.Length = VOLUME_ID_LENGTH;
  991. UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
  992. UnicodeLabel.Buffer = VolumeLabel;
  993. //
  994. // Convert this to unicode. If we get any error then use a name
  995. // length of zero.
  996. //
  997. VolumeLabelLength = 0;
  998. if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel,
  999. &AnsiLabel,
  1000. FALSE ))) {
  1001. VolumeLabelLength = UnicodeLabel.Length;
  1002. }
  1003. //
  1004. // We need to convert from big-endian to little endian.
  1005. //
  1006. } else {
  1007. CdConvertBigToLittleEndian( IrpContext,
  1008. CdRvdVolId( RawIsoVd, Vcb->VcbState ),
  1009. VOLUME_ID_LENGTH,
  1010. (PCHAR) VolumeLabel );
  1011. VolumeLabelLength = VOLUME_ID_LENGTH;
  1012. }
  1013. //
  1014. // Strip the trailing spaces or zeroes from the name.
  1015. //
  1016. Index = VolumeLabelLength / sizeof( WCHAR );
  1017. while (Index > 0) {
  1018. if ((VolumeLabel[ Index - 1 ] != L'\0') &&
  1019. (VolumeLabel[ Index - 1 ] != L' ')) {
  1020. break;
  1021. }
  1022. Index -= 1;
  1023. }
  1024. //
  1025. // Now set the final length for the name.
  1026. //
  1027. VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
  1028. //
  1029. // Now check that the label matches.
  1030. //
  1031. if ((Vpb->VolumeLabelLength != VolumeLabelLength) ||
  1032. !RtlEqualMemory( Vpb->VolumeLabel,
  1033. VolumeLabel,
  1034. VolumeLabelLength )) {
  1035. try_return( Status = STATUS_WRONG_VOLUME );
  1036. }
  1037. }
  1038. }
  1039. }
  1040. //
  1041. // The volume is OK, clear the verify bit.
  1042. //
  1043. CdUpdateVcbCondition( Vcb, VcbMounted);
  1044. CdMarkRealDevVerifyOk( Vpb->RealDevice);
  1045. //
  1046. // See if we will need to provide notification of the remount. This is the readonly
  1047. // filesystem's form of dismount/mount notification.
  1048. //
  1049. if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
  1050. ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
  1051. FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
  1052. ObReferenceObject( FileObjectToNotify );
  1053. }
  1054. try_exit: NOTHING;
  1055. //
  1056. // Update the media change count to note that we have verified the volume
  1057. // at this value - regardless of the outcome.
  1058. //
  1059. CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
  1060. //
  1061. // If we got the wrong volume then free any remaining XA sector in
  1062. // the current Vcb. Also mark the Vcb as not mounted.
  1063. //
  1064. if (Status == STATUS_WRONG_VOLUME) {
  1065. CdUpdateVcbCondition( Vcb, VcbNotMounted);
  1066. if (Vcb->XASector != NULL) {
  1067. ExFreePool( Vcb->XASector );
  1068. Vcb->XASector = 0;
  1069. Vcb->XADiskOffset = 0;
  1070. }
  1071. //
  1072. // Now, if there are no user handles to the volume, try to spark
  1073. // teardown by purging the volume.
  1074. //
  1075. if (Vcb->VcbCleanup == 0) {
  1076. if (NT_SUCCESS( CdPurgeVolume( IrpContext, Vcb, FALSE ))) {
  1077. ReleaseVcb = CdCheckForDismount( IrpContext, Vcb, FALSE );
  1078. }
  1079. }
  1080. }
  1081. } finally {
  1082. //
  1083. // Free the TOC buffer if allocated.
  1084. //
  1085. if (CdromToc != NULL) {
  1086. ExFreePool( CdromToc );
  1087. }
  1088. if (RawIsoVd != NULL) {
  1089. ExFreePool( RawIsoVd );
  1090. }
  1091. if (ReleaseVcb) {
  1092. CdReleaseVcb( IrpContext, Vcb );
  1093. }
  1094. CdReleaseCdData( IrpContext );
  1095. }
  1096. //
  1097. // Now send mount notification.
  1098. //
  1099. if (FileObjectToNotify) {
  1100. FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
  1101. ObDereferenceObject( FileObjectToNotify );
  1102. }
  1103. //
  1104. // Complete the request if no exception.
  1105. //
  1106. CdCompleteRequest( IrpContext, Irp, Status );
  1107. return Status;
  1108. }
  1109. //
  1110. // Local support routine
  1111. //
  1112. NTSTATUS
  1113. CdOplockRequest (
  1114. IN PIRP_CONTEXT IrpContext,
  1115. IN PIRP Irp
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. This is the common routine to handle oplock requests made via the
  1120. NtFsControlFile call.
  1121. Arguments:
  1122. Irp - Supplies the Irp being processed
  1123. Return Value:
  1124. NTSTATUS - The return status for the operation
  1125. --*/
  1126. {
  1127. NTSTATUS Status;
  1128. PFCB Fcb;
  1129. PCCB Ccb;
  1130. ULONG OplockCount = 0;
  1131. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1132. PAGED_CODE();
  1133. //
  1134. // We only permit oplock requests on files.
  1135. //
  1136. if (CdDecodeFileObject( IrpContext,
  1137. IrpSp->FileObject,
  1138. &Fcb,
  1139. &Ccb ) != UserFileOpen ) {
  1140. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1141. return STATUS_INVALID_PARAMETER;
  1142. }
  1143. //
  1144. // Make this a waitable Irpcontext so we don't fail to acquire
  1145. // the resources.
  1146. //
  1147. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1148. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  1149. //
  1150. // Switch on the function control code. We grab the Fcb exclusively
  1151. // for oplock requests, shared for oplock break acknowledgement.
  1152. //
  1153. switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
  1154. case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
  1155. case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
  1156. case FSCTL_REQUEST_BATCH_OPLOCK :
  1157. case FSCTL_REQUEST_FILTER_OPLOCK :
  1158. CdAcquireFcbExclusive( IrpContext, Fcb, FALSE );
  1159. if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
  1160. if (Fcb->FileLock != NULL) {
  1161. OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock );
  1162. }
  1163. } else {
  1164. OplockCount = Fcb->FcbCleanup;
  1165. }
  1166. break;
  1167. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  1168. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  1169. case FSCTL_OPLOCK_BREAK_NOTIFY:
  1170. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  1171. CdAcquireFcbShared( IrpContext, Fcb, FALSE );
  1172. break;
  1173. default:
  1174. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1175. return STATUS_INVALID_PARAMETER;
  1176. }
  1177. //
  1178. // Use a try finally to free the Fcb.
  1179. //
  1180. try {
  1181. //
  1182. // Verify the Fcb.
  1183. //
  1184. CdVerifyFcbOperation( IrpContext, Fcb );
  1185. //
  1186. // Call the FsRtl routine to grant/acknowledge oplock.
  1187. //
  1188. Status = FsRtlOplockFsctrl( &Fcb->Oplock,
  1189. Irp,
  1190. OplockCount );
  1191. //
  1192. // Set the flag indicating if Fast I/O is possible
  1193. //
  1194. CdLockFcb( IrpContext, Fcb );
  1195. Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
  1196. CdUnlockFcb( IrpContext, Fcb );
  1197. //
  1198. // The oplock package will complete the Irp.
  1199. //
  1200. Irp = NULL;
  1201. } finally {
  1202. //
  1203. // Release all of our resources
  1204. //
  1205. CdReleaseFcb( IrpContext, Fcb );
  1206. }
  1207. //
  1208. // Complete the request if there was no exception.
  1209. //
  1210. CdCompleteRequest( IrpContext, Irp, Status );
  1211. return Status;
  1212. }
  1213. //
  1214. // Local support routine
  1215. //
  1216. NTSTATUS
  1217. CdLockVolume (
  1218. IN PIRP_CONTEXT IrpContext,
  1219. IN PIRP Irp
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This routine performs the lock volume operation. It is responsible for
  1224. either completing of enqueuing the input Irp.
  1225. Arguments:
  1226. Irp - Supplies the Irp to process
  1227. Return Value:
  1228. NTSTATUS - The return status for the operation
  1229. --*/
  1230. {
  1231. NTSTATUS Status;
  1232. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1233. PVCB Vcb;
  1234. PFCB Fcb;
  1235. PCCB Ccb;
  1236. PAGED_CODE();
  1237. //
  1238. // Decode the file object, the only type of opens we accept are
  1239. // user volume opens.
  1240. //
  1241. if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) {
  1242. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1243. return STATUS_INVALID_PARAMETER;
  1244. }
  1245. //
  1246. // Send our notification so that folks that like to hold handles on
  1247. // volumes can get out of the way.
  1248. //
  1249. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
  1250. //
  1251. // Acquire exclusive access to the Vcb.
  1252. //
  1253. Vcb = Fcb->Vcb;
  1254. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  1255. try {
  1256. //
  1257. // Verify the Vcb.
  1258. //
  1259. CdVerifyVcb( IrpContext, Vcb );
  1260. Status = CdLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
  1261. } finally {
  1262. //
  1263. // Release the Vcb.
  1264. //
  1265. CdReleaseVcb( IrpContext, Vcb );
  1266. if (AbnormalTermination() || !NT_SUCCESS( Status )) {
  1267. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
  1268. }
  1269. }
  1270. //
  1271. // Complete the request if there haven't been any exceptions.
  1272. //
  1273. CdCompleteRequest( IrpContext, Irp, Status );
  1274. return Status;
  1275. }
  1276. //
  1277. // Local support routine
  1278. //
  1279. NTSTATUS
  1280. CdUnlockVolume (
  1281. IN PIRP_CONTEXT IrpContext,
  1282. IN PIRP Irp
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. This routine performs the unlock volume operation. It is responsible for
  1287. either completing of enqueuing the input Irp.
  1288. Arguments:
  1289. Irp - Supplies the Irp to process
  1290. Return Value:
  1291. NTSTATUS - The return status for the operation
  1292. --*/
  1293. {
  1294. NTSTATUS Status;
  1295. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1296. PVCB Vcb;
  1297. PFCB Fcb;
  1298. PCCB Ccb;
  1299. PAGED_CODE();
  1300. //
  1301. // Decode the file object, the only type of opens we accept are
  1302. // user volume opens.
  1303. //
  1304. if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
  1305. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1306. return STATUS_INVALID_PARAMETER;
  1307. }
  1308. //
  1309. // Acquire exclusive access to the Vcb.
  1310. //
  1311. Vcb = Fcb->Vcb;
  1312. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  1313. //
  1314. // We won't check for a valid Vcb for this request. An unlock will always
  1315. // succeed on a locked volume.
  1316. //
  1317. Status = CdUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
  1318. //
  1319. // Release all of our resources
  1320. //
  1321. CdReleaseVcb( IrpContext, Vcb );
  1322. //
  1323. // Send notification that the volume is avaliable.
  1324. //
  1325. if (NT_SUCCESS( Status )) {
  1326. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
  1327. }
  1328. //
  1329. // Complete the request if there haven't been any exceptions.
  1330. //
  1331. CdCompleteRequest( IrpContext, Irp, Status );
  1332. return Status;
  1333. }
  1334. //
  1335. // Local support routine
  1336. //
  1337. NTSTATUS
  1338. CdDismountVolume (
  1339. IN PIRP_CONTEXT IrpContext,
  1340. IN PIRP Irp
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. This routine performs the dismount volume operation. It is responsible for
  1345. either completing of enqueuing the input Irp. We only dismount a volume which
  1346. has been locked. The intent here is that someone has locked the volume (they are the
  1347. only remaining handle). We set the verify bit here and the user will close his handle.
  1348. We will dismount a volume with no user's handles in the verify path.
  1349. Arguments:
  1350. Irp - Supplies the Irp to process
  1351. Return Value:
  1352. NTSTATUS - The return status for the operation
  1353. --*/
  1354. {
  1355. NTSTATUS Status;
  1356. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1357. PVCB Vcb;
  1358. PFCB Fcb;
  1359. PCCB Ccb;
  1360. PAGED_CODE();
  1361. if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
  1362. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1363. return STATUS_INVALID_PARAMETER;
  1364. }
  1365. //
  1366. // Acquire exclusive access to the Vcb, and take the global resource to
  1367. // sync. against mounts, verifies etc.
  1368. //
  1369. Vcb = Fcb->Vcb;
  1370. CdAcquireCdData( IrpContext );
  1371. CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  1372. //
  1373. // Mark the volume as needs to be verified, but only do it if
  1374. // the vcb is locked by this handle and the volume is currently mounted.
  1375. //
  1376. if (Vcb->VcbCondition != VcbMounted) {
  1377. Status = STATUS_VOLUME_DISMOUNTED;
  1378. } else {
  1379. //
  1380. // Invalidate the volume right now.
  1381. //
  1382. // The intent here is to make every subsequent operation
  1383. // on the volume fail and grease the rails toward dismount.
  1384. // By definition there is no going back from a SURPRISE.
  1385. //
  1386. CdLockVcb( IrpContext, Vcb );
  1387. if (Vcb->VcbCondition != VcbDismountInProgress) {
  1388. CdUpdateVcbCondition( Vcb, VcbInvalid);
  1389. }
  1390. CdUnlockVcb( IrpContext, Vcb );
  1391. //
  1392. // Set flag to tell the close path that we want to force dismount
  1393. // the volume when this handle is closed.
  1394. //
  1395. SetFlag( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE);
  1396. Status = STATUS_SUCCESS;
  1397. }
  1398. //
  1399. // Release all of our resources
  1400. //
  1401. CdReleaseVcb( IrpContext, Vcb );
  1402. CdReleaseCdData( IrpContext);
  1403. //
  1404. // Complete the request if there haven't been any exceptions.
  1405. //
  1406. CdCompleteRequest( IrpContext, Irp, Status );
  1407. return Status;
  1408. }
  1409. //
  1410. // Local support routine
  1411. //
  1412. CdIsVolumeDirty (
  1413. IN PIRP_CONTEXT IrpContext,
  1414. IN PIRP Irp
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. This routine determines if a volume is currently dirty.
  1419. Arguments:
  1420. Irp - Supplies the Irp to process
  1421. Return Value:
  1422. NTSTATUS - The return status for the operation
  1423. --*/
  1424. {
  1425. PIO_STACK_LOCATION IrpSp;
  1426. TYPE_OF_OPEN TypeOfOpen;
  1427. PFCB Fcb;
  1428. PCCB Ccb;
  1429. PULONG VolumeState;
  1430. //
  1431. // Get the current stack location and extract the output
  1432. // buffer information.
  1433. //
  1434. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1435. //
  1436. // Get a pointer to the output buffer.
  1437. //
  1438. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  1439. VolumeState = Irp->AssociatedIrp.SystemBuffer;
  1440. } else {
  1441. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  1442. return STATUS_INVALID_USER_BUFFER;
  1443. }
  1444. //
  1445. // Make sure the output buffer is large enough and then initialize
  1446. // the answer to be that the volume isn't dirty.
  1447. //
  1448. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
  1449. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1450. return STATUS_INVALID_PARAMETER;
  1451. }
  1452. *VolumeState = 0;
  1453. //
  1454. // Decode the file object
  1455. //
  1456. TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
  1457. if (TypeOfOpen != UserVolumeOpen) {
  1458. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1459. return STATUS_INVALID_PARAMETER;
  1460. }
  1461. if (Fcb->Vcb->VcbCondition != VcbMounted) {
  1462. CdCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  1463. return STATUS_VOLUME_DISMOUNTED;
  1464. }
  1465. //
  1466. // Now set up to return the clean state. CDs obviously can never be dirty
  1467. // but we want to make sure we have enforced the full semantics of this call.
  1468. //
  1469. Irp->IoStatus.Information = sizeof( ULONG );
  1470. CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  1471. return STATUS_SUCCESS;
  1472. }
  1473. //
  1474. // Local support routine
  1475. //
  1476. NTSTATUS
  1477. CdIsVolumeMounted (
  1478. IN PIRP_CONTEXT IrpContext,
  1479. IN PIRP Irp
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine determines if a volume is currently mounted.
  1484. Arguments:
  1485. Irp - Supplies the Irp to process
  1486. Return Value:
  1487. NTSTATUS - The return status for the operation
  1488. --*/
  1489. {
  1490. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1491. PFCB Fcb;
  1492. PCCB Ccb;
  1493. PAGED_CODE();
  1494. //
  1495. // Decode the file object.
  1496. //
  1497. CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
  1498. if (Fcb != NULL) {
  1499. //
  1500. // Disable PopUps, we want to return any error.
  1501. //
  1502. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS );
  1503. //
  1504. // Verify the Vcb. This will raise in the error condition.
  1505. //
  1506. CdVerifyVcb( IrpContext, Fcb->Vcb );
  1507. }
  1508. CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  1509. return STATUS_SUCCESS;
  1510. }
  1511. //
  1512. // Local support routine
  1513. //
  1514. NTSTATUS
  1515. CdIsPathnameValid (
  1516. IN PIRP_CONTEXT IrpContext,
  1517. IN PIRP Irp
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. This routine determines if pathname is a valid CDFS pathname.
  1522. We always succeed this request.
  1523. Arguments:
  1524. Irp - Supplies the Irp to process.
  1525. Return Value:
  1526. None
  1527. --*/
  1528. {
  1529. PAGED_CODE();
  1530. CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  1531. return STATUS_SUCCESS;
  1532. }
  1533. //
  1534. // Local support routine
  1535. //
  1536. NTSTATUS
  1537. CdInvalidateVolumes (
  1538. IN PIRP_CONTEXT IrpContext,
  1539. IN PIRP Irp
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This routine searches for all the volumes mounted on the same real device
  1544. of the current DASD handle, and marks them all bad. The only operation
  1545. that can be done on such handles is cleanup and close.
  1546. Arguments:
  1547. Irp - Supplies the Irp to process
  1548. Return Value:
  1549. NTSTATUS - The return status for the operation
  1550. --*/
  1551. {
  1552. NTSTATUS Status;
  1553. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1554. KIRQL SavedIrql;
  1555. LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
  1556. HANDLE Handle;
  1557. PVCB Vcb;
  1558. PLIST_ENTRY Links;
  1559. PFILE_OBJECT FileToMarkBad;
  1560. PDEVICE_OBJECT DeviceToMarkBad;
  1561. //
  1562. // Check for the correct security access.
  1563. // The caller must have the SeTcbPrivilege.
  1564. //
  1565. if (!SeSinglePrivilegeCheck( TcbPrivilege, Irp->RequestorMode )) {
  1566. CdCompleteRequest( IrpContext, Irp, STATUS_PRIVILEGE_NOT_HELD );
  1567. return STATUS_PRIVILEGE_NOT_HELD;
  1568. }
  1569. //
  1570. // Try to get a pointer to the device object from the handle passed in.
  1571. //
  1572. #if defined(_WIN64)
  1573. if (IoIs32bitProcess( Irp )) {
  1574. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( UINT32 )) {
  1575. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1576. return STATUS_INVALID_PARAMETER;
  1577. }
  1578. Handle = (HANDLE) LongToHandle( *((PUINT32) Irp->AssociatedIrp.SystemBuffer) );
  1579. } else {
  1580. #endif
  1581. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) {
  1582. CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1583. return STATUS_INVALID_PARAMETER;
  1584. }
  1585. Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer);
  1586. #if defined(_WIN64)
  1587. }
  1588. #endif
  1589. Status = ObReferenceObjectByHandle( Handle,
  1590. 0,
  1591. *IoFileObjectType,
  1592. KernelMode,
  1593. &FileToMarkBad,
  1594. NULL );
  1595. if (!NT_SUCCESS(Status)) {
  1596. CdCompleteRequest( IrpContext, Irp, Status );
  1597. return Status;
  1598. }
  1599. //
  1600. // Grab the DeviceObject from the FileObject.
  1601. //
  1602. DeviceToMarkBad = FileToMarkBad->DeviceObject;
  1603. //
  1604. // We only needed the device object involved, not a reference to the file.
  1605. //
  1606. ObDereferenceObject( FileToMarkBad );
  1607. //
  1608. // Make sure this request can wait.
  1609. //
  1610. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1611. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  1612. //
  1613. // Synchronise with pnp/mount/verify paths.
  1614. //
  1615. CdAcquireCdData( IrpContext );
  1616. //
  1617. // Nothing can go wrong now.
  1618. //
  1619. //
  1620. // Now walk through all the mounted Vcb's looking for candidates to
  1621. // mark invalid.
  1622. //
  1623. // On volumes we mark invalid, check for dismount possibility (which is
  1624. // why we have to get the next link so early).
  1625. //
  1626. Links = CdData.VcbQueue.Flink;
  1627. while (Links != &CdData.VcbQueue) {
  1628. Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks);
  1629. Links = Links->Flink;
  1630. //
  1631. // If we get a match, mark the volume Bad, and also check to
  1632. // see if the volume should go away.
  1633. //
  1634. CdLockVcb( IrpContext, Vcb );
  1635. if (Vcb->Vpb->RealDevice == DeviceToMarkBad) {
  1636. //
  1637. // Take the VPB spinlock, and look to see if this volume is the
  1638. // one currently mounted on the actual device. If it is, pull it
  1639. // off immediately.
  1640. //
  1641. IoAcquireVpbSpinLock( &SavedIrql );
  1642. if (DeviceToMarkBad->Vpb == Vcb->Vpb) {
  1643. PVPB NewVpb = Vcb->SwapVpb;
  1644. ASSERT( FlagOn( Vcb->Vpb->Flags, VPB_MOUNTED));
  1645. ASSERT( NULL != NewVpb);
  1646. RtlZeroMemory( NewVpb, sizeof( VPB ) );
  1647. NewVpb->Type = IO_TYPE_VPB;
  1648. NewVpb->Size = sizeof( VPB );
  1649. NewVpb->RealDevice = DeviceToMarkBad;
  1650. NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
  1651. DeviceToMarkBad->Vpb = NewVpb;
  1652. Vcb->SwapVpb = NULL;
  1653. }
  1654. IoReleaseVpbSpinLock( SavedIrql );
  1655. if (Vcb->VcbCondition != VcbDismountInProgress) {
  1656. CdUpdateVcbCondition( Vcb, VcbInvalid);
  1657. }
  1658. CdUnlockVcb( IrpContext, Vcb );
  1659. CdPurgeVolume( IrpContext, Vcb, FALSE );
  1660. CdCheckForDismount( IrpContext, Vcb, FALSE );
  1661. } else {
  1662. CdUnlockVcb( IrpContext, Vcb );
  1663. }
  1664. }
  1665. CdReleaseCdData( IrpContext );
  1666. CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  1667. return STATUS_SUCCESS;
  1668. }
  1669. //
  1670. // Local support routine
  1671. //
  1672. VOID
  1673. CdScanForDismountedVcb (
  1674. IN PIRP_CONTEXT IrpContext
  1675. )
  1676. /*++
  1677. Routine Description:
  1678. This routine walks through the list of Vcb's looking for any which may
  1679. now be deleted. They may have been left on the list because there were
  1680. outstanding references.
  1681. Arguments:
  1682. Return Value:
  1683. None
  1684. --*/
  1685. {
  1686. PVCB Vcb;
  1687. PLIST_ENTRY Links;
  1688. PAGED_CODE();
  1689. //
  1690. // Walk through all of the Vcb's attached to the global data.
  1691. //
  1692. Links = CdData.VcbQueue.Flink;
  1693. while (Links != &CdData.VcbQueue) {
  1694. Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
  1695. //
  1696. // Move to the next link now since the current Vcb may be deleted.
  1697. //
  1698. Links = Links->Flink;
  1699. //
  1700. // If dismount is already underway then check if this Vcb can
  1701. // go away.
  1702. //
  1703. if ((Vcb->VcbCondition == VcbDismountInProgress) ||
  1704. (Vcb->VcbCondition == VcbInvalid) ||
  1705. ((Vcb->VcbCondition == VcbNotMounted) && (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE))) {
  1706. CdCheckForDismount( IrpContext, Vcb, FALSE );
  1707. }
  1708. }
  1709. return;
  1710. }
  1711. //
  1712. // Local support routine
  1713. //
  1714. BOOLEAN
  1715. CdFindPrimaryVd (
  1716. IN PIRP_CONTEXT IrpContext,
  1717. IN PVCB Vcb,
  1718. IN PCHAR RawIsoVd,
  1719. IN ULONG BlockFactor,
  1720. IN BOOLEAN ReturnOnError,
  1721. IN BOOLEAN VerifyVolume
  1722. )
  1723. /*++
  1724. Routine Description:
  1725. This routine is called to walk through the volume descriptors looking
  1726. for a primary volume descriptor. When/if a primary is found a 32-bit
  1727. serial number is generated and stored into the Vpb. We also store the
  1728. location of the primary volume descriptor in the Vcb.
  1729. Arguments:
  1730. Vcb - Pointer to the VCB for the volume.
  1731. RawIsoVd - Pointer to a sector buffer which will contain the primary
  1732. volume descriptor on exit, if successful.
  1733. BlockFactor - Block factor used by the current device for the TableOfContents.
  1734. ReturnOnError - Indicates that we should raise on I/O errors rather than
  1735. returning a FALSE value.
  1736. VerifyVolume - Indicates if we were called from the verify path. We
  1737. do a few things different in this path. We don't update the Vcb in
  1738. the verify path.
  1739. Return Value:
  1740. BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
  1741. otherwise.
  1742. --*/
  1743. {
  1744. NTSTATUS Status;
  1745. ULONG ThisPass = 1;
  1746. BOOLEAN FoundVd = FALSE;
  1747. ULONG BaseSector;
  1748. ULONG SectorOffset;
  1749. PCDROM_TOC CdromToc;
  1750. ULONG VolumeFlags;
  1751. PAGED_CODE();
  1752. //
  1753. // If there are no data tracks, don't even bother hunting for descriptors.
  1754. //
  1755. // This explicitly breaks various non-BlueBook compliant CDs that scribble
  1756. // an ISO filesystem on media claiming only audio tracks. Since these
  1757. // disks can cause serious problems in some CDROM units, fail fast. I admit
  1758. // that it is possible that someone can still record the descriptors in the
  1759. // audio track, record a data track (but fail to record descriptors there)
  1760. // and still have the disk work. As this form of error worked in NT 4.0, and
  1761. // since these disks really do exist, I don't want to change them.
  1762. //
  1763. // If we wished to support all such media (we don't), it would be neccesary
  1764. // to clear this flag on finding ISO or HSG descriptors below.
  1765. //
  1766. if (FlagOn(Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
  1767. return FALSE;
  1768. }
  1769. //
  1770. // We will make at most two passes through the volume descriptor sequence.
  1771. //
  1772. // On the first pass we will query for the last session. Using this
  1773. // as a starting offset we will attempt to mount the volume. On any failure
  1774. // we will go to the second pass and try without using any multi-session
  1775. // information.
  1776. //
  1777. // On the second pass we will start offset from sector zero.
  1778. //
  1779. while (!FoundVd && (ThisPass <= 2)) {
  1780. //
  1781. // If we aren't at pass 1 then we start at sector 0. Otherwise we
  1782. // try to look up the multi-session information.
  1783. //
  1784. BaseSector = 0;
  1785. if (ThisPass == 1) {
  1786. CdromToc = NULL;
  1787. //
  1788. // Check for whether this device supports XA and multi-session.
  1789. //
  1790. try {
  1791. //
  1792. // Allocate a buffer for the last session information.
  1793. //
  1794. CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
  1795. sizeof( CDROM_TOC ),
  1796. TAG_CDROM_TOC );
  1797. RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
  1798. //
  1799. // Query the last session information from the driver.
  1800. //
  1801. Status = CdPerformDevIoCtrl( IrpContext,
  1802. IOCTL_CDROM_GET_LAST_SESSION,
  1803. Vcb->TargetDeviceObject,
  1804. CdromToc,
  1805. sizeof( CDROM_TOC ),
  1806. FALSE,
  1807. TRUE,
  1808. NULL );
  1809. //
  1810. // Raise an exception if there was an allocation failure.
  1811. //
  1812. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  1813. CdRaiseStatus( IrpContext, Status );
  1814. }
  1815. //
  1816. // We don't handle any errors yet. We will hit that below
  1817. // as we try to scan the disk. If we have last session information
  1818. // then modify the base sector.
  1819. //
  1820. if (NT_SUCCESS( Status ) &&
  1821. (CdromToc->FirstTrack != CdromToc->LastTrack)) {
  1822. PCHAR Source, Dest;
  1823. ULONG Count;
  1824. Count = 4;
  1825. //
  1826. // The track address is BigEndian, we need to flip the bytes.
  1827. //
  1828. Source = (PUCHAR) &CdromToc->TrackData[0].Address[3];
  1829. Dest = (PUCHAR) &BaseSector;
  1830. do {
  1831. *Dest++ = *Source--;
  1832. } while (--Count);
  1833. //
  1834. // Now adjust the base sector by the block factor of the
  1835. // device.
  1836. //
  1837. BaseSector /= BlockFactor;
  1838. //
  1839. // Make this look like the second pass since we are only using the
  1840. // first session. No reason to retry on error.
  1841. //
  1842. } else {
  1843. ThisPass += 1;
  1844. }
  1845. } finally {
  1846. if (CdromToc != NULL) { ExFreePool( CdromToc ); }
  1847. }
  1848. }
  1849. //
  1850. // Compute the starting sector offset from the start of the session.
  1851. //
  1852. SectorOffset = FIRST_VD_SECTOR;
  1853. //
  1854. // Start by assuming we have neither Hsg or Iso volumes.
  1855. //
  1856. VolumeFlags = 0;
  1857. //
  1858. // Loop until either error encountered, primary volume descriptor is
  1859. // found or a terminal volume descriptor is found.
  1860. //
  1861. while (TRUE) {
  1862. //
  1863. // Attempt to read the desired sector. Exit directly if operation
  1864. // not completed.
  1865. //
  1866. // If this is pass 1 we will ignore errors in read sectors and just
  1867. // go to the next pass.
  1868. //
  1869. if (!CdReadSectors( IrpContext,
  1870. LlBytesFromSectors( BaseSector + SectorOffset ),
  1871. SECTOR_SIZE,
  1872. (BOOLEAN) ((ThisPass == 1) || ReturnOnError),
  1873. RawIsoVd,
  1874. Vcb->TargetDeviceObject )) {
  1875. break;
  1876. }
  1877. //
  1878. // Check if either an ISO or HSG volume.
  1879. //
  1880. if (RtlEqualMemory( CdIsoId,
  1881. CdRvdId( RawIsoVd, VCB_STATE_ISO ),
  1882. VOL_ID_LEN )) {
  1883. SetFlag( VolumeFlags, VCB_STATE_ISO );
  1884. } else if (RtlEqualMemory( CdHsgId,
  1885. CdRvdId( RawIsoVd, VCB_STATE_HSG ),
  1886. VOL_ID_LEN )) {
  1887. SetFlag( VolumeFlags, VCB_STATE_HSG );
  1888. //
  1889. // We have neither so break out of the loop.
  1890. //
  1891. } else {
  1892. break;
  1893. }
  1894. //
  1895. // Break out if the version number is incorrect or this is
  1896. // a terminator.
  1897. //
  1898. if ((CdRvdVersion( RawIsoVd, VolumeFlags ) != VERSION_1) ||
  1899. (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_TERMINATOR)) {
  1900. break;
  1901. }
  1902. //
  1903. // If this is a primary volume descriptor then our search is over.
  1904. //
  1905. if (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_PRIMARY) {
  1906. //
  1907. // If we are not in the verify path then initialize the
  1908. // fields in the Vcb with basic information from this
  1909. // descriptor.
  1910. //
  1911. if (!VerifyVolume) {
  1912. //
  1913. // Set the flag for the volume type.
  1914. //
  1915. SetFlag( Vcb->VcbState, VolumeFlags );
  1916. //
  1917. // Store the base sector and sector offset for the
  1918. // primary volume descriptor.
  1919. //
  1920. Vcb->BaseSector = BaseSector;
  1921. Vcb->VdSectorOffset = SectorOffset;
  1922. Vcb->PrimaryVdSectorOffset = SectorOffset;
  1923. }
  1924. FoundVd = TRUE;
  1925. break;
  1926. }
  1927. //
  1928. // Indicate that we're at the next sector.
  1929. //
  1930. SectorOffset += 1;
  1931. }
  1932. ThisPass += 1;
  1933. }
  1934. return FoundVd;
  1935. }
  1936. //
  1937. // Local support routine
  1938. //
  1939. BOOLEAN
  1940. CdIsRemount (
  1941. IN PIRP_CONTEXT IrpContext,
  1942. IN PVCB Vcb,
  1943. OUT PVCB *OldVcb
  1944. )
  1945. /*++
  1946. Routine Description:
  1947. This routine walks through the links of the Vcb chain in the global
  1948. data structure. The remount condition is met when the following
  1949. conditions are all met:
  1950. If the new Vcb is a device only Mvcb and there is a previous
  1951. device only Mvcb.
  1952. Otherwise following conditions must be matched.
  1953. 1 - The 32 serial in the current VPB matches that in a previous
  1954. VPB.
  1955. 2 - The volume label in the Vpb matches that in the previous
  1956. Vpb.
  1957. 3 - The system pointer to the real device object in the current
  1958. VPB matches that in the same previous VPB.
  1959. 4 - Finally the previous Vcb cannot be invalid or have a dismount
  1960. underway.
  1961. If a VPB is found which matches these conditions, then the address of
  1962. the VCB for that VPB is returned via the pointer Vcb.
  1963. Skip over the current Vcb.
  1964. Arguments:
  1965. Vcb - This is the Vcb we are checking for a remount.
  1966. OldVcb - A pointer to the address to store the address for the Vcb
  1967. for the volume if this is a remount. (This is a pointer to
  1968. a pointer)
  1969. Return Value:
  1970. BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
  1971. --*/
  1972. {
  1973. PLIST_ENTRY Link;
  1974. PVPB Vpb = Vcb->Vpb;
  1975. PVPB OldVpb;
  1976. BOOLEAN Remount = FALSE;
  1977. PAGED_CODE();
  1978. //
  1979. // Check whether we are looking for a device only Mvcb.
  1980. //
  1981. for (Link = CdData.VcbQueue.Flink;
  1982. Link != &CdData.VcbQueue;
  1983. Link = Link->Flink) {
  1984. *OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks );
  1985. //
  1986. // Skip ourselves.
  1987. //
  1988. if (Vcb == *OldVcb) { continue; }
  1989. //
  1990. // Look at the Vpb and state of the previous Vcb.
  1991. //
  1992. OldVpb = (*OldVcb)->Vpb;
  1993. if ((OldVpb != Vpb) &&
  1994. (OldVpb->RealDevice == Vpb->RealDevice) &&
  1995. ((*OldVcb)->VcbCondition == VcbNotMounted)) {
  1996. //
  1997. // If the current disk is a raw disk then it can match a previous music or
  1998. // raw disk.
  1999. //
  2000. if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
  2001. if (FlagOn( (*OldVcb)->VcbState, VCB_STATE_AUDIO_DISK )) {
  2002. //
  2003. // If we have both TOC then fail the remount if the lengths
  2004. // are different or they don't match.
  2005. //
  2006. if ((Vcb->TocLength != (*OldVcb)->TocLength) ||
  2007. ((Vcb->TocLength != 0) &&
  2008. !RtlEqualMemory( Vcb->CdromToc,
  2009. (*OldVcb)->CdromToc,
  2010. Vcb->TocLength ))) {
  2011. continue;
  2012. }
  2013. Remount = TRUE;
  2014. break;
  2015. }
  2016. //
  2017. // The current disk is not a raw disk. Go ahead and compare
  2018. // serial numbers and volume label.
  2019. //
  2020. } else if ((OldVpb->SerialNumber == Vpb->SerialNumber) &&
  2021. (Vpb->VolumeLabelLength == OldVpb->VolumeLabelLength) &&
  2022. (RtlEqualMemory( OldVpb->VolumeLabel,
  2023. Vpb->VolumeLabel,
  2024. Vpb->VolumeLabelLength ))) {
  2025. //
  2026. // Remember the old mvcb. Then set the return value to
  2027. // TRUE and break.
  2028. //
  2029. Remount = TRUE;
  2030. break;
  2031. }
  2032. }
  2033. }
  2034. return Remount;
  2035. }
  2036. //
  2037. // Local support routine
  2038. //
  2039. VOID
  2040. CdFindActiveVolDescriptor (
  2041. IN PIRP_CONTEXT IrpContext,
  2042. IN PVCB Vcb,
  2043. IN OUT PCHAR RawIsoVd,
  2044. IN BOOLEAN VerifyVolume
  2045. )
  2046. /*++
  2047. Routine Description:
  2048. This routine is called to search for a valid secondary volume descriptor that
  2049. we will support. Right now we only support Joliet escape sequences for
  2050. the secondary descriptor.
  2051. If we don't find the secondary descriptor then we will reread the primary.
  2052. This routine will update the serial number and volume label in the Vpb.
  2053. Arguments:
  2054. Vcb - This is the Vcb for the volume being mounted.
  2055. RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
  2056. on input should contain the PVD (ISO) in the SECOND 'sector' of the
  2057. buffer.
  2058. VerifyVolume - indicates we are being called by the verify path, and should
  2059. not modify the Vcb fields.
  2060. Return Value:
  2061. None
  2062. --*/
  2063. {
  2064. BOOLEAN FoundSecondaryVd = FALSE;
  2065. ULONG SectorOffset = FIRST_VD_SECTOR;
  2066. ULONG Length;
  2067. ULONG Index;
  2068. PAGED_CODE();
  2069. //
  2070. // We only look for secondary volume descriptors on an Iso disk.
  2071. //
  2072. if ((FlagOn( Vcb->VcbState, VCB_STATE_ISO) || VerifyVolume)) {
  2073. //
  2074. // Scan the volume descriptors from the beginning looking for a valid
  2075. // secondary or a terminator.
  2076. //
  2077. SectorOffset = FIRST_VD_SECTOR;
  2078. while (TRUE) {
  2079. //
  2080. // Read the next sector. We should never have an error in this
  2081. // path.
  2082. //
  2083. CdReadSectors( IrpContext,
  2084. LlBytesFromSectors( Vcb->BaseSector + SectorOffset ),
  2085. SECTOR_SIZE,
  2086. FALSE,
  2087. RawIsoVd,
  2088. Vcb->TargetDeviceObject );
  2089. //
  2090. // Break out if the version number or standard Id is incorrect.
  2091. // Also break out if this is a terminator.
  2092. //
  2093. if (!RtlEqualMemory( CdIsoId, CdRvdId( RawIsoVd, VCB_STATE_JOLIET ), VOL_ID_LEN ) ||
  2094. (CdRvdVersion( RawIsoVd, VCB_STATE_JOLIET ) != VERSION_1) ||
  2095. (CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_TERMINATOR)) {
  2096. break;
  2097. }
  2098. //
  2099. // We have a match if this is a secondary descriptor with a matching
  2100. // escape sequence.
  2101. //
  2102. if ((CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_SECONDARY) &&
  2103. (RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
  2104. CdJolietEscape[0],
  2105. ESC_SEQ_LEN ) ||
  2106. RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
  2107. CdJolietEscape[1],
  2108. ESC_SEQ_LEN ) ||
  2109. RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
  2110. CdJolietEscape[2],
  2111. ESC_SEQ_LEN ))) {
  2112. if (!VerifyVolume) {
  2113. //
  2114. // Update the Vcb with the new volume descriptor.
  2115. //
  2116. ClearFlag( Vcb->VcbState, VCB_STATE_ISO );
  2117. SetFlag( Vcb->VcbState, VCB_STATE_JOLIET );
  2118. Vcb->VdSectorOffset = SectorOffset;
  2119. }
  2120. FoundSecondaryVd = TRUE;
  2121. break;
  2122. }
  2123. //
  2124. // Otherwise move on to the next sector.
  2125. //
  2126. SectorOffset += 1;
  2127. }
  2128. //
  2129. // If we didn't find the secondary then recover the original volume
  2130. // descriptor stored in the second half of the RawIsoVd.
  2131. //
  2132. if (!FoundSecondaryVd) {
  2133. RtlCopyMemory( RawIsoVd,
  2134. Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
  2135. SECTOR_SIZE );
  2136. }
  2137. }
  2138. //
  2139. // If we're in the verify path, our work is done, since we don't want
  2140. // to update any Vcb/Vpb values.
  2141. //
  2142. if (VerifyVolume) {
  2143. return;
  2144. }
  2145. //
  2146. // Compute the serial number and volume label from the volume descriptor.
  2147. //
  2148. Vcb->Vpb->SerialNumber = CdSerial32( RawIsoVd, SECTOR_SIZE );
  2149. //
  2150. // Make sure the CD label will fit in the Vpb.
  2151. //
  2152. ASSERT( VOLUME_ID_LENGTH * sizeof( WCHAR ) <= MAXIMUM_VOLUME_LABEL_LENGTH );
  2153. //
  2154. // If this is not a Unicode label we must convert it to unicode.
  2155. //
  2156. if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
  2157. //
  2158. // Convert the label to unicode. If we get any error then use a name
  2159. // length of zero.
  2160. //
  2161. Vcb->Vpb->VolumeLabelLength = 0;
  2162. if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb->Vpb->VolumeLabel[0],
  2163. MAXIMUM_VOLUME_LABEL_LENGTH,
  2164. &Length,
  2165. CdRvdVolId( RawIsoVd, Vcb->VcbState ),
  2166. VOLUME_ID_LENGTH ))) {
  2167. Vcb->Vpb->VolumeLabelLength = (USHORT) Length;
  2168. }
  2169. //
  2170. // We need to convert from big-endian to little endian.
  2171. //
  2172. } else {
  2173. CdConvertBigToLittleEndian( IrpContext,
  2174. CdRvdVolId( RawIsoVd, Vcb->VcbState ),
  2175. VOLUME_ID_LENGTH,
  2176. (PCHAR) Vcb->Vpb->VolumeLabel );
  2177. Vcb->Vpb->VolumeLabelLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
  2178. }
  2179. //
  2180. // Strip the trailing spaces or zeroes from the name.
  2181. //
  2182. Index = Vcb->Vpb->VolumeLabelLength / sizeof( WCHAR );
  2183. while (Index > 0) {
  2184. if ((Vcb->Vpb->VolumeLabel[ Index - 1 ] != L'\0') &&
  2185. (Vcb->Vpb->VolumeLabel[ Index - 1 ] != L' ')) {
  2186. break;
  2187. }
  2188. Index -= 1;
  2189. }
  2190. //
  2191. // Now set the final length for the name.
  2192. //
  2193. Vcb->Vpb->VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
  2194. }