3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File System Control routines for Cdfs called
12 by the Fsd/Fsp dispatch drivers.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_FSCTRL)
29 BOOLEAN CdDisable
= FALSE
;
30 BOOLEAN CdNoJoliet
= FALSE
;
33 // Local support routines
38 IN PIRP_CONTEXT IrpContext
,
44 IN PIRP_CONTEXT IrpContext
,
47 IN PDEVICE_OBJECT DeviceObjectWeTalkTo
52 IN PIRP_CONTEXT IrpContext
,
58 IN PIRP_CONTEXT IrpContext
,
64 IN PIRP_CONTEXT IrpContext
,
70 IN PIRP_CONTEXT IrpContext
,
76 IN PIRP_CONTEXT IrpContext
,
82 IN PIRP_CONTEXT IrpContext
,
86 NTSTATUS
/* ReactOS Change: Function did not have a type??? */
88 IN PIRP_CONTEXT IrpContext
,
94 IN PIRP_CONTEXT IrpContext
,
100 IN PIRP_CONTEXT IrpContext
,
105 CdInvalidateVolumes (
106 IN PIRP_CONTEXT IrpContext
,
111 CdScanForDismountedVcb (
112 IN PIRP_CONTEXT IrpContext
117 IN PIRP_CONTEXT IrpContext
,
120 IN ULONG BlockFactor
,
121 IN BOOLEAN ReturnOnError
,
122 IN BOOLEAN VerifyVolume
127 IN PIRP_CONTEXT IrpContext
,
133 CdFindActiveVolDescriptor (
134 IN PIRP_CONTEXT IrpContext
,
136 IN OUT PCHAR RawIsoVd
,
137 IN BOOLEAN VerifyVolume
141 #pragma alloc_text(PAGE, CdCommonFsControl)
142 #pragma alloc_text(PAGE, CdDismountVolume)
143 #pragma alloc_text(PAGE, CdFindActiveVolDescriptor)
144 #pragma alloc_text(PAGE, CdFindPrimaryVd)
145 #pragma alloc_text(PAGE, CdIsPathnameValid)
146 #pragma alloc_text(PAGE, CdIsRemount)
147 #pragma alloc_text(PAGE, CdIsVolumeDirty)
148 #pragma alloc_text(PAGE, CdIsVolumeMounted)
149 #pragma alloc_text(PAGE, CdLockVolume)
150 #pragma alloc_text(PAGE, CdMountVolume)
151 #pragma alloc_text(PAGE, CdOplockRequest)
152 #pragma alloc_text(PAGE, CdScanForDismountedVcb)
153 #pragma alloc_text(PAGE, CdUnlockVolume)
154 #pragma alloc_text(PAGE, CdUserFsctl)
155 #pragma alloc_text(PAGE, CdVerifyVolume)
160 // Local support routine
164 CdLockVolumeInternal (
165 IN PIRP_CONTEXT IrpContext
,
167 IN PFILE_OBJECT FileObject OPTIONAL
174 This routine performs the actual lock volume operation. It will be called
175 by anyone wishing to try to protect the volume for a long duration. PNP
176 operations are such a user.
178 The volume must be held exclusive by the caller.
182 Vcb - The volume being locked.
184 FileObject - File corresponding to the handle locking the volume. If this
185 is not specified, a system lock is assumed.
189 NTSTATUS - The return status for the operation
196 NTSTATUS FinalStatus
= (FileObject
? STATUS_ACCESS_DENIED
: STATUS_DEVICE_BUSY
);
197 ULONG RemainingUserReferences
= (FileObject
? 1: 0);
200 // The cleanup count for the volume only reflects the fileobject that
201 // will lock the volume. Otherwise, we must fail the request.
203 // Since the only cleanup is for the provided fileobject, we will try
204 // to get rid of all of the other user references. If there is only one
205 // remaining after the purge then we can allow the volume to be locked.
208 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
211 // Now back out of our synchronization and wait for the lazy writer
212 // to finish off any lazy closes that could have been outstanding.
214 // Since we purged, we know that the lazy writer will issue all
215 // possible lazy closes in the next tick - if we hadn't, an otherwise
216 // unopened file with a large amount of dirty data could have hung
217 // around for a while as the data trickled out to the disk.
219 // This is even more important now since we send notification to
220 // alert other folks that this style of check is about to happen so
221 // that they can close their handles. We don't want to enter a fast
222 // race with the lazy writer tearing down his references to the file.
225 CdReleaseVcb( IrpContext
, Vcb
);
227 Status
= CcWaitForCurrentLazyWriterActivity();
230 // This is intentional. If we were able to get the Vcb before, just
231 // wait for it and take advantage of knowing that it is OK to leave
235 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
236 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
238 if (!NT_SUCCESS( Status
)) {
246 // If the volume is already explicitly locked then fail. We use the
247 // Vpb locked flag as an 'explicit lock' flag in the same way as Fat.
250 IoAcquireVpbSpinLock( &SavedIrql
);
252 if (!FlagOn( Vcb
->Vpb
->Flags
, VPB_LOCKED
) &&
253 (Vcb
->VcbCleanup
== RemainingUserReferences
) &&
254 (Vcb
->VcbUserReference
== CDFS_RESIDUAL_USER_REFERENCE
+ RemainingUserReferences
)) {
256 SetFlag( Vcb
->VcbState
, VCB_STATE_LOCKED
);
257 SetFlag( Vcb
->Vpb
->Flags
, VPB_LOCKED
);
258 Vcb
->VolumeLockFileObject
= FileObject
;
259 FinalStatus
= STATUS_SUCCESS
;
262 IoReleaseVpbSpinLock( SavedIrql
);
269 CdUnlockVolumeInternal (
270 IN PIRP_CONTEXT IrpContext
,
272 IN PFILE_OBJECT FileObject OPTIONAL
279 This routine performs the actual unlock volume operation.
281 The volume must be held exclusive by the caller.
285 Vcb - The volume being locked.
287 FileObject - File corresponding to the handle locking the volume. If this
288 is not specified, a system lock is assumed.
292 NTSTATUS - The return status for the operation
294 Attempting to remove a system lock that did not exist is OK.
299 NTSTATUS Status
= STATUS_NOT_LOCKED
;
303 // Note that we check the VPB_LOCKED flag here rather than the Vcb
304 // lock flag. The Vpb flag is only set for an explicit lock request, not
305 // for the implicit lock obtained on a volume open with zero share mode.
308 IoAcquireVpbSpinLock( &SavedIrql
);
310 if (FlagOn(Vcb
->Vpb
->Flags
, VPB_LOCKED
) &&
311 (FileObject
== Vcb
->VolumeLockFileObject
)) {
313 ClearFlag( Vcb
->VcbState
, VCB_STATE_LOCKED
);
314 ClearFlag( Vcb
->Vpb
->Flags
, VPB_LOCKED
);
315 Vcb
->VolumeLockFileObject
= NULL
;
316 Status
= STATUS_SUCCESS
;
319 IoReleaseVpbSpinLock( SavedIrql
);
327 IN PIRP_CONTEXT IrpContext
,
335 This is the common routine for doing FileSystem control operations called
336 by both the fsd and fsp threads
340 Irp - Supplies the Irp to process
344 NTSTATUS - The return status for the operation
350 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
353 // Get a pointer to the current Irp stack location
356 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
361 // We know this is a file system control so we'll case on the
362 // minor function, and call a internal worker routine to complete
366 switch (IrpSp
->MinorFunction
) {
368 case IRP_MN_USER_FS_REQUEST
:
370 Status
= CdUserFsctl( IrpContext
, Irp
);
373 case IRP_MN_MOUNT_VOLUME
:
375 Status
= CdMountVolume( IrpContext
, Irp
);
378 case IRP_MN_VERIFY_VOLUME
:
380 Status
= CdVerifyVolume( IrpContext
, Irp
);
385 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
386 Status
= STATUS_INVALID_DEVICE_REQUEST
;
395 // Local support routine
400 IN PIRP_CONTEXT IrpContext
,
407 This is the common routine for implementing the user's requests made
408 through NtFsControlFile.
412 Irp - Supplies the Irp being processed
416 NTSTATUS - The return status for the operation
422 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
427 // Case on the control code.
430 switch ( IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
432 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
433 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
434 case FSCTL_REQUEST_BATCH_OPLOCK
:
435 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
436 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
437 case FSCTL_OPLOCK_BREAK_NOTIFY
:
438 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
439 case FSCTL_REQUEST_FILTER_OPLOCK
:
441 Status
= CdOplockRequest( IrpContext
, Irp
);
444 case FSCTL_LOCK_VOLUME
:
446 Status
= CdLockVolume( IrpContext
, Irp
);
449 case FSCTL_UNLOCK_VOLUME
:
451 Status
= CdUnlockVolume( IrpContext
, Irp
);
454 case FSCTL_DISMOUNT_VOLUME
:
456 Status
= CdDismountVolume( IrpContext
, Irp
);
459 case FSCTL_IS_VOLUME_DIRTY
:
461 Status
= CdIsVolumeDirty( IrpContext
, Irp
);
464 case FSCTL_IS_VOLUME_MOUNTED
:
466 Status
= CdIsVolumeMounted( IrpContext
, Irp
);
469 case FSCTL_IS_PATHNAME_VALID
:
471 Status
= CdIsPathnameValid( IrpContext
, Irp
);
474 case FSCTL_INVALIDATE_VOLUMES
:
476 Status
= CdInvalidateVolumes( IrpContext
, Irp
);
481 // We don't support any of the known or unknown requests.
486 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
487 Status
= STATUS_INVALID_DEVICE_REQUEST
;
497 IN PIRP_CONTEXT IrpContext
,
500 IN PDEVICE_OBJECT DeviceObjectWeTalkTo
505 ObDereferenceObject( OldVcb
->TargetDeviceObject
);
507 IoAcquireVpbSpinLock( &SavedIrql
);
509 NewVcb
->Vpb
->RealDevice
->Vpb
= OldVcb
->Vpb
;
511 OldVcb
->Vpb
->RealDevice
= NewVcb
->Vpb
->RealDevice
;
512 OldVcb
->TargetDeviceObject
= DeviceObjectWeTalkTo
;
514 CdUpdateVcbCondition( OldVcb
, VcbMounted
);
515 CdUpdateMediaChangeCount( OldVcb
, NewVcb
->MediaChangeCount
);
517 ClearFlag( OldVcb
->VcbState
, VCB_STATE_VPB_NOT_ON_DEVICE
);
519 IoReleaseVpbSpinLock( SavedIrql
);
524 // Local support routine
529 IN PIRP_CONTEXT IrpContext
,
537 This routine performs the mount volume operation. It is responsible for
538 either completing of enqueuing the input Irp.
540 Its job is to verify that the volume denoted in the IRP is a Cdrom volume,
541 and create the VCB and root DCB structures. The algorithm it
542 uses is essentially as follows:
544 1. Create a new Vcb Structure, and initialize it enough to do I/O
545 through the on-disk volume descriptors.
547 2. Read the disk and check if it is a Cdrom volume.
549 3. If it is not a Cdrom volume then delete the Vcb and
550 complete the IRP back with an appropriate status.
552 4. Check if the volume was previously mounted and if it was then do a
553 remount operation. This involves deleting the VCB, hook in the
554 old VCB, and complete the IRP.
556 5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
560 Irp - Supplies the Irp to process
564 NTSTATUS - The return status for the operation
571 PVOLUME_DEVICE_OBJECT VolDo
= NULL
;
575 BOOLEAN FoundPvd
= FALSE
;
576 BOOLEAN SetDoVerifyOnFail
;
578 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
579 PDEVICE_OBJECT DeviceObjectWeTalkTo
= IrpSp
->Parameters
.MountVolume
.DeviceObject
;
580 PVPB Vpb
= IrpSp
->Parameters
.MountVolume
.Vpb
;
582 PFILE_OBJECT FileObjectToNotify
= NULL
;
585 DISK_GEOMETRY DiskGeometry
;
587 IO_SCSI_CAPABILITIES Capabilities
;
589 IO_STATUS_BLOCK Iosb
;
591 PCHAR RawIsoVd
= NULL
;
593 PCDROM_TOC CdromToc
= NULL
;
595 ULONG TocTrackCount
= 0;
596 ULONG TocDiskFlags
= 0;
597 ULONG MediaChangeCount
= 0;
602 // Check that we are talking to a Cdrom device. This request should
603 // always be waitable.
606 ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
607 ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
610 // Update the real device in the IrpContext from the Vpb. There was no available
611 // file object when the IrpContext was created.
614 IrpContext
->RealDevice
= Vpb
->RealDevice
;
616 SetDoVerifyOnFail
= CdRealDevNeedsVerify( IrpContext
->RealDevice
);
619 // Check if we have disabled the mount process.
624 CdCompleteRequest( IrpContext
, Irp
, STATUS_UNRECOGNIZED_VOLUME
);
625 return STATUS_UNRECOGNIZED_VOLUME
;
629 // Do a CheckVerify here to lift the MediaChange ticker from the driver
632 Status
= CdPerformDevIoCtrl( IrpContext
,
633 IOCTL_CDROM_CHECK_VERIFY
,
634 DeviceObjectWeTalkTo
,
641 if (!NT_SUCCESS( Status
)) {
643 CdCompleteRequest( IrpContext
, Irp
, Status
);
647 if (Iosb
.Information
!= sizeof(ULONG
)) {
650 // Be safe about the count in case the driver didn't fill it in
653 MediaChangeCount
= 0;
657 // Now let's make Jeff delirious and call to get the disk geometry. This
658 // will fix the case where the first change line is swallowed.
661 Status
= CdPerformDevIoCtrl( IrpContext
,
662 IOCTL_CDROM_GET_DRIVE_GEOMETRY
,
663 DeviceObjectWeTalkTo
,
665 sizeof( DISK_GEOMETRY
),
671 // Return insufficient sources to our caller.
674 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
676 CdCompleteRequest( IrpContext
, Irp
, Status
);
681 // Now check the block factor for addressing the volume descriptors.
682 // If the call for the disk geometry failed then assume there is one
688 if (NT_SUCCESS( Status
) &&
689 (DiskGeometry
.BytesPerSector
!= 0) &&
690 (DiskGeometry
.BytesPerSector
< SECTOR_SIZE
)) {
692 BlockFactor
= SECTOR_SIZE
/ DiskGeometry
.BytesPerSector
;
696 // Acquire the global resource to do mount operations.
699 CdAcquireCdData( IrpContext
);
702 // Use a try-finally to facilitate cleanup.
708 // Allocate a buffer to query the TOC.
711 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
715 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
718 // Do a quick check to see if there any Vcb's which can be removed.
721 CdScanForDismountedVcb( IrpContext
);
724 // Get our device object and alignment requirement.
727 Status
= IoCreateDevice( CdData
.DriverObject
,
728 sizeof( VOLUME_DEVICE_OBJECT
) - sizeof( DEVICE_OBJECT
),
730 FILE_DEVICE_CD_ROM_FILE_SYSTEM
,
733 (PDEVICE_OBJECT
*) &VolDo
);
735 if (!NT_SUCCESS( Status
)) { try_leave( Status
); }
738 // Our alignment requirement is the larger of the processor alignment requirement
739 // already in the volume device object and that in the DeviceObjectWeTalkTo
742 if (DeviceObjectWeTalkTo
->AlignmentRequirement
> VolDo
->DeviceObject
.AlignmentRequirement
) {
744 VolDo
->DeviceObject
.AlignmentRequirement
= DeviceObjectWeTalkTo
->AlignmentRequirement
;
748 // We must initialize the stack size in our device object before
749 // the following reads, because the I/O system has not done it yet.
752 ((PDEVICE_OBJECT
) VolDo
)->StackSize
= (CCHAR
) (DeviceObjectWeTalkTo
->StackSize
+ 1);
754 ClearFlag( VolDo
->DeviceObject
.Flags
, DO_DEVICE_INITIALIZING
);
757 // Initialize the overflow queue for the volume
760 VolDo
->OverflowQueueCount
= 0;
761 InitializeListHead( &VolDo
->OverflowQueue
);
763 VolDo
->PostedRequestCount
= 0;
764 KeInitializeSpinLock( &VolDo
->OverflowQueueSpinLock
);
767 // Let's query for the Toc now and handle any error we get from this operation.
770 Status
= CdProcessToc( IrpContext
,
771 DeviceObjectWeTalkTo
,
778 // If we failed to read the TOC, then bail out. Probably blank media.
781 if (Status
!= STATUS_SUCCESS
) {
787 // Now before we can initialize the Vcb we need to set up the
788 // device object field in the VPB to point to our new volume device
792 Vpb
->DeviceObject
= (PDEVICE_OBJECT
) VolDo
;
795 // Initialize the Vcb. This routine will raise on an allocation
799 CdInitializeVcb( IrpContext
,
801 DeviceObjectWeTalkTo
,
811 // Show that we initialized the Vcb and can cleanup with the Vcb.
820 // Store the Vcb in the IrpContext as we didn't have one before.
823 IrpContext
->Vcb
= Vcb
;
825 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
828 // Let's reference the Vpb to make sure we are the one to
829 // have the last dereference.
832 Vcb
->Vpb
->ReferenceCount
+= 1;
835 // Clear the verify bit for the start of mount.
838 CdMarkRealDevVerifyOk( Vcb
->Vpb
->RealDevice
);
840 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
843 // Allocate a buffer to read in the volume descriptors. We allocate a full
844 // page to make sure we don't hit any alignment problems.
847 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
848 ROUND_TO_PAGES( SECTOR_SIZE
),
852 // Try to find the primary volume descriptor.
855 FoundPvd
= CdFindPrimaryVd( IrpContext
,
865 // We failed to find a valid VD in the data track, but there were also
866 // audio tracks on this disc, so we'll try to mount it as an audio CD.
867 // Since we're always last in the mount order, we won't be preventing
868 // any other FS from trying to mount the data track. However if the
869 // data track was at the start of the disc, then we abort, to avoid
870 // having to filter it from our synthesized directory listing later. We
871 // already filtered off any data track at the end.
874 if (!(TocDiskFlags
& CDROM_DISK_AUDIO_TRACK
) ||
875 BooleanFlagOn( Vcb
->CdromToc
->TrackData
[0].Control
, TOC_DATA_TRACK
)) {
877 try_leave( Status
= STATUS_UNRECOGNIZED_VOLUME
);
880 SetFlag( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
| VCB_STATE_CDXA
);
882 CdFreePool( &RawIsoVd
);
888 // Look and see if there is a secondary volume descriptor we want to
895 // Store the primary volume descriptor in the second half of
896 // RawIsoVd. Then if our search for a secondary fails we can
897 // recover this immediately.
900 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
905 // We have the initial volume descriptor. Locate a secondary
906 // volume descriptor if present.
909 CdFindActiveVolDescriptor( IrpContext
,
916 // Check if this is a remount operation. If so then clean up
917 // the data structures passed in and created here.
920 if (CdIsRemount( IrpContext
, Vcb
, &OldVcb
)) {
922 //KIRQL SavedIrql; /* ReactOS Change: GCC Unused variable */
924 ASSERT( NULL
!= OldVcb
->SwapVpb
);
927 // Link the old Vcb to point to the new device object that we
928 // should be talking to, dereferencing the previous. Call a
929 // nonpaged routine to do this since we take the Vpb spinlock.
932 CdReMountOldVcb( IrpContext
,
935 DeviceObjectWeTalkTo
);
938 // See if we will need to provide notification of the remount. This is the readonly
939 // filesystem's form of dismount/mount notification - we promise that whenever a
940 // volume is "dismounted", that a mount notification will occur when it is revalidated.
941 // Note that we do not send mount on normal remounts - that would duplicate the media
942 // arrival notification of the device driver.
945 if (FlagOn( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
947 ClearFlag( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
949 FileObjectToNotify
= OldVcb
->RootIndexFcb
->FileObject
;
950 ObReferenceObject( FileObjectToNotify
);
953 try_leave( Status
= STATUS_SUCCESS
);
957 // This is a new mount. Go ahead and initialize the
958 // Vcb from the volume descriptor.
961 CdUpdateVcbFromVolDescriptor( IrpContext
,
966 // Drop an extra reference on the root dir file so we'll be able to send
970 if (Vcb
->RootIndexFcb
) {
972 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
973 ObReferenceObject( FileObjectToNotify
);
977 // Now check the maximum transfer limits on the device in case we
978 // get raw reads on this volume.
981 Status
= CdPerformDevIoCtrl( IrpContext
,
982 IOCTL_SCSI_GET_CAPABILITIES
,
983 DeviceObjectWeTalkTo
,
985 sizeof( IO_SCSI_CAPABILITIES
),
990 if (NT_SUCCESS(Status
)) {
992 Vcb
->MaximumTransferRawSectors
= Capabilities
.MaximumTransferLength
/ RAW_SECTOR_SIZE
;
993 Vcb
->MaximumPhysicalPages
= Capabilities
.MaximumPhysicalPages
;
998 // This should never happen, but we can safely assume 64k and 16 pages.
1001 Vcb
->MaximumTransferRawSectors
= (64 * 1024) / RAW_SECTOR_SIZE
;
1002 Vcb
->MaximumPhysicalPages
= 16;
1006 // The new mount is complete. Remove the additional references on this
1007 // Vcb and the device we are mounted on top of.
1010 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1011 ASSERT( Vcb
->VcbReference
== CDFS_RESIDUAL_REFERENCE
);
1013 ObDereferenceObject( Vcb
->TargetDeviceObject
);
1015 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1017 CdReleaseVcb( IrpContext
, Vcb
);
1020 Status
= STATUS_SUCCESS
;
1025 // Free the TOC buffer if not in the Vcb.
1028 if (CdromToc
!= NULL
) {
1030 CdFreePool( &CdromToc
);
1034 // Free the sector buffer if allocated.
1037 if (RawIsoVd
!= NULL
) {
1039 CdFreePool( &RawIsoVd
);
1043 // If we are not mounting the device, then set the verify bit again.
1046 if ((AbnormalTermination() || (Status
!= STATUS_SUCCESS
)) &&
1047 SetDoVerifyOnFail
) {
1049 CdMarkRealDevForVerify( IrpContext
->RealDevice
);
1053 // If we didn't complete the mount then cleanup any remaining structures.
1056 if (Vpb
!= NULL
) { Vpb
->DeviceObject
= NULL
; }
1061 // Make sure there is no Vcb in the IrpContext since it could go away
1064 IrpContext
->Vcb
= NULL
;
1066 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1068 if (CdDismountVcb( IrpContext
, Vcb
)) {
1070 CdReleaseVcb( IrpContext
, Vcb
);
1073 } else if (VolDo
!= NULL
) {
1075 IoDeleteDevice( (PDEVICE_OBJECT
) VolDo
);
1079 // Release the global resource.
1082 CdReleaseCdData( IrpContext
);
1086 // Now send mount notification.
1089 if (FileObjectToNotify
) {
1091 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1092 ObDereferenceObject( FileObjectToNotify
);
1096 // Complete the request if no exception.
1099 CdCompleteRequest( IrpContext
, Irp
, Status
);
1105 // Local support routine
1110 IN PIRP_CONTEXT IrpContext
,
1116 Routine Description:
1118 This routine performs the verify volume operation. It is responsible for
1119 either completing of enqueuing the input Irp.
1123 Irp - Supplies the Irp to process
1127 NTSTATUS - The return status for the operation
1132 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1133 PVPB Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
1134 PVCB Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->Parameters
.VerifyVolume
.DeviceObject
)->Vcb
;
1136 PCHAR RawIsoVd
= NULL
;
1138 PCDROM_TOC CdromToc
= NULL
;
1139 ULONG TocLength
= 0;
1140 ULONG TocTrackCount
= 0;
1141 ULONG TocDiskFlags
= 0;
1143 ULONG MediaChangeCount
= Vcb
->MediaChangeCount
;
1145 PFILE_OBJECT FileObjectToNotify
= NULL
;
1147 BOOLEAN ReturnError
;
1148 BOOLEAN ReleaseVcb
= FALSE
;
1150 IO_STATUS_BLOCK Iosb
;
1153 UNICODE_STRING UnicodeLabel
;
1155 WCHAR VolumeLabel
[ VOLUME_ID_LENGTH
];
1156 ULONG VolumeLabelLength
;
1165 // We check that we are talking to a Cdrom device.
1168 ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
1169 ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
1172 // Update the real device in the IrpContext from the Vpb. There was no available
1173 // file object when the IrpContext was created.
1176 IrpContext
->RealDevice
= Vpb
->RealDevice
;
1179 // Acquire the global resource to synchronise against mounts and teardown,
1180 // finally clause releases.
1183 CdAcquireCdData( IrpContext
);
1187 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1191 // Verify that there is a disk here.
1194 Status
= CdPerformDevIoCtrl( IrpContext
,
1195 IOCTL_CDROM_CHECK_VERIFY
,
1196 Vcb
->TargetDeviceObject
,
1203 if (!NT_SUCCESS( Status
)) {
1206 // If we will allow a raw mount then return WRONG_VOLUME to
1207 // allow the volume to be mounted by raw.
1210 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1212 Status
= STATUS_WRONG_VOLUME
;
1215 try_return( Status
);
1218 if (Iosb
.Information
!= sizeof(ULONG
)) {
1221 // Be safe about the count in case the driver didn't fill it in
1224 MediaChangeCount
= 0;
1228 // Verify that the device actually saw a change. If the driver does not
1229 // support the MCC, then we must verify the volume in any case.
1232 if (MediaChangeCount
== 0 ||
1233 (Vcb
->MediaChangeCount
!= MediaChangeCount
)) {
1236 // Allocate a buffer to query the TOC.
1239 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
1240 sizeof( CDROM_TOC
),
1243 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
1246 // Let's query for the Toc now and handle any error we get from this operation.
1249 Status
= CdProcessToc( IrpContext
,
1250 Vcb
->TargetDeviceObject
,
1257 // If we failed to read the TOC, then give up now. Drives will fail
1258 // a TOC read on, for example, erased CD-RW media.
1261 if (Status
!= STATUS_SUCCESS
) {
1264 // For any errors other than no media and not ready, commute the
1265 // status to ensure that the current VPB is kicked off the device
1266 // below - there is probably blank media in the drive, since we got
1267 // further than the check verify.
1270 if (!CdIsRawDevice( IrpContext
, Status
)) {
1272 Status
= STATUS_WRONG_VOLUME
;
1275 try_return( Status
);
1278 // We got a TOC. Verify that it matches the previous Toc.
1281 } else if ((Vcb
->TocLength
!= TocLength
) ||
1282 (Vcb
->TrackCount
!= TocTrackCount
) ||
1283 (Vcb
->DiskFlags
!= TocDiskFlags
) ||
1284 !RtlEqualMemory( CdromToc
,
1288 try_return( Status
= STATUS_WRONG_VOLUME
);
1292 // If the disk to verify is an audio disk then we already have a
1293 // match. Otherwise we need to check the volume descriptor.
1296 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
1299 // Allocate a buffer for the sector buffer.
1302 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
1303 ROUND_TO_PAGES( 2 * SECTOR_SIZE
),
1307 // Read the primary volume descriptor for this volume. If we
1308 // get an io error and this verify was a the result of DASD open,
1309 // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
1310 // expect a music disk then this request should fail.
1313 ReturnError
= FALSE
;
1315 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1320 if (!CdFindPrimaryVd( IrpContext
,
1328 // If the previous Vcb did not represent a raw disk
1329 // then show this volume was dismounted.
1332 try_return( Status
= STATUS_WRONG_VOLUME
);
1338 // Look for a supplementary VD.
1340 // Store the primary volume descriptor in the second half of
1341 // RawIsoVd. Then if our search for a secondary fails we can
1342 // recover this immediately.
1345 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
1350 // We have the initial volume descriptor. Locate a secondary
1351 // volume descriptor if present.
1354 CdFindActiveVolDescriptor( IrpContext
,
1359 // Compare the serial numbers. If they don't match, set the
1360 // status to wrong volume.
1363 if (Vpb
->SerialNumber
!= CdSerial32( RawIsoVd
, SECTOR_SIZE
)) {
1365 try_return( Status
= STATUS_WRONG_VOLUME
);
1369 // Verify the volume labels.
1372 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
1375 // Compute the length of the volume name
1378 AnsiLabel
.Buffer
= (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
); /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
1379 AnsiLabel
.MaximumLength
= AnsiLabel
.Length
= VOLUME_ID_LENGTH
;
1381 UnicodeLabel
.MaximumLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
1382 UnicodeLabel
.Buffer
= VolumeLabel
;
1385 // Convert this to unicode. If we get any error then use a name
1389 VolumeLabelLength
= 0;
1391 if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel
,
1395 VolumeLabelLength
= UnicodeLabel
.Length
;
1399 // We need to convert from big-endian to little endian.
1404 CdConvertBigToLittleEndian( IrpContext
,
1405 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
1407 (PCHAR
) VolumeLabel
);
1409 VolumeLabelLength
= VOLUME_ID_LENGTH
;
1413 // Strip the trailing spaces or zeroes from the name.
1416 Index
= VolumeLabelLength
/ sizeof( WCHAR
);
1420 if ((VolumeLabel
[ Index
- 1 ] != L
'\0') &&
1421 (VolumeLabel
[ Index
- 1 ] != L
' ')) {
1430 // Now set the final length for the name.
1433 VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));
1436 // Now check that the label matches.
1438 if ((Vpb
->VolumeLabelLength
!= VolumeLabelLength
) ||
1439 !RtlEqualMemory( Vpb
->VolumeLabel
,
1441 VolumeLabelLength
)) {
1443 try_return( Status
= STATUS_WRONG_VOLUME
);
1450 // The volume is OK, clear the verify bit.
1453 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1455 CdMarkRealDevVerifyOk( Vpb
->RealDevice
);
1458 // See if we will need to provide notification of the remount. This is the readonly
1459 // filesystem's form of dismount/mount notification.
1462 if (FlagOn( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1464 ClearFlag( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1466 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1467 ObReferenceObject( FileObjectToNotify
);
1473 // Update the media change count to note that we have verified the volume
1474 // at this value - regardless of the outcome.
1477 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
1480 // If we got the wrong volume then free any remaining XA sector in
1481 // the current Vcb. Also mark the Vcb as not mounted.
1484 if (Status
== STATUS_WRONG_VOLUME
) {
1486 CdUpdateVcbCondition( Vcb
, VcbNotMounted
);
1488 if (Vcb
->XASector
!= NULL
) {
1490 CdFreePool( &Vcb
->XASector
);
1492 Vcb
->XADiskOffset
= 0;
1496 // Now, if there are no user handles to the volume, try to spark
1497 // teardown by purging the volume.
1500 if (Vcb
->VcbCleanup
== 0) {
1502 if (NT_SUCCESS( CdPurgeVolume( IrpContext
, Vcb
, FALSE
))) {
1504 ReleaseVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
1512 // Free the TOC buffer if allocated.
1515 if (CdromToc
!= NULL
) {
1517 CdFreePool( &CdromToc
);
1520 if (RawIsoVd
!= NULL
) {
1522 CdFreePool( &RawIsoVd
);
1527 CdReleaseVcb( IrpContext
, Vcb
);
1530 CdReleaseCdData( IrpContext
);
1534 // Now send mount notification.
1537 if (FileObjectToNotify
) {
1539 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1540 ObDereferenceObject( FileObjectToNotify
);
1544 // Complete the request if no exception.
1547 CdCompleteRequest( IrpContext
, Irp
, Status
);
1553 // Local support routine
1558 IN PIRP_CONTEXT IrpContext
,
1564 Routine Description:
1566 This is the common routine to handle oplock requests made via the
1567 NtFsControlFile call.
1571 Irp - Supplies the Irp being processed
1575 NTSTATUS - The return status for the operation
1584 ULONG OplockCount
= 0;
1585 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1590 // We only permit oplock requests on files.
1593 if (CdDecodeFileObject( IrpContext
,
1596 &Ccb
) != UserFileOpen
) {
1598 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1599 return STATUS_INVALID_PARAMETER
;
1603 // Make this a waitable Irpcontext so we don't fail to acquire
1607 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1608 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1611 // Switch on the function control code. We grab the Fcb exclusively
1612 // for oplock requests, shared for oplock break acknowledgement.
1615 switch (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
1617 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
1618 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
1619 case FSCTL_REQUEST_BATCH_OPLOCK
:
1620 case FSCTL_REQUEST_FILTER_OPLOCK
:
1622 CdAcquireFcbExclusive( IrpContext
, Fcb
, FALSE
);
1624 if (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_REQUEST_OPLOCK_LEVEL_2
) {
1626 if (Fcb
->FileLock
!= NULL
) {
1628 OplockCount
= (ULONG
) FsRtlAreThereCurrentFileLocks( Fcb
->FileLock
);
1633 OplockCount
= Fcb
->FcbCleanup
;
1638 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
1639 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
1640 case FSCTL_OPLOCK_BREAK_NOTIFY
:
1641 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
1643 CdAcquireFcbShared( IrpContext
, Fcb
, FALSE
);
1648 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1649 return STATUS_INVALID_PARAMETER
;
1653 // Use a try finally to free the Fcb.
1662 CdVerifyFcbOperation( IrpContext
, Fcb
);
1665 // Call the FsRtl routine to grant/acknowledge oplock.
1668 Status
= FsRtlOplockFsctrl( &Fcb
->Oplock
,
1673 // Set the flag indicating if Fast I/O is possible
1676 CdLockFcb( IrpContext
, Fcb
);
1677 Fcb
->IsFastIoPossible
= CdIsFastIoPossible( Fcb
);
1678 CdUnlockFcb( IrpContext
, Fcb
);
1681 // The oplock package will complete the Irp.
1689 // Release all of our resources
1692 CdReleaseFcb( IrpContext
, Fcb
);
1696 // Complete the request if there was no exception.
1699 CdCompleteRequest( IrpContext
, Irp
, Status
);
1705 // Local support routine
1710 IN PIRP_CONTEXT IrpContext
,
1716 Routine Description:
1718 This routine performs the lock volume operation. It is responsible for
1719 either completing of enqueuing the input Irp.
1723 Irp - Supplies the Irp to process
1727 NTSTATUS - The return status for the operation
1734 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1743 // Decode the file object, the only type of opens we accept are
1744 // user volume opens.
1747 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1749 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1751 return STATUS_INVALID_PARAMETER
;
1755 // Send our notification so that folks that like to hold handles on
1756 // volumes can get out of the way.
1759 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
1762 // Acquire exclusive access to the Vcb.
1766 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1774 CdVerifyVcb( IrpContext
, Vcb
);
1776 Status
= CdLockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
1784 CdReleaseVcb( IrpContext
, Vcb
);
1786 if (AbnormalTermination() || !NT_SUCCESS( Status
)) {
1788 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
1793 // Complete the request if there haven't been any exceptions.
1796 CdCompleteRequest( IrpContext
, Irp
, Status
);
1802 // Local support routine
1807 IN PIRP_CONTEXT IrpContext
,
1813 Routine Description:
1815 This routine performs the unlock volume operation. It is responsible for
1816 either completing of enqueuing the input Irp.
1820 Irp - Supplies the Irp to process
1824 NTSTATUS - The return status for the operation
1831 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1840 // Decode the file object, the only type of opens we accept are
1841 // user volume opens.
1844 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1846 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1847 return STATUS_INVALID_PARAMETER
;
1851 // Acquire exclusive access to the Vcb.
1856 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1859 // We won't check for a valid Vcb for this request. An unlock will always
1860 // succeed on a locked volume.
1863 Status
= CdUnlockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
1866 // Release all of our resources
1869 CdReleaseVcb( IrpContext
, Vcb
);
1872 // Send notification that the volume is available.
1875 if (NT_SUCCESS( Status
)) {
1877 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
1881 // Complete the request if there haven't been any exceptions.
1884 CdCompleteRequest( IrpContext
, Irp
, Status
);
1891 // Local support routine
1896 IN PIRP_CONTEXT IrpContext
,
1902 Routine Description:
1904 This routine performs the dismount volume operation. It is responsible for
1905 either completing of enqueuing the input Irp. We only dismount a volume which
1906 has been locked. The intent here is that someone has locked the volume (they are the
1907 only remaining handle). We set the verify bit here and the user will close his handle.
1908 We will dismount a volume with no user's handles in the verify path.
1912 Irp - Supplies the Irp to process
1916 NTSTATUS - The return status for the operation
1922 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1930 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1932 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1933 return STATUS_INVALID_PARAMETER
;
1939 // Make this request waitable.
1942 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1945 // Acquire exclusive access to the Vcb, and take the global resource to
1946 // sync. against mounts, verifies etc.
1949 CdAcquireCdData( IrpContext
);
1950 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1953 // Mark the volume as needs to be verified, but only do it if
1954 // the vcb is locked by this handle and the volume is currently mounted.
1957 if (Vcb
->VcbCondition
!= VcbMounted
) {
1959 Status
= STATUS_VOLUME_DISMOUNTED
;
1964 // Invalidate the volume right now.
1966 // The intent here is to make every subsequent operation
1967 // on the volume fail and grease the rails toward dismount.
1968 // By definition there is no going back from a SURPRISE.
1971 CdLockVcb( IrpContext
, Vcb
);
1973 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
1975 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
1978 CdUnlockVcb( IrpContext
, Vcb
);
1981 // Set flag to tell the close path that we want to force dismount
1982 // the volume when this handle is closed.
1985 SetFlag( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
);
1987 Status
= STATUS_SUCCESS
;
1991 // Release all of our resources
1994 CdReleaseVcb( IrpContext
, Vcb
);
1995 CdReleaseCdData( IrpContext
);
1998 // Complete the request if there haven't been any exceptions.
2001 CdCompleteRequest( IrpContext
, Irp
, Status
);
2007 // Local support routine
2009 NTSTATUS
/* ReactOS Change: Function did not have a type??? */
2011 IN PIRP_CONTEXT IrpContext
,
2017 Routine Description:
2019 This routine determines if a volume is currently dirty.
2023 Irp - Supplies the Irp to process
2027 NTSTATUS - The return status for the operation
2032 PIO_STACK_LOCATION IrpSp
;
2034 TYPE_OF_OPEN TypeOfOpen
;
2041 // Get the current stack location and extract the output
2042 // buffer information.
2045 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2048 // Get a pointer to the output buffer.
2051 if (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
) {
2053 VolumeState
= Irp
->AssociatedIrp
.SystemBuffer
;
2057 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_USER_BUFFER
);
2058 return STATUS_INVALID_USER_BUFFER
;
2062 // Make sure the output buffer is large enough and then initialize
2063 // the answer to be that the volume isn't dirty.
2066 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
)) {
2068 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2069 return STATUS_INVALID_PARAMETER
;
2075 // Decode the file object
2078 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2080 if (TypeOfOpen
!= UserVolumeOpen
) {
2082 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2083 return STATUS_INVALID_PARAMETER
;
2086 if (Fcb
->Vcb
->VcbCondition
!= VcbMounted
) {
2088 CdCompleteRequest( IrpContext
, Irp
, STATUS_VOLUME_DISMOUNTED
);
2089 return STATUS_VOLUME_DISMOUNTED
;
2093 // Now set up to return the clean state. CDs obviously can never be dirty
2094 // but we want to make sure we have enforced the full semantics of this call.
2097 Irp
->IoStatus
.Information
= sizeof( ULONG
);
2099 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2100 return STATUS_SUCCESS
;
2105 // Local support routine
2110 IN PIRP_CONTEXT IrpContext
,
2116 Routine Description:
2118 This routine determines if a volume is currently mounted.
2122 Irp - Supplies the Irp to process
2126 NTSTATUS - The return status for the operation
2131 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2139 // Decode the file object.
2142 CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2147 // Disable PopUps, we want to return any error.
2150 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
2153 // Verify the Vcb. This will raise in the error condition.
2156 CdVerifyVcb( IrpContext
, Fcb
->Vcb
);
2159 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2161 return STATUS_SUCCESS
;
2166 // Local support routine
2171 IN PIRP_CONTEXT IrpContext
,
2177 Routine Description:
2179 This routine determines if pathname is a valid CDFS pathname.
2180 We always succeed this request.
2184 Irp - Supplies the Irp to process.
2195 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2196 return STATUS_SUCCESS
;
2201 // Local support routine
2205 CdInvalidateVolumes (
2206 IN PIRP_CONTEXT IrpContext
,
2212 Routine Description:
2214 This routine searches for all the volumes mounted on the same real device
2215 of the current DASD handle, and marks them all bad. The only operation
2216 that can be done on such handles is cleanup and close.
2220 Irp - Supplies the Irp to process
2224 NTSTATUS - The return status for the operation
2230 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2233 BOOLEAN UnlockVcb
= FALSE
;
2235 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
2243 PFILE_OBJECT FileToMarkBad
;
2244 PDEVICE_OBJECT DeviceToMarkBad
;
2247 // We only allow the invalidate call to come in on our file system devices.
2250 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
2252 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
2254 return STATUS_INVALID_DEVICE_REQUEST
;
2258 // Check for the correct security access.
2259 // The caller must have the SeTcbPrivilege.
2262 if (!SeSinglePrivilegeCheck( TcbPrivilege
, Irp
->RequestorMode
)) {
2264 CdCompleteRequest( IrpContext
, Irp
, STATUS_PRIVILEGE_NOT_HELD
);
2266 return STATUS_PRIVILEGE_NOT_HELD
;
2270 // Try to get a pointer to the device object from the handle passed in.
2274 if (IoIs32bitProcess( Irp
)) {
2276 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( UINT32
)) {
2278 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2279 return STATUS_INVALID_PARAMETER
;
2282 Handle
= (HANDLE
) LongToHandle( *((PUINT32
) Irp
->AssociatedIrp
.SystemBuffer
) );
2286 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( HANDLE
)) {
2288 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2289 return STATUS_INVALID_PARAMETER
;
2291 Handle
= *((PHANDLE
) Irp
->AssociatedIrp
.SystemBuffer
);
2296 Status
= ObReferenceObjectByHandle( Handle
,
2300 (PVOID
*)&FileToMarkBad
, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
2303 if (!NT_SUCCESS(Status
)) {
2305 CdCompleteRequest( IrpContext
, Irp
, Status
);
2310 // Grab the DeviceObject from the FileObject.
2313 DeviceToMarkBad
= FileToMarkBad
->DeviceObject
;
2316 // We only needed the device object involved, not a reference to the file.
2319 ObDereferenceObject( FileToMarkBad
);
2322 // Make sure this request can wait.
2325 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2326 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
2329 // Synchronise with pnp/mount/verify paths.
2332 CdAcquireCdData( IrpContext
);
2335 // Nothing can go wrong now.
2339 // Now walk through all the mounted Vcb's looking for candidates to
2342 // On volumes we mark invalid, check for dismount possibility (which is
2343 // why we have to get the next link so early).
2346 Links
= CdData
.VcbQueue
.Flink
;
2348 while (Links
!= &CdData
.VcbQueue
) {
2350 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2352 Links
= Links
->Flink
;
2355 // If we get a match, mark the volume Bad, and also check to
2356 // see if the volume should go away.
2359 CdLockVcb( IrpContext
, Vcb
);
2361 if (Vcb
->Vpb
->RealDevice
== DeviceToMarkBad
) {
2364 // Take the VPB spinlock, and look to see if this volume is the
2365 // one currently mounted on the actual device. If it is, pull it
2369 IoAcquireVpbSpinLock( &SavedIrql
);
2371 if (DeviceToMarkBad
->Vpb
== Vcb
->Vpb
) {
2373 PVPB NewVpb
= Vcb
->SwapVpb
;
2375 ASSERT( FlagOn( Vcb
->Vpb
->Flags
, VPB_MOUNTED
));
2376 ASSERT( NULL
!= NewVpb
);
2378 RtlZeroMemory( NewVpb
, sizeof( VPB
) );
2380 NewVpb
->Type
= IO_TYPE_VPB
;
2381 NewVpb
->Size
= sizeof( VPB
);
2382 NewVpb
->RealDevice
= DeviceToMarkBad
;
2383 NewVpb
->Flags
= FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_REMOVE_PENDING
);
2385 DeviceToMarkBad
->Vpb
= NewVpb
;
2386 Vcb
->SwapVpb
= NULL
;
2389 IoReleaseVpbSpinLock( SavedIrql
);
2391 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2393 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2396 CdUnlockVcb( IrpContext
, Vcb
);
2398 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2400 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
2402 UnlockVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2406 CdReleaseVcb( IrpContext
, Vcb
);
2411 CdUnlockVcb( IrpContext
, Vcb
);
2415 CdReleaseCdData( IrpContext
);
2417 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2418 return STATUS_SUCCESS
;
2423 // Local support routine
2427 CdScanForDismountedVcb (
2428 IN PIRP_CONTEXT IrpContext
2433 Routine Description:
2435 This routine walks through the list of Vcb's looking for any which may
2436 now be deleted. They may have been left on the list because there were
2437 outstanding references.
2454 // Walk through all of the Vcb's attached to the global data.
2457 Links
= CdData
.VcbQueue
.Flink
;
2459 while (Links
!= &CdData
.VcbQueue
) {
2461 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2464 // Move to the next link now since the current Vcb may be deleted.
2467 Links
= Links
->Flink
;
2470 // If dismount is already underway then check if this Vcb can
2474 if ((Vcb
->VcbCondition
== VcbDismountInProgress
) ||
2475 (Vcb
->VcbCondition
== VcbInvalid
) ||
2476 ((Vcb
->VcbCondition
== VcbNotMounted
) && (Vcb
->VcbReference
<= CDFS_RESIDUAL_REFERENCE
))) {
2478 CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2487 // Local support routine
2492 IN PIRP_CONTEXT IrpContext
,
2495 IN ULONG BlockFactor
,
2496 IN BOOLEAN ReturnOnError
,
2497 IN BOOLEAN VerifyVolume
2502 Routine Description:
2504 This routine is called to walk through the volume descriptors looking
2505 for a primary volume descriptor. When/if a primary is found a 32-bit
2506 serial number is generated and stored into the Vpb. We also store the
2507 location of the primary volume descriptor in the Vcb.
2511 Vcb - Pointer to the VCB for the volume.
2513 RawIsoVd - Pointer to a sector buffer which will contain the primary
2514 volume descriptor on exit, if successful.
2516 BlockFactor - Block factor used by the current device for the TableOfContents.
2518 ReturnOnError - Indicates that we should raise on I/O errors rather than
2519 returning a FALSE value.
2521 VerifyVolume - Indicates if we were called from the verify path. We
2522 do a few things different in this path. We don't update the Vcb in
2527 BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
2535 BOOLEAN FoundVd
= FALSE
;
2540 PCDROM_TOC CdromToc
;
2547 // If there are no data tracks, don't even bother hunting for descriptors.
2549 // This explicitly breaks various non-BlueBook compliant CDs that scribble
2550 // an ISO filesystem on media claiming only audio tracks. Since these
2551 // disks can cause serious problems in some CDROM units, fail fast. I admit
2552 // that it is possible that someone can still record the descriptors in the
2553 // audio track, record a data track (but fail to record descriptors there)
2554 // and still have the disk work. As this form of error worked in NT 4.0, and
2555 // since these disks really do exist, I don't want to change them.
2557 // If we wished to support all such media (we don't), it would be necessary
2558 // to clear this flag on finding ISO or HSG descriptors below.
2561 if (FlagOn(Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2567 // We will make at most two passes through the volume descriptor sequence.
2569 // On the first pass we will query for the last session. Using this
2570 // as a starting offset we will attempt to mount the volume. On any failure
2571 // we will go to the second pass and try without using any multi-session
2574 // On the second pass we will start offset from sector zero.
2577 while (!FoundVd
&& (ThisPass
<= 2)) {
2580 // If we aren't at pass 1 then we start at sector 0. Otherwise we
2581 // try to look up the multi-session information.
2586 if (ThisPass
== 1) {
2591 // Check for whether this device supports XA and multi-session.
2597 // Allocate a buffer for the last session information.
2600 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
2601 sizeof( CDROM_TOC
),
2604 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
2607 // Query the last session information from the driver.
2610 Status
= CdPerformDevIoCtrl( IrpContext
,
2611 IOCTL_CDROM_GET_LAST_SESSION
,
2612 Vcb
->TargetDeviceObject
,
2614 sizeof( CDROM_TOC
),
2620 // Raise an exception if there was an allocation failure.
2623 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
2625 CdRaiseStatus( IrpContext
, Status
);
2629 // We don't handle any errors yet. We will hit that below
2630 // as we try to scan the disk. If we have last session information
2631 // then modify the base sector.
2634 if (NT_SUCCESS( Status
) &&
2635 (CdromToc
->FirstTrack
!= CdromToc
->LastTrack
)) {
2643 // The track address is BigEndian, we need to flip the bytes.
2646 Source
= (PCHAR
) &CdromToc
->TrackData
[0].Address
[3];/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
2647 Dest
= (PCHAR
) &BaseSector
; /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
2651 *Dest
++ = *Source
--;
2656 // Now adjust the base sector by the block factor of the
2660 BaseSector
/= BlockFactor
;
2663 // Make this look like the second pass since we are only using the
2664 // first session. No reason to retry on error.
2674 if (CdromToc
!= NULL
) { CdFreePool( &CdromToc
); }
2679 // Compute the starting sector offset from the start of the session.
2682 SectorOffset
= FIRST_VD_SECTOR
;
2685 // Start by assuming we have neither Hsg or Iso volumes.
2691 // Loop until either error encountered, primary volume descriptor is
2692 // found or a terminal volume descriptor is found.
2698 // Attempt to read the desired sector. Exit directly if operation
2701 // If this is pass 1 we will ignore errors in read sectors and just
2702 // go to the next pass.
2705 if (!CdReadSectors( IrpContext
,
2706 LlBytesFromSectors( BaseSector
+ SectorOffset
),
2708 (BOOLEAN
) ((ThisPass
== 1) || ReturnOnError
),
2710 Vcb
->TargetDeviceObject
)) {
2716 // Check if either an ISO or HSG volume.
2719 if (RtlEqualMemory( CdIsoId
,
2720 CdRvdId( RawIsoVd
, VCB_STATE_ISO
),
2723 SetFlag( VolumeFlags
, VCB_STATE_ISO
);
2725 } else if (RtlEqualMemory( CdHsgId
,
2726 CdRvdId( RawIsoVd
, VCB_STATE_HSG
),
2729 SetFlag( VolumeFlags
, VCB_STATE_HSG
);
2732 // We have neither so break out of the loop.
2741 // Break out if the version number is incorrect or this is
2745 if ((CdRvdVersion( RawIsoVd
, VolumeFlags
) != VERSION_1
) ||
2746 (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_TERMINATOR
)) {
2752 // If this is a primary volume descriptor then our search is over.
2755 if (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_PRIMARY
) {
2758 // If we are not in the verify path then initialize the
2759 // fields in the Vcb with basic information from this
2763 if (!VerifyVolume
) {
2766 // Set the flag for the volume type.
2769 SetFlag( Vcb
->VcbState
, VolumeFlags
);
2772 // Store the base sector and sector offset for the
2773 // primary volume descriptor.
2776 Vcb
->BaseSector
= BaseSector
;
2777 Vcb
->VdSectorOffset
= SectorOffset
;
2778 Vcb
->PrimaryVdSectorOffset
= SectorOffset
;
2786 // Indicate that we're at the next sector.
2800 // Local support routine
2805 IN PIRP_CONTEXT IrpContext
,
2811 Routine Description:
2813 This routine walks through the links of the Vcb chain in the global
2814 data structure. The remount condition is met when the following
2815 conditions are all met:
2817 If the new Vcb is a device only Mvcb and there is a previous
2820 Otherwise following conditions must be matched.
2822 1 - The 32 serial in the current VPB matches that in a previous
2825 2 - The volume label in the Vpb matches that in the previous
2828 3 - The system pointer to the real device object in the current
2829 VPB matches that in the same previous VPB.
2831 4 - Finally the previous Vcb cannot be invalid or have a dismount
2834 If a VPB is found which matches these conditions, then the address of
2835 the VCB for that VPB is returned via the pointer Vcb.
2837 Skip over the current Vcb.
2841 Vcb - This is the Vcb we are checking for a remount.
2843 OldVcb - A pointer to the address to store the address for the Vcb
2844 for the volume if this is a remount. (This is a pointer to
2849 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
2856 PVPB Vpb
= Vcb
->Vpb
;
2859 BOOLEAN Remount
= FALSE
;
2864 // Check whether we are looking for a device only Mvcb.
2867 for (Link
= CdData
.VcbQueue
.Flink
;
2868 Link
!= &CdData
.VcbQueue
;
2869 Link
= Link
->Flink
) {
2871 *OldVcb
= CONTAINING_RECORD( Link
, VCB
, VcbLinks
);
2877 if (Vcb
== *OldVcb
) { continue; }
2880 // Look at the Vpb and state of the previous Vcb.
2883 OldVpb
= (*OldVcb
)->Vpb
;
2885 if ((OldVpb
!= Vpb
) &&
2886 (OldVpb
->RealDevice
== Vpb
->RealDevice
) &&
2887 ((*OldVcb
)->VcbCondition
== VcbNotMounted
)) {
2890 // If the current disk is a raw disk then it can match a previous music or
2894 if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2896 if (FlagOn( (*OldVcb
)->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2899 // If we have both TOC then fail the remount if the lengths
2900 // are different or they don't match.
2903 if ((Vcb
->TocLength
!= (*OldVcb
)->TocLength
) ||
2904 ((Vcb
->TocLength
!= 0) &&
2905 !RtlEqualMemory( Vcb
->CdromToc
,
2906 (*OldVcb
)->CdromToc
,
2907 Vcb
->TocLength
))) {
2917 // The current disk is not a raw disk. Go ahead and compare
2918 // serial numbers and volume label.
2921 } else if ((OldVpb
->SerialNumber
== Vpb
->SerialNumber
) &&
2922 (Vpb
->VolumeLabelLength
== OldVpb
->VolumeLabelLength
) &&
2923 (RtlEqualMemory( OldVpb
->VolumeLabel
,
2925 Vpb
->VolumeLabelLength
))) {
2928 // Remember the old mvcb. Then set the return value to
2943 // Local support routine
2947 CdFindActiveVolDescriptor (
2948 IN PIRP_CONTEXT IrpContext
,
2950 IN OUT PCHAR RawIsoVd
,
2951 IN BOOLEAN VerifyVolume
2956 Routine Description:
2958 This routine is called to search for a valid secondary volume descriptor that
2959 we will support. Right now we only support Joliet escape sequences for
2960 the secondary descriptor.
2962 If we don't find the secondary descriptor then we will reread the primary.
2964 This routine will update the serial number and volume label in the Vpb.
2968 Vcb - This is the Vcb for the volume being mounted.
2970 RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
2971 on input should contain the PVD (ISO) in the SECOND 'sector' of the
2974 VerifyVolume - indicates we are being called by the verify path, and should
2975 not modify the Vcb fields.
2984 BOOLEAN FoundSecondaryVd
= FALSE
;
2985 ULONG SectorOffset
= FIRST_VD_SECTOR
;
2994 // We only look for secondary volume descriptors on an Iso disk.
2997 if ((FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
) || VerifyVolume
) && !CdNoJoliet
) {
3000 // Scan the volume descriptors from the beginning looking for a valid
3001 // secondary or a terminator.
3004 SectorOffset
= FIRST_VD_SECTOR
;
3009 // Read the next sector. We should never have an error in this
3013 CdReadSectors( IrpContext
,
3014 LlBytesFromSectors( Vcb
->BaseSector
+ SectorOffset
),
3018 Vcb
->TargetDeviceObject
);
3021 // Break out if the version number or standard Id is incorrect.
3022 // Also break out if this is a terminator.
3025 if (!RtlEqualMemory( CdIsoId
, CdRvdId( RawIsoVd
, VCB_STATE_JOLIET
), VOL_ID_LEN
) ||
3026 (CdRvdVersion( RawIsoVd
, VCB_STATE_JOLIET
) != VERSION_1
) ||
3027 (CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_TERMINATOR
)) {
3033 // We have a match if this is a secondary descriptor with a matching
3037 if ((CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_SECONDARY
) &&
3038 (RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3041 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3044 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3048 if (!VerifyVolume
) {
3051 // Update the Vcb with the new volume descriptor.
3054 ClearFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
3055 SetFlag( Vcb
->VcbState
, VCB_STATE_JOLIET
);
3057 Vcb
->VdSectorOffset
= SectorOffset
;
3060 FoundSecondaryVd
= TRUE
;
3065 // Otherwise move on to the next sector.
3072 // If we didn't find the secondary then recover the original volume
3073 // descriptor stored in the second half of the RawIsoVd.
3076 if (!FoundSecondaryVd
) {
3078 RtlCopyMemory( RawIsoVd
,
3079 Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
3085 // If we're in the verify path, our work is done, since we don't want
3086 // to update any Vcb/Vpb values.
3095 // Compute the serial number and volume label from the volume descriptor.
3098 Vcb
->Vpb
->SerialNumber
= CdSerial32( RawIsoVd
, SECTOR_SIZE
);
3101 // Make sure the CD label will fit in the Vpb.
3104 ASSERT( VOLUME_ID_LENGTH
* sizeof( WCHAR
) <= MAXIMUM_VOLUME_LABEL_LENGTH
);
3107 // If this is not a Unicode label we must convert it to unicode.
3110 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
3113 // Convert the label to unicode. If we get any error then use a name
3117 Vcb
->Vpb
->VolumeLabelLength
= 0;
3119 if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb
->Vpb
->VolumeLabel
[0],
3120 MAXIMUM_VOLUME_LABEL_LENGTH
,
3122 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
3123 VOLUME_ID_LENGTH
))) {
3125 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) Length
;
3129 // We need to convert from big-endian to little endian.
3134 CdConvertBigToLittleEndian( IrpContext
,
3135 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
3137 (PCHAR
) Vcb
->Vpb
->VolumeLabel
);
3139 Vcb
->Vpb
->VolumeLabelLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
3143 // Strip the trailing spaces or zeroes from the name.
3146 Index
= Vcb
->Vpb
->VolumeLabelLength
/ sizeof( WCHAR
);
3150 if ((Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
'\0') &&
3151 (Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
' ')) {
3160 // Now set the final length for the name.
3163 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));