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;
600 DEVICE_TYPE FilesystemDeviceType
;
606 // Check that we are talking to a Cdrom device. This request should
607 // always be waitable.
611 if (IrpSp
->DeviceObject
== CdData
.HddFileSystemDeviceObject
) {
612 FilesystemDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
615 ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
617 FilesystemDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
620 ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
623 // Update the real device in the IrpContext from the Vpb. There was no available
624 // file object when the IrpContext was created.
627 IrpContext
->RealDevice
= Vpb
->RealDevice
;
629 SetDoVerifyOnFail
= CdRealDevNeedsVerify( IrpContext
->RealDevice
);
632 // Check if we have disabled the mount process.
637 CdCompleteRequest( IrpContext
, Irp
, STATUS_UNRECOGNIZED_VOLUME
);
638 return STATUS_UNRECOGNIZED_VOLUME
;
642 // Do a CheckVerify here to lift the MediaChange ticker from the driver
645 Status
= CdPerformDevIoCtrl( IrpContext
,
647 IOCTL_CDROM_CHECK_VERIFY
,
649 (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
? IOCTL_DISK_CHECK_VERIFY
: IOCTL_CDROM_CHECK_VERIFY
),
651 DeviceObjectWeTalkTo
,
658 if (!NT_SUCCESS( Status
)) {
660 CdCompleteRequest( IrpContext
, Irp
, Status
);
664 if (Iosb
.Information
!= sizeof(ULONG
)) {
667 // Be safe about the count in case the driver didn't fill it in
670 MediaChangeCount
= 0;
674 // Now let's make Jeff delirious and call to get the disk geometry. This
675 // will fix the case where the first change line is swallowed.
678 Status
= CdPerformDevIoCtrl( IrpContext
,
680 IOCTL_CDROM_GET_DRIVE_GEOMETRY
,
682 (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
? IOCTL_DISK_GET_DRIVE_GEOMETRY
: IOCTL_CDROM_GET_DRIVE_GEOMETRY
),
684 DeviceObjectWeTalkTo
,
686 sizeof( DISK_GEOMETRY
),
692 // Return insufficient sources to our caller.
695 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
697 CdCompleteRequest( IrpContext
, Irp
, Status
);
702 // Now check the block factor for addressing the volume descriptors.
703 // If the call for the disk geometry failed then assume there is one
709 if (NT_SUCCESS( Status
) &&
710 (DiskGeometry
.BytesPerSector
!= 0) &&
711 (DiskGeometry
.BytesPerSector
< SECTOR_SIZE
)) {
713 BlockFactor
= SECTOR_SIZE
/ DiskGeometry
.BytesPerSector
;
717 // Acquire the global resource to do mount operations.
720 CdAcquireCdData( IrpContext
);
723 // Use a try-finally to facilitate cleanup.
729 // Allocate a buffer to query the TOC.
732 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
736 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
739 // Do a quick check to see if there any Vcb's which can be removed.
742 CdScanForDismountedVcb( IrpContext
);
745 // Get our device object and alignment requirement.
748 Status
= IoCreateDevice( CdData
.DriverObject
,
749 sizeof( VOLUME_DEVICE_OBJECT
) - sizeof( DEVICE_OBJECT
),
752 FILE_DEVICE_CD_ROM_FILE_SYSTEM
,
754 FilesystemDeviceType
,
758 (PDEVICE_OBJECT
*) &VolDo
);
760 if (!NT_SUCCESS( Status
)) { try_leave( Status
); }
763 // Our alignment requirement is the larger of the processor alignment requirement
764 // already in the volume device object and that in the DeviceObjectWeTalkTo
767 if (DeviceObjectWeTalkTo
->AlignmentRequirement
> VolDo
->DeviceObject
.AlignmentRequirement
) {
769 VolDo
->DeviceObject
.AlignmentRequirement
= DeviceObjectWeTalkTo
->AlignmentRequirement
;
773 // We must initialize the stack size in our device object before
774 // the following reads, because the I/O system has not done it yet.
777 ((PDEVICE_OBJECT
) VolDo
)->StackSize
= (CCHAR
) (DeviceObjectWeTalkTo
->StackSize
+ 1);
779 ClearFlag( VolDo
->DeviceObject
.Flags
, DO_DEVICE_INITIALIZING
);
782 // Initialize the overflow queue for the volume
785 VolDo
->OverflowQueueCount
= 0;
786 InitializeListHead( &VolDo
->OverflowQueue
);
788 VolDo
->PostedRequestCount
= 0;
789 KeInitializeSpinLock( &VolDo
->OverflowQueueSpinLock
);
792 // Let's query for the Toc now and handle any error we get from this operation.
795 Status
= CdProcessToc( IrpContext
,
796 DeviceObjectWeTalkTo
,
803 // If we failed to read the TOC, then bail out. Probably blank media.
806 if (Status
!= STATUS_SUCCESS
) {
811 // Don't bail out if that was a disk based ISO image, it is legit
814 if (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) {
815 CdFreePool( &CdromToc
);
816 Status
= STATUS_SUCCESS
;
826 // Now before we can initialize the Vcb we need to set up the
827 // device object field in the VPB to point to our new volume device
831 Vpb
->DeviceObject
= (PDEVICE_OBJECT
) VolDo
;
834 // Initialize the Vcb. This routine will raise on an allocation
838 CdInitializeVcb( IrpContext
,
840 DeviceObjectWeTalkTo
,
850 // Show that we initialized the Vcb and can cleanup with the Vcb.
859 // Store the Vcb in the IrpContext as we didn't have one before.
862 IrpContext
->Vcb
= Vcb
;
864 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
867 // Let's reference the Vpb to make sure we are the one to
868 // have the last dereference.
871 Vcb
->Vpb
->ReferenceCount
+= 1;
874 // Clear the verify bit for the start of mount.
877 CdMarkRealDevVerifyOk( Vcb
->Vpb
->RealDevice
);
879 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
882 // Allocate a buffer to read in the volume descriptors. We allocate a full
883 // page to make sure we don't hit any alignment problems.
886 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
887 ROUND_TO_PAGES( SECTOR_SIZE
),
891 // Try to find the primary volume descriptor.
894 FoundPvd
= CdFindPrimaryVd( IrpContext
,
904 // We failed to find a valid VD in the data track, but there were also
905 // audio tracks on this disc, so we'll try to mount it as an audio CD.
906 // Since we're always last in the mount order, we won't be preventing
907 // any other FS from trying to mount the data track. However if the
908 // data track was at the start of the disc, then we abort, to avoid
909 // having to filter it from our synthesized directory listing later. We
910 // already filtered off any data track at the end.
913 if (!(TocDiskFlags
& CDROM_DISK_AUDIO_TRACK
) ||
914 BooleanFlagOn( Vcb
->CdromToc
->TrackData
[0].Control
, TOC_DATA_TRACK
)) {
916 try_leave( Status
= STATUS_UNRECOGNIZED_VOLUME
);
919 SetFlag( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
| VCB_STATE_CDXA
);
921 CdFreePool( &RawIsoVd
);
927 // Look and see if there is a secondary volume descriptor we want to
934 // Store the primary volume descriptor in the second half of
935 // RawIsoVd. Then if our search for a secondary fails we can
936 // recover this immediately.
939 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
944 // We have the initial volume descriptor. Locate a secondary
945 // volume descriptor if present.
948 CdFindActiveVolDescriptor( IrpContext
,
955 // Check if this is a remount operation. If so then clean up
956 // the data structures passed in and created here.
959 if (CdIsRemount( IrpContext
, Vcb
, &OldVcb
)) {
961 //KIRQL SavedIrql; /* ReactOS Change: GCC Unused variable */
963 ASSERT( NULL
!= OldVcb
->SwapVpb
);
966 // Link the old Vcb to point to the new device object that we
967 // should be talking to, dereferencing the previous. Call a
968 // nonpaged routine to do this since we take the Vpb spinlock.
971 CdReMountOldVcb( IrpContext
,
974 DeviceObjectWeTalkTo
);
977 // See if we will need to provide notification of the remount. This is the readonly
978 // filesystem's form of dismount/mount notification - we promise that whenever a
979 // volume is "dismounted", that a mount notification will occur when it is revalidated.
980 // Note that we do not send mount on normal remounts - that would duplicate the media
981 // arrival notification of the device driver.
984 if (FlagOn( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
986 ClearFlag( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
988 FileObjectToNotify
= OldVcb
->RootIndexFcb
->FileObject
;
989 ObReferenceObject( FileObjectToNotify
);
992 try_leave( Status
= STATUS_SUCCESS
);
996 // This is a new mount. Go ahead and initialize the
997 // Vcb from the volume descriptor.
1000 CdUpdateVcbFromVolDescriptor( IrpContext
,
1005 // Drop an extra reference on the root dir file so we'll be able to send
1009 if (Vcb
->RootIndexFcb
) {
1011 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1012 ObReferenceObject( FileObjectToNotify
);
1016 // Now check the maximum transfer limits on the device in case we
1017 // get raw reads on this volume.
1020 Status
= CdPerformDevIoCtrl( IrpContext
,
1021 IOCTL_SCSI_GET_CAPABILITIES
,
1022 DeviceObjectWeTalkTo
,
1024 sizeof( IO_SCSI_CAPABILITIES
),
1029 if (NT_SUCCESS(Status
)) {
1031 Vcb
->MaximumTransferRawSectors
= Capabilities
.MaximumTransferLength
/ RAW_SECTOR_SIZE
;
1032 Vcb
->MaximumPhysicalPages
= Capabilities
.MaximumPhysicalPages
;
1037 // This should never happen, but we can safely assume 64k and 16 pages.
1040 Vcb
->MaximumTransferRawSectors
= (64 * 1024) / RAW_SECTOR_SIZE
;
1041 Vcb
->MaximumPhysicalPages
= 16;
1045 // The new mount is complete. Remove the additional references on this
1046 // Vcb and the device we are mounted on top of.
1049 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1050 ASSERT( Vcb
->VcbReference
== CDFS_RESIDUAL_REFERENCE
);
1052 ObDereferenceObject( Vcb
->TargetDeviceObject
);
1054 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1056 CdReleaseVcb( IrpContext
, Vcb
);
1059 Status
= STATUS_SUCCESS
;
1064 // Free the TOC buffer if not in the Vcb.
1067 if (CdromToc
!= NULL
) {
1069 CdFreePool( &CdromToc
);
1073 // Free the sector buffer if allocated.
1076 if (RawIsoVd
!= NULL
) {
1078 CdFreePool( &RawIsoVd
);
1082 // If we are not mounting the device, then set the verify bit again.
1085 if ((AbnormalTermination() || (Status
!= STATUS_SUCCESS
)) &&
1086 SetDoVerifyOnFail
) {
1088 CdMarkRealDevForVerify( IrpContext
->RealDevice
);
1092 // If we didn't complete the mount then cleanup any remaining structures.
1095 if (Vpb
!= NULL
) { Vpb
->DeviceObject
= NULL
; }
1100 // Make sure there is no Vcb in the IrpContext since it could go away
1103 IrpContext
->Vcb
= NULL
;
1105 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1107 if (CdDismountVcb( IrpContext
, Vcb
)) {
1109 CdReleaseVcb( IrpContext
, Vcb
);
1112 } else if (VolDo
!= NULL
) {
1114 IoDeleteDevice( (PDEVICE_OBJECT
) VolDo
);
1118 // Release the global resource.
1121 CdReleaseCdData( IrpContext
);
1125 // Now send mount notification.
1128 if (FileObjectToNotify
) {
1130 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1131 ObDereferenceObject( FileObjectToNotify
);
1135 // Complete the request if no exception.
1138 CdCompleteRequest( IrpContext
, Irp
, Status
);
1144 // Local support routine
1149 IN PIRP_CONTEXT IrpContext
,
1155 Routine Description:
1157 This routine performs the verify volume operation. It is responsible for
1158 either completing of enqueuing the input Irp.
1162 Irp - Supplies the Irp to process
1166 NTSTATUS - The return status for the operation
1171 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1172 PVPB Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
1173 PVCB Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->Parameters
.VerifyVolume
.DeviceObject
)->Vcb
;
1175 PCHAR RawIsoVd
= NULL
;
1177 PCDROM_TOC CdromToc
= NULL
;
1178 ULONG TocLength
= 0;
1179 ULONG TocTrackCount
= 0;
1180 ULONG TocDiskFlags
= 0;
1182 ULONG MediaChangeCount
= Vcb
->MediaChangeCount
;
1184 PFILE_OBJECT FileObjectToNotify
= NULL
;
1186 BOOLEAN ReturnError
;
1187 BOOLEAN ReleaseVcb
= FALSE
;
1189 IO_STATUS_BLOCK Iosb
;
1192 UNICODE_STRING UnicodeLabel
;
1194 WCHAR VolumeLabel
[ VOLUME_ID_LENGTH
];
1195 ULONG VolumeLabelLength
;
1204 // We check that we are talking to a Cdrom device.
1207 ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
1208 ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
1211 // Update the real device in the IrpContext from the Vpb. There was no available
1212 // file object when the IrpContext was created.
1215 IrpContext
->RealDevice
= Vpb
->RealDevice
;
1218 // Acquire the global resource to synchronise against mounts and teardown,
1219 // finally clause releases.
1222 CdAcquireCdData( IrpContext
);
1226 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1230 // Verify that there is a disk here.
1233 Status
= CdPerformDevIoCtrl( IrpContext
,
1234 IOCTL_CDROM_CHECK_VERIFY
,
1235 Vcb
->TargetDeviceObject
,
1242 if (!NT_SUCCESS( Status
)) {
1245 // If we will allow a raw mount then return WRONG_VOLUME to
1246 // allow the volume to be mounted by raw.
1249 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1251 Status
= STATUS_WRONG_VOLUME
;
1254 try_return( Status
);
1257 if (Iosb
.Information
!= sizeof(ULONG
)) {
1260 // Be safe about the count in case the driver didn't fill it in
1263 MediaChangeCount
= 0;
1267 // Verify that the device actually saw a change. If the driver does not
1268 // support the MCC, then we must verify the volume in any case.
1271 if (MediaChangeCount
== 0 ||
1272 (Vcb
->MediaChangeCount
!= MediaChangeCount
)) {
1275 // Allocate a buffer to query the TOC.
1278 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
1279 sizeof( CDROM_TOC
),
1282 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
1285 // Let's query for the Toc now and handle any error we get from this operation.
1288 Status
= CdProcessToc( IrpContext
,
1289 Vcb
->TargetDeviceObject
,
1296 // If we failed to read the TOC, then give up now. Drives will fail
1297 // a TOC read on, for example, erased CD-RW media.
1300 if (Status
!= STATUS_SUCCESS
) {
1303 // For any errors other than no media and not ready, commute the
1304 // status to ensure that the current VPB is kicked off the device
1305 // below - there is probably blank media in the drive, since we got
1306 // further than the check verify.
1309 if (!CdIsRawDevice( IrpContext
, Status
)) {
1311 Status
= STATUS_WRONG_VOLUME
;
1314 try_return( Status
);
1317 // We got a TOC. Verify that it matches the previous Toc.
1320 } else if ((Vcb
->TocLength
!= TocLength
) ||
1321 (Vcb
->TrackCount
!= TocTrackCount
) ||
1322 (Vcb
->DiskFlags
!= TocDiskFlags
) ||
1323 !RtlEqualMemory( CdromToc
,
1327 try_return( Status
= STATUS_WRONG_VOLUME
);
1331 // If the disk to verify is an audio disk then we already have a
1332 // match. Otherwise we need to check the volume descriptor.
1335 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
1338 // Allocate a buffer for the sector buffer.
1341 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
1342 ROUND_TO_PAGES( 2 * SECTOR_SIZE
),
1346 // Read the primary volume descriptor for this volume. If we
1347 // get an io error and this verify was a the result of DASD open,
1348 // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
1349 // expect a music disk then this request should fail.
1352 ReturnError
= FALSE
;
1354 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1359 if (!CdFindPrimaryVd( IrpContext
,
1367 // If the previous Vcb did not represent a raw disk
1368 // then show this volume was dismounted.
1371 try_return( Status
= STATUS_WRONG_VOLUME
);
1377 // Look for a supplementary VD.
1379 // Store the primary volume descriptor in the second half of
1380 // RawIsoVd. Then if our search for a secondary fails we can
1381 // recover this immediately.
1384 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
1389 // We have the initial volume descriptor. Locate a secondary
1390 // volume descriptor if present.
1393 CdFindActiveVolDescriptor( IrpContext
,
1398 // Compare the serial numbers. If they don't match, set the
1399 // status to wrong volume.
1402 if (Vpb
->SerialNumber
!= CdSerial32( RawIsoVd
, SECTOR_SIZE
)) {
1404 try_return( Status
= STATUS_WRONG_VOLUME
);
1408 // Verify the volume labels.
1411 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
1414 // Compute the length of the volume name
1417 AnsiLabel
.Buffer
= (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
); /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
1418 AnsiLabel
.MaximumLength
= AnsiLabel
.Length
= VOLUME_ID_LENGTH
;
1420 UnicodeLabel
.MaximumLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
1421 UnicodeLabel
.Buffer
= VolumeLabel
;
1424 // Convert this to unicode. If we get any error then use a name
1428 VolumeLabelLength
= 0;
1430 if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel
,
1434 VolumeLabelLength
= UnicodeLabel
.Length
;
1438 // We need to convert from big-endian to little endian.
1443 CdConvertBigToLittleEndian( IrpContext
,
1444 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
1446 (PCHAR
) VolumeLabel
);
1448 VolumeLabelLength
= VOLUME_ID_LENGTH
;
1452 // Strip the trailing spaces or zeroes from the name.
1455 Index
= VolumeLabelLength
/ sizeof( WCHAR
);
1459 if ((VolumeLabel
[ Index
- 1 ] != L
'\0') &&
1460 (VolumeLabel
[ Index
- 1 ] != L
' ')) {
1469 // Now set the final length for the name.
1472 VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));
1475 // Now check that the label matches.
1477 if ((Vpb
->VolumeLabelLength
!= VolumeLabelLength
) ||
1478 !RtlEqualMemory( Vpb
->VolumeLabel
,
1480 VolumeLabelLength
)) {
1482 try_return( Status
= STATUS_WRONG_VOLUME
);
1489 // The volume is OK, clear the verify bit.
1492 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1494 CdMarkRealDevVerifyOk( Vpb
->RealDevice
);
1497 // See if we will need to provide notification of the remount. This is the readonly
1498 // filesystem's form of dismount/mount notification.
1501 if (FlagOn( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1503 ClearFlag( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1505 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1506 ObReferenceObject( FileObjectToNotify
);
1512 // Update the media change count to note that we have verified the volume
1513 // at this value - regardless of the outcome.
1516 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
1519 // If we got the wrong volume then free any remaining XA sector in
1520 // the current Vcb. Also mark the Vcb as not mounted.
1523 if (Status
== STATUS_WRONG_VOLUME
) {
1525 CdUpdateVcbCondition( Vcb
, VcbNotMounted
);
1527 if (Vcb
->XASector
!= NULL
) {
1529 CdFreePool( &Vcb
->XASector
);
1531 Vcb
->XADiskOffset
= 0;
1535 // Now, if there are no user handles to the volume, try to spark
1536 // teardown by purging the volume.
1539 if (Vcb
->VcbCleanup
== 0) {
1541 if (NT_SUCCESS( CdPurgeVolume( IrpContext
, Vcb
, FALSE
))) {
1543 ReleaseVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
1551 // Free the TOC buffer if allocated.
1554 if (CdromToc
!= NULL
) {
1556 CdFreePool( &CdromToc
);
1559 if (RawIsoVd
!= NULL
) {
1561 CdFreePool( &RawIsoVd
);
1566 CdReleaseVcb( IrpContext
, Vcb
);
1569 CdReleaseCdData( IrpContext
);
1573 // Now send mount notification.
1576 if (FileObjectToNotify
) {
1578 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1579 ObDereferenceObject( FileObjectToNotify
);
1583 // Complete the request if no exception.
1586 CdCompleteRequest( IrpContext
, Irp
, Status
);
1592 // Local support routine
1597 IN PIRP_CONTEXT IrpContext
,
1603 Routine Description:
1605 This is the common routine to handle oplock requests made via the
1606 NtFsControlFile call.
1610 Irp - Supplies the Irp being processed
1614 NTSTATUS - The return status for the operation
1623 ULONG OplockCount
= 0;
1624 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1629 // We only permit oplock requests on files.
1632 if (CdDecodeFileObject( IrpContext
,
1635 &Ccb
) != UserFileOpen
) {
1637 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1638 return STATUS_INVALID_PARAMETER
;
1642 // Make this a waitable Irpcontext so we don't fail to acquire
1646 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1647 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1650 // Switch on the function control code. We grab the Fcb exclusively
1651 // for oplock requests, shared for oplock break acknowledgement.
1654 switch (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
1656 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
1657 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
1658 case FSCTL_REQUEST_BATCH_OPLOCK
:
1659 case FSCTL_REQUEST_FILTER_OPLOCK
:
1661 CdAcquireFcbExclusive( IrpContext
, Fcb
, FALSE
);
1663 if (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_REQUEST_OPLOCK_LEVEL_2
) {
1665 if (Fcb
->FileLock
!= NULL
) {
1667 OplockCount
= (ULONG
) FsRtlAreThereCurrentFileLocks( Fcb
->FileLock
);
1672 OplockCount
= Fcb
->FcbCleanup
;
1677 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
1678 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
1679 case FSCTL_OPLOCK_BREAK_NOTIFY
:
1680 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
1682 CdAcquireFcbShared( IrpContext
, Fcb
, FALSE
);
1687 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1688 return STATUS_INVALID_PARAMETER
;
1692 // Use a try finally to free the Fcb.
1701 CdVerifyFcbOperation( IrpContext
, Fcb
);
1704 // Call the FsRtl routine to grant/acknowledge oplock.
1707 Status
= FsRtlOplockFsctrl( &Fcb
->Oplock
,
1712 // Set the flag indicating if Fast I/O is possible
1715 CdLockFcb( IrpContext
, Fcb
);
1716 Fcb
->IsFastIoPossible
= CdIsFastIoPossible( Fcb
);
1717 CdUnlockFcb( IrpContext
, Fcb
);
1720 // The oplock package will complete the Irp.
1728 // Release all of our resources
1731 CdReleaseFcb( IrpContext
, Fcb
);
1735 // Complete the request if there was no exception.
1738 CdCompleteRequest( IrpContext
, Irp
, Status
);
1744 // Local support routine
1749 IN PIRP_CONTEXT IrpContext
,
1755 Routine Description:
1757 This routine performs the lock volume operation. It is responsible for
1758 either completing of enqueuing the input Irp.
1762 Irp - Supplies the Irp to process
1766 NTSTATUS - The return status for the operation
1773 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1782 // Decode the file object, the only type of opens we accept are
1783 // user volume opens.
1786 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1788 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1790 return STATUS_INVALID_PARAMETER
;
1794 // Send our notification so that folks that like to hold handles on
1795 // volumes can get out of the way.
1798 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
1801 // Acquire exclusive access to the Vcb.
1805 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1813 CdVerifyVcb( IrpContext
, Vcb
);
1815 Status
= CdLockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
1823 CdReleaseVcb( IrpContext
, Vcb
);
1825 if (AbnormalTermination() || !NT_SUCCESS( Status
)) {
1827 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
1832 // Complete the request if there haven't been any exceptions.
1835 CdCompleteRequest( IrpContext
, Irp
, Status
);
1841 // Local support routine
1846 IN PIRP_CONTEXT IrpContext
,
1852 Routine Description:
1854 This routine performs the unlock volume operation. It is responsible for
1855 either completing of enqueuing the input Irp.
1859 Irp - Supplies the Irp to process
1863 NTSTATUS - The return status for the operation
1870 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1879 // Decode the file object, the only type of opens we accept are
1880 // user volume opens.
1883 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1885 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1886 return STATUS_INVALID_PARAMETER
;
1890 // Acquire exclusive access to the Vcb.
1895 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1898 // We won't check for a valid Vcb for this request. An unlock will always
1899 // succeed on a locked volume.
1902 Status
= CdUnlockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
1905 // Release all of our resources
1908 CdReleaseVcb( IrpContext
, Vcb
);
1911 // Send notification that the volume is available.
1914 if (NT_SUCCESS( Status
)) {
1916 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
1920 // Complete the request if there haven't been any exceptions.
1923 CdCompleteRequest( IrpContext
, Irp
, Status
);
1930 // Local support routine
1935 IN PIRP_CONTEXT IrpContext
,
1941 Routine Description:
1943 This routine performs the dismount volume operation. It is responsible for
1944 either completing of enqueuing the input Irp. We only dismount a volume which
1945 has been locked. The intent here is that someone has locked the volume (they are the
1946 only remaining handle). We set the verify bit here and the user will close his handle.
1947 We will dismount a volume with no user's handles in the verify path.
1951 Irp - Supplies the Irp to process
1955 NTSTATUS - The return status for the operation
1961 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1969 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1971 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1972 return STATUS_INVALID_PARAMETER
;
1978 // Make this request waitable.
1981 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1984 // Acquire exclusive access to the Vcb, and take the global resource to
1985 // sync. against mounts, verifies etc.
1988 CdAcquireCdData( IrpContext
);
1989 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1992 // Mark the volume as needs to be verified, but only do it if
1993 // the vcb is locked by this handle and the volume is currently mounted.
1996 if (Vcb
->VcbCondition
!= VcbMounted
) {
1998 Status
= STATUS_VOLUME_DISMOUNTED
;
2003 // Invalidate the volume right now.
2005 // The intent here is to make every subsequent operation
2006 // on the volume fail and grease the rails toward dismount.
2007 // By definition there is no going back from a SURPRISE.
2010 CdLockVcb( IrpContext
, Vcb
);
2012 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2014 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2017 CdUnlockVcb( IrpContext
, Vcb
);
2020 // Set flag to tell the close path that we want to force dismount
2021 // the volume when this handle is closed.
2024 SetFlag( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
);
2026 Status
= STATUS_SUCCESS
;
2030 // Release all of our resources
2033 CdReleaseVcb( IrpContext
, Vcb
);
2034 CdReleaseCdData( IrpContext
);
2037 // Complete the request if there haven't been any exceptions.
2040 CdCompleteRequest( IrpContext
, Irp
, Status
);
2046 // Local support routine
2048 NTSTATUS
/* ReactOS Change: Function did not have a type??? */
2050 IN PIRP_CONTEXT IrpContext
,
2056 Routine Description:
2058 This routine determines if a volume is currently dirty.
2062 Irp - Supplies the Irp to process
2066 NTSTATUS - The return status for the operation
2071 PIO_STACK_LOCATION IrpSp
;
2073 TYPE_OF_OPEN TypeOfOpen
;
2080 // Get the current stack location and extract the output
2081 // buffer information.
2084 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2087 // Get a pointer to the output buffer.
2090 if (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
) {
2092 VolumeState
= Irp
->AssociatedIrp
.SystemBuffer
;
2096 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_USER_BUFFER
);
2097 return STATUS_INVALID_USER_BUFFER
;
2101 // Make sure the output buffer is large enough and then initialize
2102 // the answer to be that the volume isn't dirty.
2105 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
)) {
2107 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2108 return STATUS_INVALID_PARAMETER
;
2114 // Decode the file object
2117 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2119 if (TypeOfOpen
!= UserVolumeOpen
) {
2121 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2122 return STATUS_INVALID_PARAMETER
;
2125 if (Fcb
->Vcb
->VcbCondition
!= VcbMounted
) {
2127 CdCompleteRequest( IrpContext
, Irp
, STATUS_VOLUME_DISMOUNTED
);
2128 return STATUS_VOLUME_DISMOUNTED
;
2132 // Now set up to return the clean state. CDs obviously can never be dirty
2133 // but we want to make sure we have enforced the full semantics of this call.
2136 Irp
->IoStatus
.Information
= sizeof( ULONG
);
2138 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2139 return STATUS_SUCCESS
;
2144 // Local support routine
2149 IN PIRP_CONTEXT IrpContext
,
2155 Routine Description:
2157 This routine determines if a volume is currently mounted.
2161 Irp - Supplies the Irp to process
2165 NTSTATUS - The return status for the operation
2170 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2178 // Decode the file object.
2181 CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2186 // Disable PopUps, we want to return any error.
2189 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
2192 // Verify the Vcb. This will raise in the error condition.
2195 CdVerifyVcb( IrpContext
, Fcb
->Vcb
);
2198 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2200 return STATUS_SUCCESS
;
2205 // Local support routine
2210 IN PIRP_CONTEXT IrpContext
,
2216 Routine Description:
2218 This routine determines if pathname is a valid CDFS pathname.
2219 We always succeed this request.
2223 Irp - Supplies the Irp to process.
2234 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2235 return STATUS_SUCCESS
;
2240 // Local support routine
2244 CdInvalidateVolumes (
2245 IN PIRP_CONTEXT IrpContext
,
2251 Routine Description:
2253 This routine searches for all the volumes mounted on the same real device
2254 of the current DASD handle, and marks them all bad. The only operation
2255 that can be done on such handles is cleanup and close.
2259 Irp - Supplies the Irp to process
2263 NTSTATUS - The return status for the operation
2269 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2272 BOOLEAN UnlockVcb
= FALSE
;
2274 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
2282 PFILE_OBJECT FileToMarkBad
;
2283 PDEVICE_OBJECT DeviceToMarkBad
;
2286 // We only allow the invalidate call to come in on our file system devices.
2290 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
2292 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
&&
2293 IrpSp
->DeviceObject
!= CdData
.HddFileSystemDeviceObject
) {
2296 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
2298 return STATUS_INVALID_DEVICE_REQUEST
;
2302 // Check for the correct security access.
2303 // The caller must have the SeTcbPrivilege.
2306 if (!SeSinglePrivilegeCheck( TcbPrivilege
, Irp
->RequestorMode
)) {
2308 CdCompleteRequest( IrpContext
, Irp
, STATUS_PRIVILEGE_NOT_HELD
);
2310 return STATUS_PRIVILEGE_NOT_HELD
;
2314 // Try to get a pointer to the device object from the handle passed in.
2318 if (IoIs32bitProcess( Irp
)) {
2320 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( UINT32
)) {
2322 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2323 return STATUS_INVALID_PARAMETER
;
2326 Handle
= (HANDLE
) LongToHandle( *((PUINT32
) Irp
->AssociatedIrp
.SystemBuffer
) );
2330 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( HANDLE
)) {
2332 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2333 return STATUS_INVALID_PARAMETER
;
2335 Handle
= *((PHANDLE
) Irp
->AssociatedIrp
.SystemBuffer
);
2340 Status
= ObReferenceObjectByHandle( Handle
,
2344 (PVOID
*)&FileToMarkBad
, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
2347 if (!NT_SUCCESS(Status
)) {
2349 CdCompleteRequest( IrpContext
, Irp
, Status
);
2354 // Grab the DeviceObject from the FileObject.
2357 DeviceToMarkBad
= FileToMarkBad
->DeviceObject
;
2360 // We only needed the device object involved, not a reference to the file.
2363 ObDereferenceObject( FileToMarkBad
);
2366 // Make sure this request can wait.
2369 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2370 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
2373 // Synchronise with pnp/mount/verify paths.
2376 CdAcquireCdData( IrpContext
);
2379 // Nothing can go wrong now.
2383 // Now walk through all the mounted Vcb's looking for candidates to
2386 // On volumes we mark invalid, check for dismount possibility (which is
2387 // why we have to get the next link so early).
2390 Links
= CdData
.VcbQueue
.Flink
;
2392 while (Links
!= &CdData
.VcbQueue
) {
2394 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2396 Links
= Links
->Flink
;
2399 // If we get a match, mark the volume Bad, and also check to
2400 // see if the volume should go away.
2403 CdLockVcb( IrpContext
, Vcb
);
2405 if (Vcb
->Vpb
->RealDevice
== DeviceToMarkBad
) {
2408 // Take the VPB spinlock, and look to see if this volume is the
2409 // one currently mounted on the actual device. If it is, pull it
2413 IoAcquireVpbSpinLock( &SavedIrql
);
2415 if (DeviceToMarkBad
->Vpb
== Vcb
->Vpb
) {
2417 PVPB NewVpb
= Vcb
->SwapVpb
;
2419 ASSERT( FlagOn( Vcb
->Vpb
->Flags
, VPB_MOUNTED
));
2420 ASSERT( NULL
!= NewVpb
);
2422 RtlZeroMemory( NewVpb
, sizeof( VPB
) );
2424 NewVpb
->Type
= IO_TYPE_VPB
;
2425 NewVpb
->Size
= sizeof( VPB
);
2426 NewVpb
->RealDevice
= DeviceToMarkBad
;
2427 NewVpb
->Flags
= FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_REMOVE_PENDING
);
2429 DeviceToMarkBad
->Vpb
= NewVpb
;
2430 Vcb
->SwapVpb
= NULL
;
2433 IoReleaseVpbSpinLock( SavedIrql
);
2435 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2437 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2440 CdUnlockVcb( IrpContext
, Vcb
);
2442 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2444 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
2446 UnlockVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2450 CdReleaseVcb( IrpContext
, Vcb
);
2455 CdUnlockVcb( IrpContext
, Vcb
);
2459 CdReleaseCdData( IrpContext
);
2461 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2462 return STATUS_SUCCESS
;
2467 // Local support routine
2471 CdScanForDismountedVcb (
2472 IN PIRP_CONTEXT IrpContext
2477 Routine Description:
2479 This routine walks through the list of Vcb's looking for any which may
2480 now be deleted. They may have been left on the list because there were
2481 outstanding references.
2498 // Walk through all of the Vcb's attached to the global data.
2501 Links
= CdData
.VcbQueue
.Flink
;
2503 while (Links
!= &CdData
.VcbQueue
) {
2505 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2508 // Move to the next link now since the current Vcb may be deleted.
2511 Links
= Links
->Flink
;
2514 // If dismount is already underway then check if this Vcb can
2518 if ((Vcb
->VcbCondition
== VcbDismountInProgress
) ||
2519 (Vcb
->VcbCondition
== VcbInvalid
) ||
2520 ((Vcb
->VcbCondition
== VcbNotMounted
) && (Vcb
->VcbReference
<= CDFS_RESIDUAL_REFERENCE
))) {
2522 CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2531 // Local support routine
2536 IN PIRP_CONTEXT IrpContext
,
2539 IN ULONG BlockFactor
,
2540 IN BOOLEAN ReturnOnError
,
2541 IN BOOLEAN VerifyVolume
2546 Routine Description:
2548 This routine is called to walk through the volume descriptors looking
2549 for a primary volume descriptor. When/if a primary is found a 32-bit
2550 serial number is generated and stored into the Vpb. We also store the
2551 location of the primary volume descriptor in the Vcb.
2555 Vcb - Pointer to the VCB for the volume.
2557 RawIsoVd - Pointer to a sector buffer which will contain the primary
2558 volume descriptor on exit, if successful.
2560 BlockFactor - Block factor used by the current device for the TableOfContents.
2562 ReturnOnError - Indicates that we should raise on I/O errors rather than
2563 returning a FALSE value.
2565 VerifyVolume - Indicates if we were called from the verify path. We
2566 do a few things different in this path. We don't update the Vcb in
2571 BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
2579 BOOLEAN FoundVd
= FALSE
;
2584 PCDROM_TOC CdromToc
;
2591 // If there are no data tracks, don't even bother hunting for descriptors.
2593 // This explicitly breaks various non-BlueBook compliant CDs that scribble
2594 // an ISO filesystem on media claiming only audio tracks. Since these
2595 // disks can cause serious problems in some CDROM units, fail fast. I admit
2596 // that it is possible that someone can still record the descriptors in the
2597 // audio track, record a data track (but fail to record descriptors there)
2598 // and still have the disk work. As this form of error worked in NT 4.0, and
2599 // since these disks really do exist, I don't want to change them.
2601 // If we wished to support all such media (we don't), it would be necessary
2602 // to clear this flag on finding ISO or HSG descriptors below.
2605 if (FlagOn(Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2611 // We will make at most two passes through the volume descriptor sequence.
2613 // On the first pass we will query for the last session. Using this
2614 // as a starting offset we will attempt to mount the volume. On any failure
2615 // we will go to the second pass and try without using any multi-session
2618 // On the second pass we will start offset from sector zero.
2621 while (!FoundVd
&& (ThisPass
<= 2)) {
2624 // If we aren't at pass 1 then we start at sector 0. Otherwise we
2625 // try to look up the multi-session information.
2630 if (ThisPass
== 1) {
2635 // Check for whether this device supports XA and multi-session.
2641 // Allocate a buffer for the last session information.
2644 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
2645 sizeof( CDROM_TOC
),
2648 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC
));
2651 // Query the last session information from the driver.
2654 Status
= CdPerformDevIoCtrl( IrpContext
,
2655 IOCTL_CDROM_GET_LAST_SESSION
,
2656 Vcb
->TargetDeviceObject
,
2658 sizeof( CDROM_TOC
),
2664 // Raise an exception if there was an allocation failure.
2667 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
2669 CdRaiseStatus( IrpContext
, Status
);
2673 // We don't handle any errors yet. We will hit that below
2674 // as we try to scan the disk. If we have last session information
2675 // then modify the base sector.
2678 if (NT_SUCCESS( Status
) &&
2679 (CdromToc
->FirstTrack
!= CdromToc
->LastTrack
)) {
2687 // The track address is BigEndian, we need to flip the bytes.
2690 Source
= (PCHAR
) &CdromToc
->TrackData
[0].Address
[3];/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
2691 Dest
= (PCHAR
) &BaseSector
; /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
2695 *Dest
++ = *Source
--;
2700 // Now adjust the base sector by the block factor of the
2704 BaseSector
/= BlockFactor
;
2707 // Make this look like the second pass since we are only using the
2708 // first session. No reason to retry on error.
2718 if (CdromToc
!= NULL
) { CdFreePool( &CdromToc
); }
2723 // Compute the starting sector offset from the start of the session.
2726 SectorOffset
= FIRST_VD_SECTOR
;
2729 // Start by assuming we have neither Hsg or Iso volumes.
2735 // Loop until either error encountered, primary volume descriptor is
2736 // found or a terminal volume descriptor is found.
2742 // Attempt to read the desired sector. Exit directly if operation
2745 // If this is pass 1 we will ignore errors in read sectors and just
2746 // go to the next pass.
2749 if (!CdReadSectors( IrpContext
,
2750 LlBytesFromSectors( BaseSector
+ SectorOffset
),
2752 (BOOLEAN
) ((ThisPass
== 1) || ReturnOnError
),
2754 Vcb
->TargetDeviceObject
)) {
2760 // Check if either an ISO or HSG volume.
2763 if (RtlEqualMemory( CdIsoId
,
2764 CdRvdId( RawIsoVd
, VCB_STATE_ISO
),
2767 SetFlag( VolumeFlags
, VCB_STATE_ISO
);
2769 } else if (RtlEqualMemory( CdHsgId
,
2770 CdRvdId( RawIsoVd
, VCB_STATE_HSG
),
2773 SetFlag( VolumeFlags
, VCB_STATE_HSG
);
2776 // We have neither so break out of the loop.
2785 // Break out if the version number is incorrect or this is
2789 if ((CdRvdVersion( RawIsoVd
, VolumeFlags
) != VERSION_1
) ||
2790 (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_TERMINATOR
)) {
2796 // If this is a primary volume descriptor then our search is over.
2799 if (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_PRIMARY
) {
2802 // If we are not in the verify path then initialize the
2803 // fields in the Vcb with basic information from this
2807 if (!VerifyVolume
) {
2810 // Set the flag for the volume type.
2813 SetFlag( Vcb
->VcbState
, VolumeFlags
);
2816 // Store the base sector and sector offset for the
2817 // primary volume descriptor.
2820 Vcb
->BaseSector
= BaseSector
;
2821 Vcb
->VdSectorOffset
= SectorOffset
;
2822 Vcb
->PrimaryVdSectorOffset
= SectorOffset
;
2830 // Indicate that we're at the next sector.
2844 // Local support routine
2849 IN PIRP_CONTEXT IrpContext
,
2855 Routine Description:
2857 This routine walks through the links of the Vcb chain in the global
2858 data structure. The remount condition is met when the following
2859 conditions are all met:
2861 If the new Vcb is a device only Mvcb and there is a previous
2864 Otherwise following conditions must be matched.
2866 1 - The 32 serial in the current VPB matches that in a previous
2869 2 - The volume label in the Vpb matches that in the previous
2872 3 - The system pointer to the real device object in the current
2873 VPB matches that in the same previous VPB.
2875 4 - Finally the previous Vcb cannot be invalid or have a dismount
2878 If a VPB is found which matches these conditions, then the address of
2879 the VCB for that VPB is returned via the pointer Vcb.
2881 Skip over the current Vcb.
2885 Vcb - This is the Vcb we are checking for a remount.
2887 OldVcb - A pointer to the address to store the address for the Vcb
2888 for the volume if this is a remount. (This is a pointer to
2893 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
2900 PVPB Vpb
= Vcb
->Vpb
;
2903 BOOLEAN Remount
= FALSE
;
2908 // Check whether we are looking for a device only Mvcb.
2911 for (Link
= CdData
.VcbQueue
.Flink
;
2912 Link
!= &CdData
.VcbQueue
;
2913 Link
= Link
->Flink
) {
2915 *OldVcb
= CONTAINING_RECORD( Link
, VCB
, VcbLinks
);
2921 if (Vcb
== *OldVcb
) { continue; }
2924 // Look at the Vpb and state of the previous Vcb.
2927 OldVpb
= (*OldVcb
)->Vpb
;
2929 if ((OldVpb
!= Vpb
) &&
2930 (OldVpb
->RealDevice
== Vpb
->RealDevice
) &&
2931 ((*OldVcb
)->VcbCondition
== VcbNotMounted
)) {
2934 // If the current disk is a raw disk then it can match a previous music or
2938 if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2940 if (FlagOn( (*OldVcb
)->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2943 // If we have both TOC then fail the remount if the lengths
2944 // are different or they don't match.
2947 if ((Vcb
->TocLength
!= (*OldVcb
)->TocLength
) ||
2948 ((Vcb
->TocLength
!= 0) &&
2949 !RtlEqualMemory( Vcb
->CdromToc
,
2950 (*OldVcb
)->CdromToc
,
2951 Vcb
->TocLength
))) {
2961 // The current disk is not a raw disk. Go ahead and compare
2962 // serial numbers and volume label.
2965 } else if ((OldVpb
->SerialNumber
== Vpb
->SerialNumber
) &&
2966 (Vpb
->VolumeLabelLength
== OldVpb
->VolumeLabelLength
) &&
2967 (RtlEqualMemory( OldVpb
->VolumeLabel
,
2969 Vpb
->VolumeLabelLength
))) {
2972 // Remember the old mvcb. Then set the return value to
2987 // Local support routine
2991 CdFindActiveVolDescriptor (
2992 IN PIRP_CONTEXT IrpContext
,
2994 IN OUT PCHAR RawIsoVd
,
2995 IN BOOLEAN VerifyVolume
3000 Routine Description:
3002 This routine is called to search for a valid secondary volume descriptor that
3003 we will support. Right now we only support Joliet escape sequences for
3004 the secondary descriptor.
3006 If we don't find the secondary descriptor then we will reread the primary.
3008 This routine will update the serial number and volume label in the Vpb.
3012 Vcb - This is the Vcb for the volume being mounted.
3014 RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
3015 on input should contain the PVD (ISO) in the SECOND 'sector' of the
3018 VerifyVolume - indicates we are being called by the verify path, and should
3019 not modify the Vcb fields.
3028 BOOLEAN FoundSecondaryVd
= FALSE
;
3029 ULONG SectorOffset
= FIRST_VD_SECTOR
;
3038 // We only look for secondary volume descriptors on an Iso disk.
3041 if ((FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
) || VerifyVolume
) && !CdNoJoliet
) {
3044 // Scan the volume descriptors from the beginning looking for a valid
3045 // secondary or a terminator.
3048 SectorOffset
= FIRST_VD_SECTOR
;
3053 // Read the next sector. We should never have an error in this
3057 CdReadSectors( IrpContext
,
3058 LlBytesFromSectors( Vcb
->BaseSector
+ SectorOffset
),
3062 Vcb
->TargetDeviceObject
);
3065 // Break out if the version number or standard Id is incorrect.
3066 // Also break out if this is a terminator.
3069 if (!RtlEqualMemory( CdIsoId
, CdRvdId( RawIsoVd
, VCB_STATE_JOLIET
), VOL_ID_LEN
) ||
3070 (CdRvdVersion( RawIsoVd
, VCB_STATE_JOLIET
) != VERSION_1
) ||
3071 (CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_TERMINATOR
)) {
3077 // We have a match if this is a secondary descriptor with a matching
3081 if ((CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_SECONDARY
) &&
3082 (RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3085 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3088 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3092 if (!VerifyVolume
) {
3095 // Update the Vcb with the new volume descriptor.
3098 ClearFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
3099 SetFlag( Vcb
->VcbState
, VCB_STATE_JOLIET
);
3101 Vcb
->VdSectorOffset
= SectorOffset
;
3104 FoundSecondaryVd
= TRUE
;
3109 // Otherwise move on to the next sector.
3116 // If we didn't find the secondary then recover the original volume
3117 // descriptor stored in the second half of the RawIsoVd.
3120 if (!FoundSecondaryVd
) {
3122 RtlCopyMemory( RawIsoVd
,
3123 Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
3129 // If we're in the verify path, our work is done, since we don't want
3130 // to update any Vcb/Vpb values.
3139 // Compute the serial number and volume label from the volume descriptor.
3142 Vcb
->Vpb
->SerialNumber
= CdSerial32( RawIsoVd
, SECTOR_SIZE
);
3145 // Make sure the CD label will fit in the Vpb.
3148 ASSERT( VOLUME_ID_LENGTH
* sizeof( WCHAR
) <= MAXIMUM_VOLUME_LABEL_LENGTH
);
3151 // If this is not a Unicode label we must convert it to unicode.
3154 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
3157 // Convert the label to unicode. If we get any error then use a name
3161 Vcb
->Vpb
->VolumeLabelLength
= 0;
3163 if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb
->Vpb
->VolumeLabel
[0],
3164 MAXIMUM_VOLUME_LABEL_LENGTH
,
3166 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
3167 VOLUME_ID_LENGTH
))) {
3169 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) Length
;
3173 // We need to convert from big-endian to little endian.
3178 CdConvertBigToLittleEndian( IrpContext
,
3179 (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
3181 (PCHAR
) Vcb
->Vpb
->VolumeLabel
);
3183 Vcb
->Vpb
->VolumeLabelLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
3187 // Strip the trailing spaces or zeroes from the name.
3190 Index
= Vcb
->Vpb
->VolumeLabelLength
/ sizeof( WCHAR
);
3194 if ((Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
'\0') &&
3195 (Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
' ')) {
3204 // Now set the final length for the name.
3207 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));