Leaked source code of windows server 2003
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.

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