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
36 _Requires_lock_held_(_Global_critical_region_
)
39 _Inout_ PIRP_CONTEXT IrpContext
,
45 _In_ PIRP_CONTEXT IrpContext
,
48 _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo
51 _Requires_lock_held_(_Global_critical_region_
)
54 _Inout_ PIRP_CONTEXT IrpContext
,
58 _Requires_lock_held_(_Global_critical_region_
)
61 _Inout_ PIRP_CONTEXT IrpContext
,
65 _Requires_lock_held_(_Global_critical_region_
)
68 _Inout_ PIRP_CONTEXT IrpContext
,
72 _Requires_lock_held_(_Global_critical_region_
)
75 _Inout_ PIRP_CONTEXT IrpContext
,
79 _Requires_lock_held_(_Global_critical_region_
)
82 _Inout_ PIRP_CONTEXT IrpContext
,
86 _Requires_lock_held_(_Global_critical_region_
)
89 _Inout_ PIRP_CONTEXT IrpContext
,
95 _Inout_ PIRP_CONTEXT IrpContext
,
101 _Inout_ PIRP_CONTEXT IrpContext
,
107 _Inout_ PIRP_CONTEXT IrpContext
,
111 _Requires_lock_held_(_Global_critical_region_
)
113 CdInvalidateVolumes (
114 _Inout_ PIRP_CONTEXT IrpContext
,
119 CdAllowExtendedDasdIo (
120 _Inout_ PIRP_CONTEXT IrpContext
,
124 _Requires_lock_held_(_Global_critical_region_
)
126 CdScanForDismountedVcb (
127 _Inout_ PIRP_CONTEXT IrpContext
130 _Success_(return != FALSE
)
133 _In_ PIRP_CONTEXT IrpContext
,
135 _Out_writes_bytes_(SECTOR_SIZE
) PCHAR RawIsoVd
,
136 _In_ ULONG BlockFactor
,
137 _In_ BOOLEAN ReturnOnError
,
138 _In_ BOOLEAN VerifyVolume
141 _Success_(return != FALSE
) BOOLEAN
143 _In_ PIRP_CONTEXT IrpContext
,
149 CdFindActiveVolDescriptor (
150 _In_ PIRP_CONTEXT IrpContext
,
152 _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE
)) PCHAR RawIsoVd
,
153 _In_ BOOLEAN VerifyVolume
157 #pragma alloc_text(PAGE, CdCommonFsControl)
158 #pragma alloc_text(PAGE, CdDismountVolume)
159 #pragma alloc_text(PAGE, CdFindActiveVolDescriptor)
160 #pragma alloc_text(PAGE, CdFindPrimaryVd)
161 #pragma alloc_text(PAGE, CdIsPathnameValid)
162 #pragma alloc_text(PAGE, CdIsRemount)
163 #pragma alloc_text(PAGE, CdIsVolumeDirty)
164 #pragma alloc_text(PAGE, CdIsVolumeMounted)
165 #pragma alloc_text(PAGE, CdLockVolume)
166 #pragma alloc_text(PAGE, CdMountVolume)
167 #pragma alloc_text(PAGE, CdOplockRequest)
168 #pragma alloc_text(PAGE, CdAllowExtendedDasdIo)
169 #pragma alloc_text(PAGE, CdScanForDismountedVcb)
170 #pragma alloc_text(PAGE, CdUnlockVolume)
171 #pragma alloc_text(PAGE, CdUserFsctl)
172 #pragma alloc_text(PAGE, CdVerifyVolume)
177 // Local support routine
180 _Requires_lock_held_(_Global_critical_region_
)
181 _Requires_lock_held_(Vcb
->VcbResource
)
183 CdLockVolumeInternal (
184 _In_ PIRP_CONTEXT IrpContext
,
186 _In_opt_ PFILE_OBJECT FileObject
193 This routine performs the actual lock volume operation. It will be called
194 by anyone wishing to try to protect the volume for a long duration. PNP
195 operations are such a user.
197 The volume must be held exclusive by the caller.
201 Vcb - The volume being locked.
203 FileObject - File corresponding to the handle locking the volume. If this
204 is not specified, a system lock is assumed.
208 NTSTATUS - The return status for the operation
215 NTSTATUS FinalStatus
= (FileObject
? STATUS_ACCESS_DENIED
: STATUS_DEVICE_BUSY
);
216 ULONG RemainingUserReferences
= (FileObject
? 1: 0);
219 // The cleanup count for the volume only reflects the fileobject that
220 // will lock the volume. Otherwise, we must fail the request.
222 // Since the only cleanup is for the provided fileobject, we will try
223 // to get rid of all of the other user references. If there is only one
224 // remaining after the purge then we can allow the volume to be locked.
227 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
230 // Now back out of our synchronization and wait for the lazy writer
231 // to finish off any lazy closes that could have been outstanding.
233 // Since we purged, we know that the lazy writer will issue all
234 // possible lazy closes in the next tick - if we hadn't, an otherwise
235 // unopened file with a large amount of dirty data could have hung
236 // around for a while as the data trickled out to the disk.
238 // This is even more important now since we send notification to
239 // alert other folks that this style of check is about to happen so
240 // that they can close their handles. We don't want to enter a fast
241 // race with the lazy writer tearing down his references to the file.
244 CdReleaseVcb( IrpContext
, Vcb
);
246 Status
= CcWaitForCurrentLazyWriterActivity();
249 // This is intentional. If we were able to get the Vcb before, just
250 // wait for it and take advantage of knowing that it is OK to leave
254 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
255 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
257 if (!NT_SUCCESS( Status
)) {
265 // If the volume is already explicitly locked then fail. We use the
266 // Vpb locked flag as an 'explicit lock' flag in the same way as Fat.
269 IoAcquireVpbSpinLock( &SavedIrql
);
271 if (!FlagOn( Vcb
->Vpb
->Flags
, VPB_LOCKED
) &&
272 (Vcb
->VcbCleanup
== RemainingUserReferences
) &&
273 (Vcb
->VcbUserReference
== CDFS_RESIDUAL_USER_REFERENCE
+ RemainingUserReferences
)) {
275 SetFlag( Vcb
->VcbState
, VCB_STATE_LOCKED
);
276 SetFlag( Vcb
->Vpb
->Flags
, VPB_LOCKED
);
277 Vcb
->VolumeLockFileObject
= FileObject
;
278 FinalStatus
= STATUS_SUCCESS
;
281 IoReleaseVpbSpinLock( SavedIrql
);
288 CdUnlockVolumeInternal (
289 _In_ PIRP_CONTEXT IrpContext
,
291 _In_opt_ PFILE_OBJECT FileObject
298 This routine performs the actual unlock volume operation.
300 The volume must be held exclusive by the caller.
304 Vcb - The volume being locked.
306 FileObject - File corresponding to the handle locking the volume. If this
307 is not specified, a system lock is assumed.
311 NTSTATUS - The return status for the operation
313 Attempting to remove a system lock that did not exist is OK.
318 NTSTATUS Status
= STATUS_NOT_LOCKED
;
321 UNREFERENCED_PARAMETER( IrpContext
);
324 // Note that we check the VPB_LOCKED flag here rather than the Vcb
325 // lock flag. The Vpb flag is only set for an explicit lock request, not
326 // for the implicit lock obtained on a volume open with zero share mode.
329 IoAcquireVpbSpinLock( &SavedIrql
);
331 if (FlagOn(Vcb
->Vpb
->Flags
, VPB_LOCKED
) &&
332 (FileObject
== Vcb
->VolumeLockFileObject
)) {
334 ClearFlag( Vcb
->VcbState
, VCB_STATE_LOCKED
);
335 ClearFlag( Vcb
->Vpb
->Flags
, VPB_LOCKED
);
336 Vcb
->VolumeLockFileObject
= NULL
;
337 Status
= STATUS_SUCCESS
;
340 IoReleaseVpbSpinLock( SavedIrql
);
347 _Requires_lock_held_(_Global_critical_region_
)
350 _Inout_ PIRP_CONTEXT IrpContext
,
358 This is the common routine for doing FileSystem control operations called
359 by both the fsd and fsp threads
363 Irp - Supplies the Irp to process
367 NTSTATUS - The return status for the operation
373 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
378 // We know this is a file system control so we'll case on the
379 // minor function, and call a internal worker routine to complete
383 switch (IrpSp
->MinorFunction
) {
385 case IRP_MN_USER_FS_REQUEST
:
387 Status
= CdUserFsctl( IrpContext
, Irp
);
390 case IRP_MN_MOUNT_VOLUME
:
392 Status
= CdMountVolume( IrpContext
, Irp
);
395 case IRP_MN_VERIFY_VOLUME
:
397 Status
= CdVerifyVolume( IrpContext
, Irp
);
402 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
403 Status
= STATUS_INVALID_DEVICE_REQUEST
;
412 // Local support routine
415 _Requires_lock_held_(_Global_critical_region_
)
418 _Inout_ PIRP_CONTEXT IrpContext
,
425 This is the common routine for implementing the user's requests made
426 through NtFsControlFile.
430 Irp - Supplies the Irp being processed
434 NTSTATUS - The return status for the operation
440 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
445 // Case on the control code.
448 switch ( IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
450 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
451 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
452 case FSCTL_REQUEST_BATCH_OPLOCK
:
453 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
454 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
455 case FSCTL_OPLOCK_BREAK_NOTIFY
:
456 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
457 case FSCTL_REQUEST_FILTER_OPLOCK
:
459 Status
= CdOplockRequest( IrpContext
, Irp
);
462 case FSCTL_LOCK_VOLUME
:
464 Status
= CdLockVolume( IrpContext
, Irp
);
467 case FSCTL_UNLOCK_VOLUME
:
469 Status
= CdUnlockVolume( IrpContext
, Irp
);
472 case FSCTL_DISMOUNT_VOLUME
:
474 Status
= CdDismountVolume( IrpContext
, Irp
);
477 case FSCTL_IS_VOLUME_DIRTY
:
479 Status
= CdIsVolumeDirty( IrpContext
, Irp
);
482 case FSCTL_IS_VOLUME_MOUNTED
:
484 Status
= CdIsVolumeMounted( IrpContext
, Irp
);
487 case FSCTL_IS_PATHNAME_VALID
:
489 Status
= CdIsPathnameValid( IrpContext
, Irp
);
492 case FSCTL_INVALIDATE_VOLUMES
:
494 Status
= CdInvalidateVolumes( IrpContext
, Irp
);
497 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
499 Status
= CdAllowExtendedDasdIo( IrpContext
, Irp
);
503 // We don't support any of the known or unknown requests.
508 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
509 Status
= STATUS_INVALID_DEVICE_REQUEST
;
519 _In_ PIRP_CONTEXT IrpContext
,
522 _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo
529 UNREFERENCED_PARAMETER( IrpContext
);
531 ObDereferenceObject( OldVcb
->TargetDeviceObject
);
533 IoAcquireVpbSpinLock( &SavedIrql
);
536 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed")
538 NewVcb
->Vpb
->RealDevice
->Vpb
= OldVcb
->Vpb
;
540 OldVcb
->Vpb
->RealDevice
= NewVcb
->Vpb
->RealDevice
;
541 OldVcb
->TargetDeviceObject
= DeviceObjectWeTalkTo
;
543 CdUpdateVcbCondition( OldVcb
, VcbMounted
);
544 CdUpdateMediaChangeCount( OldVcb
, NewVcb
->MediaChangeCount
);
546 ClearFlag( OldVcb
->VcbState
, VCB_STATE_VPB_NOT_ON_DEVICE
);
548 Buffer
= OldVcb
->SectorCacheBuffer
= NewVcb
->SectorCacheBuffer
;
549 NewVcb
->SectorCacheBuffer
= NULL
;
551 if (NULL
!= Buffer
) {
553 for (Index
= 0; Index
< CD_SEC_CACHE_CHUNKS
; Index
++) {
555 OldVcb
->SecCacheChunks
[ Index
].Buffer
= Buffer
;
556 OldVcb
->SecCacheChunks
[ Index
].BaseLbn
= (ULONG
)-1;
558 Buffer
+= CD_SEC_CHUNK_BLOCKS
* SECTOR_SIZE
;
562 IoReleaseVpbSpinLock( SavedIrql
);
567 // Local support routine
570 _Requires_lock_held_(_Global_critical_region_
)
573 _Inout_ PIRP_CONTEXT IrpContext
,
581 This routine performs the mount volume operation. It is responsible for
582 either completing of enqueuing the input Irp.
584 Its job is to verify that the volume denoted in the IRP is a Cdrom volume,
585 and create the VCB and root DCB structures. The algorithm it
586 uses is essentially as follows:
588 1. Create a new Vcb Structure, and initialize it enough to do I/O
589 through the on-disk volume descriptors.
591 2. Read the disk and check if it is a Cdrom volume.
593 3. If it is not a Cdrom volume then delete the Vcb and
594 complete the IRP back with an appropriate status.
596 4. Check if the volume was previously mounted and if it was then do a
597 remount operation. This involves deleting the VCB, hook in the
598 old VCB, and complete the IRP.
600 5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
604 Irp - Supplies the Irp to process
608 NTSTATUS - The return status for the operation
615 PVOLUME_DEVICE_OBJECT VolDo
= NULL
;
620 BOOLEAN FoundPvd
= FALSE
;
621 BOOLEAN SetDoVerifyOnFail
;
623 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
624 PDEVICE_OBJECT DeviceObjectWeTalkTo
= IrpSp
->Parameters
.MountVolume
.DeviceObject
;
625 PVPB Vpb
= IrpSp
->Parameters
.MountVolume
.Vpb
;
627 PFILE_OBJECT FileObjectToNotify
= NULL
;
630 DISK_GEOMETRY DiskGeometry
;
632 IO_SCSI_CAPABILITIES Capabilities
;
634 IO_STATUS_BLOCK Iosb
;
636 PCHAR RawIsoVd
= NULL
;
638 PCDROM_TOC_LARGE CdromToc
= NULL
;
640 ULONG TocTrackCount
= 0;
641 ULONG TocDiskFlags
= 0;
642 ULONG MediaChangeCount
= 0;
645 DEVICE_TYPE FilesystemDeviceType
;
648 #ifdef CDFS_TELEMETRY_DATA
650 GUID VolumeCorrelationId
= { 0 };
656 // Check that we are talking to a Cdrom device. This request should
657 // always be waitable.
661 if (IrpSp
->DeviceObject
== CdData
.HddFileSystemDeviceObject
) {
662 FilesystemDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
665 NT_ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
667 FilesystemDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
670 NT_ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
672 #ifdef CDFS_TELEMETRY_DATA
674 // We don't want a bogus VolumeGuid to show up in our telemetry
677 RtlZeroMemory( &VolumeGuid
, sizeof(GUID
) );
682 // Update the real device in the IrpContext from the Vpb. There was no available
683 // file object when the IrpContext was created.
686 IrpContext
->RealDevice
= Vpb
->RealDevice
;
688 SetDoVerifyOnFail
= CdRealDevNeedsVerify( IrpContext
->RealDevice
);
691 // Check if we have disabled the mount process.
696 CdCompleteRequest( IrpContext
, Irp
, STATUS_UNRECOGNIZED_VOLUME
);
697 return STATUS_UNRECOGNIZED_VOLUME
;
701 // If we've shutdown disallow further mounts.
704 if (FlagOn( CdData
.Flags
, CD_FLAGS_SHUTDOWN
)) {
706 CdCompleteRequest( IrpContext
, Irp
, STATUS_SYSTEM_SHUTDOWN
);
707 return STATUS_SYSTEM_SHUTDOWN
;
711 // Do a CheckVerify here to lift the MediaChange ticker from the driver
714 Status
= CdPerformDevIoCtrl( IrpContext
,
716 IOCTL_CDROM_CHECK_VERIFY
,
718 (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
? IOCTL_DISK_CHECK_VERIFY
: IOCTL_CDROM_CHECK_VERIFY
),
720 DeviceObjectWeTalkTo
,
727 if (!NT_SUCCESS( Status
)) {
729 CdCompleteRequest( IrpContext
, Irp
, Status
);
733 if (Iosb
.Information
!= sizeof(ULONG
)) {
736 // Be safe about the count in case the driver didn't fill it in
739 MediaChangeCount
= 0;
743 // Now let's make Jeff delirious and call to get the disk geometry. This
744 // will fix the case where the first change line is swallowed.
747 Status
= CdPerformDevIoCtrl( IrpContext
,
749 IOCTL_CDROM_GET_DRIVE_GEOMETRY
,
751 (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
? IOCTL_DISK_GET_DRIVE_GEOMETRY
: IOCTL_CDROM_GET_DRIVE_GEOMETRY
),
753 DeviceObjectWeTalkTo
,
755 sizeof( DISK_GEOMETRY
),
761 // Return insufficient sources to our caller.
764 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
766 CdCompleteRequest( IrpContext
, Irp
, Status
);
771 // Now check the block factor for addressing the volume descriptors.
772 // If the call for the disk geometry failed then assume there is one
778 if (NT_SUCCESS( Status
) &&
779 (DiskGeometry
.BytesPerSector
!= 0) &&
780 (DiskGeometry
.BytesPerSector
< SECTOR_SIZE
)) {
782 BlockFactor
= SECTOR_SIZE
/ DiskGeometry
.BytesPerSector
;
786 // Acquire the global resource to do mount operations.
789 CdAcquireCdData( IrpContext
);
792 // Use a try-finally to facilitate cleanup.
798 // Allocate a buffer to query the TOC.
801 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
802 sizeof( CDROM_TOC_LARGE
),
805 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC_LARGE
));
808 // Do a quick check to see if there any Vcb's which can be removed.
811 CdScanForDismountedVcb( IrpContext
);
814 // Get our device object and alignment requirement.
817 Status
= IoCreateDevice( CdData
.DriverObject
,
818 sizeof( VOLUME_DEVICE_OBJECT
) - sizeof( DEVICE_OBJECT
),
821 FILE_DEVICE_CD_ROM_FILE_SYSTEM
,
823 FilesystemDeviceType
,
827 (PDEVICE_OBJECT
*) &VolDo
);
829 if (!NT_SUCCESS( Status
)) { try_leave( Status
); }
832 // Our alignment requirement is the larger of the processor alignment requirement
833 // already in the volume device object and that in the DeviceObjectWeTalkTo
836 if (DeviceObjectWeTalkTo
->AlignmentRequirement
> VolDo
->DeviceObject
.AlignmentRequirement
) {
838 VolDo
->DeviceObject
.AlignmentRequirement
= DeviceObjectWeTalkTo
->AlignmentRequirement
;
842 // We must initialize the stack size in our device object before
843 // the following reads, because the I/O system has not done it yet.
846 ((PDEVICE_OBJECT
) VolDo
)->StackSize
= (CCHAR
) (DeviceObjectWeTalkTo
->StackSize
+ 1);
847 StackSize
= ((PDEVICE_OBJECT
) VolDo
)->StackSize
;
849 ClearFlag( VolDo
->DeviceObject
.Flags
, DO_DEVICE_INITIALIZING
);
852 // Initialize the overflow queue for the volume
855 VolDo
->OverflowQueueCount
= 0;
856 InitializeListHead( &VolDo
->OverflowQueue
);
858 VolDo
->PostedRequestCount
= 0;
859 KeInitializeSpinLock( &VolDo
->OverflowQueueSpinLock
);
862 // Let's query for the Toc now and handle any error we get from this operation.
865 Status
= CdProcessToc( IrpContext
,
866 DeviceObjectWeTalkTo
,
873 // If we failed to read the TOC, then bail out. Probably blank media.
876 if (Status
!= STATUS_SUCCESS
) {
881 // Don't bail out if that was a disk based ISO image, it is legit
884 if (FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) {
885 CdFreePool( &CdromToc
);
886 Status
= STATUS_SUCCESS
;
896 // Now before we can initialize the Vcb we need to set up the
897 // device object field in the VPB to point to our new volume device
901 Vpb
->DeviceObject
= (PDEVICE_OBJECT
) VolDo
;
904 // Initialize the Vcb. This routine will raise on an allocation
908 CdInitializeVcb( IrpContext
,
910 DeviceObjectWeTalkTo
,
920 // Show that we initialized the Vcb and can cleanup with the Vcb.
928 #ifdef CDFS_TELEMETRY_DATA
931 // Initialize the volume guid.
934 if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb
->TargetDeviceObject
, &VolumeGuid
))) {
937 // We got a GUID, set it in the Telemetry structure
940 RtlCopyMemory( &CdTelemetryData
.VolumeGuid
, &VolumeGuid
, sizeof(GUID
) );
944 // Initialize the correlation ID.
947 if (NT_SUCCESS( FsRtlVolumeDeviceToCorrelationId( Vcb
->TargetDeviceObject
, &VolumeCorrelationId
) )) {
950 // Stash a copy away in the VCB.
953 RtlCopyMemory( &Vcb
->VolumeCorrelationId
, &VolumeCorrelationId
, sizeof( GUID
) );
956 #endif // CDFS_TELEMETRY_DATA
958 // Lock object is acquired and released using internal state
959 _Analysis_suppress_lock_checking_(Vcb
->VcbResource
);
962 // Store the Vcb in the IrpContext as we didn't have one before.
965 IrpContext
->Vcb
= Vcb
;
967 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
970 // Let's reference the Vpb to make sure we are the one to
971 // have the last dereference.
974 Vcb
->Vpb
->ReferenceCount
+= 1;
977 // Clear the verify bit for the start of mount.
980 CdMarkRealDevVerifyOk( Vcb
->Vpb
->RealDevice
);
982 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
985 // Allocate a buffer to read in the volume descriptors. We allocate a full
986 // page to make sure we don't hit any alignment problems.
989 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
990 ROUND_TO_PAGES( SECTOR_SIZE
),
994 // Try to find the primary volume descriptor.
997 FoundPvd
= CdFindPrimaryVd( IrpContext
,
1007 // We failed to find a valid VD in the data track, but there were also
1008 // audio tracks on this disc, so we'll try to mount it as an audio CD.
1009 // Since we're always last in the mount order, we won't be preventing
1010 // any other FS from trying to mount the data track. However if the
1011 // data track was at the start of the disc, then we abort, to avoid
1012 // having to filter it from our synthesised directory listing later. We
1013 // already filtered off any data track at the end.
1016 if (!(TocDiskFlags
& CDROM_DISK_AUDIO_TRACK
) ||
1017 BooleanFlagOn( Vcb
->CdromToc
->TrackData
[0].Control
, TOC_DATA_TRACK
)) {
1019 try_leave( Status
= STATUS_UNRECOGNIZED_VOLUME
);
1022 SetFlag( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
| VCB_STATE_CDXA
);
1024 CdFreePool( &RawIsoVd
);
1030 // Look and see if there is a secondary volume descriptor we want to
1037 // Store the primary volume descriptor in the second half of
1038 // RawIsoVd. Then if our search for a secondary fails we can
1039 // recover this immediately.
1042 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
1047 // We have the initial volume descriptor. Locate a secondary
1048 // volume descriptor if present.
1051 CdFindActiveVolDescriptor( IrpContext
,
1058 // Allocate a block cache to speed directory operations. We can't
1059 // use the cache if there is any chance the volume has link blocks
1060 // in the data area (i.e. was packet written and then finalized to
1061 // Joliet/9660). So we simply only allow the cache to operate on
1062 // media with a single track - since we're really targetting pressed
1063 // installation media here. We can't be more precise, since D/CD-ROM
1064 // drives don't support READ_TRACK_INFO, which is the only way for
1065 // certain to know whether or not a track was packet written.
1068 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
) &&
1069 ((Vcb
->CdromToc
->LastTrack
- Vcb
->CdromToc
->FirstTrack
) == 0)) {
1075 Vcb
->SectorCacheBuffer
= FsRtlAllocatePool( CdPagedPool
,
1076 CD_SEC_CACHE_CHUNKS
*
1077 CD_SEC_CHUNK_BLOCKS
*
1080 for (Index
= 0; Index
< (ULONG
)CD_SEC_CACHE_CHUNKS
; Index
++) {
1082 Vcb
->SecCacheChunks
[ Index
].Buffer
= Buffer
;
1083 Vcb
->SecCacheChunks
[ Index
].BaseLbn
= (ULONG
)-1;
1085 Buffer
+= CD_SEC_CHUNK_BLOCKS
* SECTOR_SIZE
;
1088 Vcb
->SectorCacheIrp
= IoAllocateIrp( StackSize
, FALSE
);
1090 if (Vcb
->SectorCacheIrp
== NULL
) {
1092 try_leave( Status
= STATUS_INSUFFICIENT_RESOURCES
);
1095 IoInitializeIrp( Vcb
->SectorCacheIrp
,
1096 IoSizeOfIrp( StackSize
),
1099 KeInitializeEvent( &Vcb
->SectorCacheEvent
, SynchronizationEvent
, FALSE
);
1100 ExInitializeResourceLite( &Vcb
->SectorCacheResource
);
1104 // Check if this is a remount operation. If so then clean up
1105 // the data structures passed in and created here.
1108 if (CdIsRemount( IrpContext
, Vcb
, &OldVcb
)) {
1110 NT_ASSERT( NULL
!= OldVcb
->SwapVpb
);
1113 // Link the old Vcb to point to the new device object that we
1114 // should be talking to, dereferencing the previous. Call a
1115 // nonpaged routine to do this since we take the Vpb spinlock.
1118 CdReMountOldVcb( IrpContext
,
1121 DeviceObjectWeTalkTo
);
1124 // See if we will need to provide notification of the remount. This is the readonly
1125 // filesystem's form of dismount/mount notification - we promise that whenever a
1126 // volume is "dismounted", that a mount notification will occur when it is revalidated.
1127 // Note that we do not send mount on normal remounts - that would duplicate the media
1128 // arrival notification of the device driver.
1131 if (FlagOn( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1133 ClearFlag( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1135 FileObjectToNotify
= OldVcb
->RootIndexFcb
->FileObject
;
1136 ObReferenceObject( FileObjectToNotify
);
1139 try_leave( Status
= STATUS_SUCCESS
);
1143 // This is a new mount. Go ahead and initialize the
1144 // Vcb from the volume descriptor.
1147 CdUpdateVcbFromVolDescriptor( IrpContext
,
1152 // Drop an extra reference on the root dir file so we'll be able to send
1156 if (Vcb
->RootIndexFcb
) {
1158 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1159 ObReferenceObject( FileObjectToNotify
);
1163 // Now check the maximum transfer limits on the device in case we
1164 // get raw reads on this volume.
1167 Status
= CdPerformDevIoCtrl( IrpContext
,
1168 IOCTL_SCSI_GET_CAPABILITIES
,
1169 DeviceObjectWeTalkTo
,
1171 sizeof( IO_SCSI_CAPABILITIES
),
1176 if (NT_SUCCESS(Status
)) {
1178 Vcb
->MaximumTransferRawSectors
= Capabilities
.MaximumTransferLength
/ RAW_SECTOR_SIZE
;
1179 Vcb
->MaximumPhysicalPages
= Capabilities
.MaximumPhysicalPages
;
1184 // This should never happen, but we can safely assume 64k and 16 pages.
1187 Vcb
->MaximumTransferRawSectors
= (64 * 1024) / RAW_SECTOR_SIZE
;
1188 Vcb
->MaximumPhysicalPages
= 16;
1192 // The new mount is complete. Remove the additional references on this
1193 // Vcb and the device we are mounted on top of.
1196 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1197 NT_ASSERT( Vcb
->VcbReference
== CDFS_RESIDUAL_REFERENCE
);
1199 ObDereferenceObject( Vcb
->TargetDeviceObject
);
1201 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1203 CdReleaseVcb( IrpContext
, Vcb
);
1206 Status
= STATUS_SUCCESS
;
1211 // Free the TOC buffer if not in the Vcb.
1214 if (CdromToc
!= NULL
) {
1216 CdFreePool( &CdromToc
);
1220 // Free the sector buffer if allocated.
1223 if (RawIsoVd
!= NULL
) {
1225 CdFreePool( &RawIsoVd
);
1229 // If we are not mounting the device, then set the verify bit again.
1232 if ((_SEH2_AbnormalTermination() || (Status
!= STATUS_SUCCESS
)) &&
1233 SetDoVerifyOnFail
) {
1235 CdMarkRealDevForVerify( IrpContext
->RealDevice
);
1239 // If we didn't complete the mount then cleanup any remaining structures.
1242 if (Vpb
!= NULL
) { Vpb
->DeviceObject
= NULL
; }
1247 // Make sure there is no Vcb in the IrpContext since it could go away
1250 IrpContext
->Vcb
= NULL
;
1252 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1254 if (CdDismountVcb( IrpContext
, Vcb
)) {
1256 CdReleaseVcb( IrpContext
, Vcb
);
1259 } else if (VolDo
!= NULL
) {
1261 IoDeleteDevice( (PDEVICE_OBJECT
) VolDo
);
1265 // Release the global resource.
1268 CdReleaseCdData( IrpContext
);
1272 // Now send mount notification.
1275 if (FileObjectToNotify
) {
1277 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1278 ObDereferenceObject( FileObjectToNotify
);
1281 #ifdef CDFS_TELEMETRY_DATA
1287 CdTelemetryMountSafe( &VolumeCorrelationId
, STATUS_SUCCESS
, Vcb
);
1292 // Complete the request if no exception.
1295 CdCompleteRequest( IrpContext
, Irp
, Status
);
1301 // Local support routine
1304 _Requires_lock_held_(_Global_critical_region_
)
1307 _Inout_ PIRP_CONTEXT IrpContext
,
1313 Routine Description:
1315 This routine performs the verify volume operation. It is responsible for
1316 either completing of enqueuing the input Irp.
1320 Irp - Supplies the Irp to process
1324 NTSTATUS - The return status for the operation
1329 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1330 PVPB Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
1331 PVCB Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->Parameters
.VerifyVolume
.DeviceObject
)->Vcb
;
1333 PCHAR RawIsoVd
= NULL
;
1335 PCDROM_TOC_LARGE CdromToc
= NULL
;
1336 ULONG TocLength
= 0;
1337 ULONG TocTrackCount
= 0;
1338 ULONG TocDiskFlags
= 0;
1340 ULONG MediaChangeCount
= Vcb
->MediaChangeCount
;
1342 PFILE_OBJECT FileObjectToNotify
= NULL
;
1344 BOOLEAN ReturnError
;
1345 BOOLEAN ReleaseVcb
= FALSE
;
1347 IO_STATUS_BLOCK Iosb
;
1350 UNICODE_STRING UnicodeLabel
;
1352 WCHAR VolumeLabel
[ VOLUME_ID_LENGTH
];
1353 ULONG VolumeLabelLength
;
1357 NTSTATUS Status
= STATUS_SUCCESS
;
1362 // We check that we are talking to a Cdrom device.
1365 NT_ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
1366 NT_ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
1369 // Update the real device in the IrpContext from the Vpb. There was no available
1370 // file object when the IrpContext was created.
1373 IrpContext
->RealDevice
= Vpb
->RealDevice
;
1376 // Acquire the global resource to synchronise against mounts and teardown,
1377 // finally clause releases.
1380 CdAcquireCdData( IrpContext
);
1384 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1388 // Check to see if the volume is eligible for verification.
1391 if ((Vcb
->VcbCondition
== VcbInvalid
) ||
1392 (Vcb
->VcbCondition
== VcbDismountInProgress
)) {
1394 try_return( Status
= STATUS_WRONG_VOLUME
);
1398 // Verify that there is a disk here.
1401 Status
= CdPerformDevIoCtrl( IrpContext
,
1402 IOCTL_CDROM_CHECK_VERIFY
,
1403 Vcb
->TargetDeviceObject
,
1410 if (!NT_SUCCESS( Status
)) {
1413 // If we will allow a raw mount then return WRONG_VOLUME to
1414 // allow the volume to be mounted by raw.
1417 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1419 Status
= STATUS_WRONG_VOLUME
;
1422 try_return( Status
);
1425 if (Iosb
.Information
!= sizeof(ULONG
)) {
1428 // Be safe about the count in case the driver didn't fill it in
1431 MediaChangeCount
= 0;
1435 // Verify that the device actually saw a change. If the driver does not
1436 // support the MCC, then we must verify the volume in any case.
1439 if (MediaChangeCount
== 0 ||
1440 (Vcb
->MediaChangeCount
!= MediaChangeCount
)) {
1443 // Allocate a buffer to query the TOC.
1446 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
1447 sizeof( CDROM_TOC_LARGE
),
1450 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC_LARGE
));
1453 // Let's query for the Toc now and handle any error we get from this operation.
1456 Status
= CdProcessToc( IrpContext
,
1457 Vcb
->TargetDeviceObject
,
1464 // If we failed to read the TOC, then give up now. Drives will fail
1465 // a TOC read on, for example, erased CD-RW media.
1468 if (Status
!= STATUS_SUCCESS
) {
1471 // For any errors other than no media and not ready, commute the
1472 // status to ensure that the current VPB is kicked off the device
1473 // below - there is probably blank media in the drive, since we got
1474 // further than the check verify.
1477 if (!CdIsRawDevice( IrpContext
, Status
)) {
1479 Status
= STATUS_WRONG_VOLUME
;
1482 try_return( Status
);
1485 // We got a TOC. Verify that it matches the previous Toc.
1488 } else if ((Vcb
->TocLength
!= TocLength
) ||
1489 (Vcb
->TrackCount
!= TocTrackCount
) ||
1490 (Vcb
->DiskFlags
!= TocDiskFlags
) ||
1491 !RtlEqualMemory( CdromToc
,
1495 try_return( Status
= STATUS_WRONG_VOLUME
);
1499 // If the disk to verify is an audio disk then we already have a
1500 // match. Otherwise we need to check the volume descriptor.
1503 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
1506 // Allocate a buffer for the sector buffer.
1509 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
1510 ROUND_TO_PAGES( 2 * SECTOR_SIZE
),
1514 // Read the primary volume descriptor for this volume. If we
1515 // get an io error and this verify was a the result of DASD open,
1516 // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
1517 // expect a music disk then this request should fail.
1520 ReturnError
= FALSE
;
1522 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1527 if (!CdFindPrimaryVd( IrpContext
,
1535 // If the previous Vcb did not represent a raw disk
1536 // then show this volume was dismounted.
1539 try_return( Status
= STATUS_WRONG_VOLUME
);
1545 // Look for a supplementary VD.
1547 // Store the primary volume descriptor in the second half of
1548 // RawIsoVd. Then if our search for a secondary fails we can
1549 // recover this immediately.
1552 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
1557 // We have the initial volume descriptor. Locate a secondary
1558 // volume descriptor if present.
1561 CdFindActiveVolDescriptor( IrpContext
,
1566 // Compare the serial numbers. If they don't match, set the
1567 // status to wrong volume.
1570 if (Vpb
->SerialNumber
!= CdSerial32( RawIsoVd
, SECTOR_SIZE
)) {
1572 try_return( Status
= STATUS_WRONG_VOLUME
);
1576 // Verify the volume labels.
1579 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
1582 // Compute the length of the volume name
1585 AnsiLabel
.Buffer
= (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
);
1586 AnsiLabel
.MaximumLength
= AnsiLabel
.Length
= (ULONG
)VOLUME_ID_LENGTH
;
1588 UnicodeLabel
.MaximumLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
1589 UnicodeLabel
.Buffer
= VolumeLabel
;
1592 // Convert this to unicode. If we get any error then use a name
1596 VolumeLabelLength
= 0;
1598 if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel
,
1602 VolumeLabelLength
= UnicodeLabel
.Length
;
1606 // We need to convert from big-endian to little endian.
1611 CdConvertBigToLittleEndian( IrpContext
,
1612 (PCHAR
) CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
1614 (PCHAR
) VolumeLabel
);
1616 VolumeLabelLength
= VOLUME_ID_LENGTH
;
1620 // Strip the trailing spaces or zeroes from the name.
1623 Index
= VolumeLabelLength
/ sizeof( WCHAR
);
1627 if ((VolumeLabel
[ Index
- 1 ] != L
'\0') &&
1628 (VolumeLabel
[ Index
- 1 ] != L
' ')) {
1637 // Now set the final length for the name.
1640 VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));
1643 // Now check that the label matches.
1645 if ((Vpb
->VolumeLabelLength
!= VolumeLabelLength
) ||
1646 !RtlEqualMemory( Vpb
->VolumeLabel
,
1648 VolumeLabelLength
)) {
1650 try_return( Status
= STATUS_WRONG_VOLUME
);
1657 // The volume is OK, clear the verify bit.
1660 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1662 CdMarkRealDevVerifyOk( Vpb
->RealDevice
);
1665 // See if we will need to provide notification of the remount. This is the readonly
1666 // filesystem's form of dismount/mount notification.
1669 if (FlagOn( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1671 ClearFlag( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1673 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1674 ObReferenceObject( FileObjectToNotify
);
1680 // Update the media change count to note that we have verified the volume
1681 // at this value - regardless of the outcome.
1684 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
1687 // If the volume was already unmounted, nothing more to do.
1690 if (Vcb
->VcbCondition
== VcbNotMounted
) {
1692 Status
= STATUS_WRONG_VOLUME
;
1695 // If we got the wrong volume then free any remaining XA sector in
1696 // the current Vcb. Also mark the Vcb as not mounted.
1699 } else if ((Vcb
->VcbCondition
== VcbMounted
) && (Status
== STATUS_WRONG_VOLUME
)) {
1701 CdUpdateVcbCondition( Vcb
, VcbNotMounted
);
1703 if (Vcb
->XASector
!= NULL
) {
1705 CdFreePool( &Vcb
->XASector
);
1707 Vcb
->XADiskOffset
= 0;
1710 CdFreeDirCache( IrpContext
);
1713 // Now, if there are no user handles to the volume, try to spark
1714 // teardown by purging the volume.
1717 if (Vcb
->VcbCleanup
== 0) {
1719 if (NT_SUCCESS( CdPurgeVolume( IrpContext
, Vcb
, FALSE
))) {
1721 ReleaseVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
1729 // Free the TOC buffer if allocated.
1732 if (CdromToc
!= NULL
) {
1734 CdFreePool( &CdromToc
);
1737 if (RawIsoVd
!= NULL
) {
1739 CdFreePool( &RawIsoVd
);
1744 CdReleaseVcb( IrpContext
, Vcb
);
1747 _Analysis_assume_lock_not_held_(Vcb
->VcbResource
);
1750 CdReleaseCdData( IrpContext
);
1754 // Now send mount notification.
1757 if (FileObjectToNotify
) {
1759 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1760 ObDereferenceObject( FileObjectToNotify
);
1764 // Complete the request if no exception.
1767 CdCompleteRequest( IrpContext
, Irp
, Status
);
1773 // Local support routine
1776 _Requires_lock_held_(_Global_critical_region_
)
1779 _Inout_ PIRP_CONTEXT IrpContext
,
1785 Routine Description:
1787 This is the common routine to handle oplock requests made via the
1788 NtFsControlFile call.
1792 Irp - Supplies the Irp being processed
1796 NTSTATUS - The return status for the operation
1801 NTSTATUS Status
= STATUS_SUCCESS
;
1805 ULONG OplockCount
= 0;
1806 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1811 // We only permit oplock requests on files.
1814 if (CdDecodeFileObject( IrpContext
,
1817 &Ccb
) != UserFileOpen
) {
1819 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1820 return STATUS_INVALID_PARAMETER
;
1824 // Make this a waitable Irpcontext so we don't fail to acquire
1828 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1829 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1832 // Switch on the function control code. We grab the Fcb exclusively
1833 // for oplock requests, shared for oplock break acknowledgement.
1836 switch (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
1838 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
1839 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
1840 case FSCTL_REQUEST_BATCH_OPLOCK
:
1841 case FSCTL_REQUEST_FILTER_OPLOCK
:
1843 CdAcquireFcbExclusive( IrpContext
, Fcb
, FALSE
);
1845 if (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_REQUEST_OPLOCK_LEVEL_2
) {
1847 if (Fcb
->FileLock
!= NULL
) {
1849 #if (NTDDI_VERSION >= NTDDI_WIN7)
1850 OplockCount
= (ULONG
) FsRtlAreThereCurrentOrInProgressFileLocks( Fcb
->FileLock
);
1852 OplockCount
= (ULONG
) FsRtlAreThereCurrentFileLocks( Fcb
->FileLock
);
1858 OplockCount
= Fcb
->FcbCleanup
;
1863 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
1864 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
1865 case FSCTL_OPLOCK_BREAK_NOTIFY
:
1866 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
1868 CdAcquireFcbShared( IrpContext
, Fcb
, FALSE
);
1873 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1874 return STATUS_INVALID_PARAMETER
;
1878 // Use a try finally to free the Fcb.
1887 CdVerifyFcbOperation( IrpContext
, Fcb
);
1890 // Call the FsRtl routine to grant/acknowledge oplock.
1893 Status
= FsRtlOplockFsctrl( CdGetFcbOplock(Fcb
),
1898 // Set the flag indicating if Fast I/O is possible
1901 CdLockFcb( IrpContext
, Fcb
);
1902 Fcb
->IsFastIoPossible
= CdIsFastIoPossible( Fcb
);
1903 CdUnlockFcb( IrpContext
, Fcb
);
1906 // The oplock package will complete the Irp.
1914 // Release all of our resources
1917 CdReleaseFcb( IrpContext
, Fcb
);
1921 // Complete the request if there was no exception.
1924 CdCompleteRequest( IrpContext
, Irp
, Status
);
1930 // Local support routine
1933 _Requires_lock_held_(_Global_critical_region_
)
1936 _Inout_ PIRP_CONTEXT IrpContext
,
1942 Routine Description:
1944 This routine performs the lock volume operation. It is responsible for
1945 either completing of enqueuing the input Irp.
1949 Irp - Supplies the Irp to process
1953 NTSTATUS - The return status for the operation
1958 NTSTATUS Status
= STATUS_SUCCESS
;
1960 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1969 // Decode the file object, the only type of opens we accept are
1970 // user volume opens.
1973 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1975 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1977 return STATUS_INVALID_PARAMETER
;
1981 // Send our notification so that folks that like to hold handles on
1982 // volumes can get out of the way.
1985 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
1988 // Acquire exclusive access to the Vcb.
1992 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2000 CdVerifyVcb( IrpContext
, Vcb
);
2002 Status
= CdLockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2010 CdReleaseVcb( IrpContext
, Vcb
);
2012 if (_SEH2_AbnormalTermination() || !NT_SUCCESS( Status
)) {
2014 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
2019 // Complete the request if there haven't been any exceptions.
2022 CdCompleteRequest( IrpContext
, Irp
, Status
);
2028 // Local support routine
2031 _Requires_lock_held_(_Global_critical_region_
)
2034 _Inout_ PIRP_CONTEXT IrpContext
,
2040 Routine Description:
2042 This routine performs the unlock volume operation. It is responsible for
2043 either completing of enqueuing the input Irp.
2047 Irp - Supplies the Irp to process
2051 NTSTATUS - The return status for the operation
2058 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2067 // Decode the file object, the only type of opens we accept are
2068 // user volume opens.
2071 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2073 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2074 return STATUS_INVALID_PARAMETER
;
2078 // Acquire exclusive access to the Vcb.
2083 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2086 // We won't check for a valid Vcb for this request. An unlock will always
2087 // succeed on a locked volume.
2090 Status
= CdUnlockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2093 // Release all of our resources
2096 CdReleaseVcb( IrpContext
, Vcb
);
2099 // Send notification that the volume is avaliable.
2102 if (NT_SUCCESS( Status
)) {
2104 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
2108 // Complete the request if there haven't been any exceptions.
2111 CdCompleteRequest( IrpContext
, Irp
, Status
);
2118 // Local support routine
2121 _Requires_lock_held_(_Global_critical_region_
)
2124 _Inout_ PIRP_CONTEXT IrpContext
,
2130 Routine Description:
2132 This routine performs the dismount volume operation. It is responsible for
2133 either completing of enqueuing the input Irp. We only dismount a volume which
2134 has been locked. The intent here is that someone has locked the volume (they are the
2135 only remaining handle). We set the verify bit here and the user will close his handle.
2136 We will dismount a volume with no user's handles in the verify path.
2140 Irp - Supplies the Irp to process
2144 NTSTATUS - The return status for the operation
2150 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2158 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2160 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2161 return STATUS_INVALID_PARAMETER
;
2167 // Send dismount notification.
2170 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_DISMOUNT
);
2173 // Make this request waitable.
2176 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2179 // Acquire exclusive access to the Vcb, and take the global resource to
2180 // sync. against mounts, verifies etc.
2183 CdAcquireCdData( IrpContext
);
2184 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2187 // Mark the volume as needs to be verified, but only do it if
2188 // the vcb is locked by this handle and the volume is currently mounted.
2191 if (Vcb
->VcbCondition
!= VcbMounted
) {
2193 Status
= STATUS_VOLUME_DISMOUNTED
;
2198 // Invalidate the volume right now.
2200 // The intent here is to make every subsequent operation
2201 // on the volume fail and grease the rails toward dismount.
2202 // By definition there is no going back from a SURPRISE.
2205 CdLockVcb( IrpContext
, Vcb
);
2207 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2209 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2212 SetFlag( Vcb
->VcbState
, VCB_STATE_DISMOUNTED
);
2214 CdUnlockVcb( IrpContext
, Vcb
);
2218 // Set flag to tell the close path that we want to force dismount
2219 // the volume when this handle is closed.
2222 SetFlag( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
);
2224 Status
= STATUS_SUCCESS
;
2228 // Release all of our resources
2231 CdReleaseVcb( IrpContext
, Vcb
);
2232 CdReleaseCdData( IrpContext
);
2234 #if (NTDDI_VERSION >= NTDDI_WIN8)
2236 FsRtlDismountComplete( Vcb
->TargetDeviceObject
, Status
);
2241 // Complete the request if there haven't been any exceptions.
2244 CdCompleteRequest( IrpContext
, Irp
, Status
);
2250 // Local support routine
2255 _Inout_ PIRP_CONTEXT IrpContext
,
2261 Routine Description:
2263 This routine determines if a volume is currently dirty.
2267 Irp - Supplies the Irp to process
2271 NTSTATUS - The return status for the operation
2276 PIO_STACK_LOCATION IrpSp
;
2278 TYPE_OF_OPEN TypeOfOpen
;
2287 // Get the current stack location and extract the output
2288 // buffer information.
2291 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2294 // Get a pointer to the output buffer.
2297 if (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
) {
2299 VolumeState
= Irp
->AssociatedIrp
.SystemBuffer
;
2303 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_USER_BUFFER
);
2304 return STATUS_INVALID_USER_BUFFER
;
2308 // Make sure the output buffer is large enough and then initialize
2309 // the answer to be that the volume isn't dirty.
2312 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
)) {
2314 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2315 return STATUS_INVALID_PARAMETER
;
2321 // Decode the file object
2324 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2326 if (TypeOfOpen
!= UserVolumeOpen
) {
2328 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2329 return STATUS_INVALID_PARAMETER
;
2332 if (Fcb
->Vcb
->VcbCondition
!= VcbMounted
) {
2334 CdCompleteRequest( IrpContext
, Irp
, STATUS_VOLUME_DISMOUNTED
);
2335 return STATUS_VOLUME_DISMOUNTED
;
2339 // Now set up to return the clean state. CDs obviously can never be dirty
2340 // but we want to make sure we have enforced the full semantics of this call.
2343 Irp
->IoStatus
.Information
= sizeof( ULONG
);
2345 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2346 return STATUS_SUCCESS
;
2351 // Local support routine
2356 _Inout_ PIRP_CONTEXT IrpContext
,
2362 Routine Description:
2364 This routine determines if a volume is currently mounted.
2368 Irp - Supplies the Irp to process
2372 NTSTATUS - The return status for the operation
2377 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2385 // Decode the file object.
2388 CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2393 // Disable PopUps, we want to return any error.
2396 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
2399 // Verify the Vcb. This will raise in the error condition.
2402 CdVerifyVcb( IrpContext
, Fcb
->Vcb
);
2405 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2407 return STATUS_SUCCESS
;
2412 // Local support routine
2417 _Inout_ PIRP_CONTEXT IrpContext
,
2423 Routine Description:
2425 This routine determines if pathname is a valid CDFS pathname.
2426 We always succeed this request.
2430 Irp - Supplies the Irp to process.
2441 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2442 return STATUS_SUCCESS
;
2447 // Local support routine
2450 _Requires_lock_held_(_Global_critical_region_
)
2452 CdInvalidateVolumes (
2453 _Inout_ PIRP_CONTEXT IrpContext
,
2459 Routine Description:
2461 This routine searches for all the volumes mounted on the same real device
2462 of the current DASD handle, and marks them all bad. The only operation
2463 that can be done on such handles is cleanup and close.
2467 Irp - Supplies the Irp to process
2471 NTSTATUS - The return status for the operation
2477 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2480 BOOLEAN UnlockVcb
= FALSE
;
2482 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
2490 PFILE_OBJECT FileToMarkBad
;
2491 PDEVICE_OBJECT DeviceToMarkBad
;
2494 // We only allow the invalidate call to come in on our file system devices.
2498 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
2500 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
&&
2501 IrpSp
->DeviceObject
!= CdData
.HddFileSystemDeviceObject
) {
2504 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
2506 return STATUS_INVALID_DEVICE_REQUEST
;
2510 // Check for the correct security access.
2511 // The caller must have the SeTcbPrivilege.
2514 if (!SeSinglePrivilegeCheck( TcbPrivilege
, Irp
->RequestorMode
)) {
2516 CdCompleteRequest( IrpContext
, Irp
, STATUS_PRIVILEGE_NOT_HELD
);
2518 return STATUS_PRIVILEGE_NOT_HELD
;
2522 // Try to get a pointer to the device object from the handle passed in.
2525 #if defined(_WIN64) && BUILD_WOW64_ENABLED
2527 if (IoIs32bitProcess( Irp
)) {
2529 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( UINT32
)) {
2531 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2532 return STATUS_INVALID_PARAMETER
;
2535 Handle
= (HANDLE
) LongToHandle( *((PUINT32
) Irp
->AssociatedIrp
.SystemBuffer
) );
2542 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( HANDLE
)) {
2544 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2545 return STATUS_INVALID_PARAMETER
;
2548 Handle
= *((PHANDLE
) Irp
->AssociatedIrp
.SystemBuffer
);
2551 Status
= ObReferenceObjectByHandle( Handle
,
2555 (PVOID
*)&FileToMarkBad
, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
2558 if (!NT_SUCCESS(Status
)) {
2560 CdCompleteRequest( IrpContext
, Irp
, Status
);
2565 // Grab the DeviceObject from the FileObject.
2568 DeviceToMarkBad
= FileToMarkBad
->DeviceObject
;
2571 // We only needed the device object involved, not a reference to the file.
2574 ObDereferenceObject( FileToMarkBad
);
2577 // Make sure this request can wait.
2580 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2581 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
2584 // Synchronise with pnp/mount/verify paths.
2587 CdAcquireCdData( IrpContext
);
2590 // Nothing can go wrong now.
2594 // Now walk through all the mounted Vcb's looking for candidates to
2597 // On volumes we mark invalid, check for dismount possibility (which is
2598 // why we have to get the next link so early).
2601 Links
= CdData
.VcbQueue
.Flink
;
2603 while (Links
!= &CdData
.VcbQueue
) {
2605 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2607 Links
= Links
->Flink
;
2610 // If we get a match, mark the volume Bad, and also check to
2611 // see if the volume should go away.
2614 CdLockVcb( IrpContext
, Vcb
);
2616 if (Vcb
->Vpb
->RealDevice
== DeviceToMarkBad
) {
2619 // Take the VPB spinlock, and look to see if this volume is the
2620 // one currently mounted on the actual device. If it is, pull it
2624 IoAcquireVpbSpinLock( &SavedIrql
);
2627 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed")
2629 if (DeviceToMarkBad
->Vpb
== Vcb
->Vpb
) {
2631 PVPB NewVpb
= Vcb
->SwapVpb
;
2633 NT_ASSERT( FlagOn( Vcb
->Vpb
->Flags
, VPB_MOUNTED
));
2634 NT_ASSERT( NULL
!= NewVpb
);
2636 RtlZeroMemory( NewVpb
, sizeof( VPB
) );
2638 NewVpb
->Type
= IO_TYPE_VPB
;
2639 NewVpb
->Size
= sizeof( VPB
);
2640 NewVpb
->RealDevice
= DeviceToMarkBad
;
2643 #pragma prefast(push)
2644 #pragma prefast(disable: 28175, "this is a filesystem driver, touching the vpb is allowed")
2646 NewVpb
->Flags
= FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_REMOVE_PENDING
);
2647 DeviceToMarkBad
->Vpb
= NewVpb
;
2649 #pragma prefast(pop)
2652 Vcb
->SwapVpb
= NULL
;
2655 IoReleaseVpbSpinLock( SavedIrql
);
2657 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2659 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2662 CdUnlockVcb( IrpContext
, Vcb
);
2664 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2666 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
2668 UnlockVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2671 // prefast: if UnlockVcb is false, then the VCB was already deleted, so we better not touch the Vcb.
2672 // tell Prefast something nice so it stops complaining about us leaking it.
2675 __analysis_assert( UnlockVcb
== TRUE
);
2679 CdReleaseVcb( IrpContext
, Vcb
);
2684 CdUnlockVcb( IrpContext
, Vcb
);
2688 CdReleaseCdData( IrpContext
);
2690 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2691 return STATUS_SUCCESS
;
2696 // Local support routine
2700 CdAllowExtendedDasdIo (
2701 _Inout_ PIRP_CONTEXT IrpContext
,
2707 Routine Description:
2709 This routine marks the CCB to indicate that the handle
2710 may be used to read past the end of the volume file. The
2711 handle must be a dasd handle.
2715 Irp - Supplies the Irp to process
2719 NTSTATUS - The return status for the operation
2725 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2733 // Decode the file object, the only type of opens we accept are
2734 // user volume opens.
2737 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2739 Status
= STATUS_INVALID_PARAMETER
;
2743 SetFlag( Ccb
->Flags
, CCB_FLAG_ALLOW_EXTENDED_DASD_IO
);
2744 Status
= STATUS_SUCCESS
;
2747 CdCompleteRequest( IrpContext
, Irp
, Status
);
2753 // Local support routine
2756 _Requires_lock_held_(_Global_critical_region_
)
2758 CdScanForDismountedVcb (
2759 _Inout_ PIRP_CONTEXT IrpContext
2764 Routine Description:
2766 This routine walks through the list of Vcb's looking for any which may
2767 now be deleted. They may have been left on the list because there were
2768 outstanding references.
2785 // Walk through all of the Vcb's attached to the global data.
2788 Links
= CdData
.VcbQueue
.Flink
;
2790 while (Links
!= &CdData
.VcbQueue
) {
2792 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2795 // Move to the next link now since the current Vcb may be deleted.
2798 Links
= Links
->Flink
;
2801 // If dismount is already underway then check if this Vcb can
2805 if ((Vcb
->VcbCondition
== VcbDismountInProgress
) ||
2806 (Vcb
->VcbCondition
== VcbInvalid
) ||
2807 ((Vcb
->VcbCondition
== VcbNotMounted
) && (Vcb
->VcbReference
<= CDFS_RESIDUAL_REFERENCE
))) {
2809 CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2818 // Local support routine
2820 _Success_(return != FALSE
)
2823 _In_ PIRP_CONTEXT IrpContext
,
2825 _Out_writes_bytes_(SECTOR_SIZE
) PCHAR RawIsoVd
,
2826 _In_ ULONG BlockFactor
,
2827 _In_ BOOLEAN ReturnOnError
,
2828 _In_ BOOLEAN VerifyVolume
2833 Routine Description:
2835 This routine is called to walk through the volume descriptors looking
2836 for a primary volume descriptor. When/if a primary is found a 32-bit
2837 serial number is generated and stored into the Vpb. We also store the
2838 location of the primary volume descriptor in the Vcb.
2842 Vcb - Pointer to the VCB for the volume.
2844 RawIsoVd - Pointer to a sector buffer which will contain the primary
2845 volume descriptor on exit, if successful.
2847 BlockFactor - Block factor used by the current device for the TableOfContents.
2849 ReturnOnError - Indicates that we should raise on I/O errors rather than
2850 returning a FALSE value.
2852 VerifyVolume - Indicates if we were called from the verify path. We
2853 do a few things different in this path. We don't update the Vcb in
2858 BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
2866 BOOLEAN FoundVd
= FALSE
;
2871 PCDROM_TOC_LARGE CdromToc
;
2878 // If there are no data tracks, don't even bother hunting for descriptors.
2880 // This explicitly breaks various non-BlueBook compliant CDs that scribble
2881 // an ISO filesystem on media claiming only audio tracks. Since these
2882 // disks can cause serious problems in some CDROM units, fail fast. I admit
2883 // that it is possible that someone can still record the descriptors in the
2884 // audio track, record a data track (but fail to record descriptors there)
2885 // and still have the disk work. As this form of error worked in NT 4.0, and
2886 // since these disks really do exist, I don't want to change them.
2888 // If we wished to support all such media (we don't), it would be neccesary
2889 // to clear this flag on finding ISO or HSG descriptors below.
2892 if (FlagOn(Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2898 // We will make at most two passes through the volume descriptor sequence.
2900 // On the first pass we will query for the last session. Using this
2901 // as a starting offset we will attempt to mount the volume. On any failure
2902 // we will go to the second pass and try without using any multi-session
2905 // On the second pass we will start offset from sector zero.
2908 while (!FoundVd
&& (ThisPass
<= 2)) {
2911 // If we aren't at pass 1 then we start at sector 0. Otherwise we
2912 // try to look up the multi-session information.
2917 if (ThisPass
== 1) {
2922 // Check for whether this device supports XA and multi-session.
2928 // Allocate a buffer for the last session information.
2931 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
2932 sizeof( CDROM_TOC_LARGE
),
2935 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC_LARGE
));
2938 // Query the last session information from the driver.
2941 Status
= CdPerformDevIoCtrl( IrpContext
,
2942 IOCTL_CDROM_GET_LAST_SESSION
,
2943 Vcb
->TargetDeviceObject
,
2945 sizeof( CDROM_TOC_LARGE
),
2951 // Raise an exception if there was an allocation failure.
2954 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
2956 CdRaiseStatus( IrpContext
, Status
);
2960 // We don't handle any errors yet. We will hit that below
2961 // as we try to scan the disk. If we have last session information
2962 // then modify the base sector.
2965 if (NT_SUCCESS( Status
) &&
2966 (CdromToc
->FirstTrack
!= CdromToc
->LastTrack
)) {
2974 // The track address is BigEndian, we need to flip the bytes.
2977 Source
= (PCHAR
) &CdromToc
->TrackData
[0].Address
[3];
2978 Dest
= (PCHAR
) &BaseSector
;
2982 *Dest
++ = *Source
--;
2987 // Now adjust the base sector by the block factor of the
2991 BaseSector
/= BlockFactor
;
2994 // Make this look like the second pass since we are only using the
2995 // first session. No reason to retry on error.
3005 if (CdromToc
!= NULL
) { CdFreePool( &CdromToc
); }
3010 // Compute the starting sector offset from the start of the session.
3013 SectorOffset
= FIRST_VD_SECTOR
;
3016 // Start by assuming we have neither Hsg or Iso volumes.
3022 // Loop until either error encountered, primary volume descriptor is
3023 // found or a terminal volume descriptor is found.
3029 // Attempt to read the desired sector. Exit directly if operation
3032 // If this is pass 1 we will ignore errors in read sectors and just
3033 // go to the next pass.
3036 if (!CdReadSectors( IrpContext
,
3037 LlBytesFromSectors( BaseSector
+ SectorOffset
),
3039 (BOOLEAN
) ((ThisPass
== 1) || ReturnOnError
),
3041 Vcb
->TargetDeviceObject
)) {
3047 // Check if either an ISO or HSG volume.
3050 if (RtlEqualMemory( CdIsoId
,
3051 CdRvdId( RawIsoVd
, VCB_STATE_ISO
),
3054 SetFlag( VolumeFlags
, VCB_STATE_ISO
);
3056 } else if (RtlEqualMemory( CdHsgId
,
3057 CdRvdId( RawIsoVd
, VCB_STATE_HSG
),
3060 SetFlag( VolumeFlags
, VCB_STATE_HSG
);
3063 // We have neither so break out of the loop.
3072 // Break out if the version number is incorrect or this is
3076 if ((CdRvdVersion( RawIsoVd
, VolumeFlags
) != VERSION_1
) ||
3077 (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_TERMINATOR
)) {
3083 // If this is a primary volume descriptor then our search is over.
3086 if (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_PRIMARY
) {
3089 // If we are not in the verify path then initialize the
3090 // fields in the Vcb with basic information from this
3094 if (!VerifyVolume
) {
3097 // Set the flag for the volume type.
3100 SetFlag( Vcb
->VcbState
, VolumeFlags
);
3103 // Store the base sector and sector offset for the
3104 // primary volume descriptor.
3107 Vcb
->BaseSector
= BaseSector
;
3108 Vcb
->VdSectorOffset
= SectorOffset
;
3109 Vcb
->PrimaryVdSectorOffset
= SectorOffset
;
3117 // Indicate that we're at the next sector.
3131 // Local support routine
3134 _Success_(return != FALSE
) BOOLEAN
3136 _In_ PIRP_CONTEXT IrpContext
,
3142 Routine Description:
3144 This routine walks through the links of the Vcb chain in the global
3145 data structure. The remount condition is met when the following
3146 conditions are all met:
3148 If the new Vcb is a device only Mvcb and there is a previous
3151 Otherwise following conditions must be matched.
3153 1 - The 32 serial in the current VPB matches that in a previous
3156 2 - The volume label in the Vpb matches that in the previous
3159 3 - The system pointer to the real device object in the current
3160 VPB matches that in the same previous VPB.
3162 4 - Finally the previous Vcb cannot be invalid or have a dismount
3165 If a VPB is found which matches these conditions, then the address of
3166 the VCB for that VPB is returned via the pointer Vcb.
3168 Skip over the current Vcb.
3172 Vcb - This is the Vcb we are checking for a remount.
3174 OldVcb - A pointer to the address to store the address for the Vcb
3175 for the volume if this is a remount. (This is a pointer to
3180 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
3187 PVPB Vpb
= Vcb
->Vpb
;
3190 BOOLEAN Remount
= FALSE
;
3194 UNREFERENCED_PARAMETER( IrpContext
);
3197 // Check whether we are looking for a device only Mvcb.
3200 for (Link
= CdData
.VcbQueue
.Flink
;
3201 Link
!= &CdData
.VcbQueue
;
3202 Link
= Link
->Flink
) {
3204 *OldVcb
= CONTAINING_RECORD( Link
, VCB
, VcbLinks
);
3210 if (Vcb
== *OldVcb
) { continue; }
3213 // Look at the Vpb and state of the previous Vcb.
3216 OldVpb
= (*OldVcb
)->Vpb
;
3218 if ((OldVpb
!= Vpb
) &&
3219 (OldVpb
->RealDevice
== Vpb
->RealDevice
) &&
3220 ((*OldVcb
)->VcbCondition
== VcbNotMounted
)) {
3223 // If the current disk is a raw disk then it can match a previous music or
3227 if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
3229 if (FlagOn( (*OldVcb
)->VcbState
, VCB_STATE_AUDIO_DISK
)) {
3232 // If we have both TOC then fail the remount if the lengths
3233 // are different or they don't match.
3236 if ((Vcb
->TocLength
!= (*OldVcb
)->TocLength
) ||
3237 ((Vcb
->TocLength
!= 0) &&
3238 !RtlEqualMemory( Vcb
->CdromToc
,
3239 (*OldVcb
)->CdromToc
,
3240 Vcb
->TocLength
))) {
3250 // The current disk is not a raw disk. Go ahead and compare
3251 // serial numbers, volume label and TOC.
3255 else if ((OldVpb
->SerialNumber
== Vpb
->SerialNumber
) &&
3256 (Vcb
->TocLength
== (*OldVcb
)->TocLength
) &&
3257 ((Vcb
->TocLength
== 0) || RtlEqualMemory( Vcb
->CdromToc
,
3258 (*OldVcb
)->CdromToc
,
3259 Vcb
->TocLength
)) &&
3260 (Vpb
->VolumeLabelLength
== OldVpb
->VolumeLabelLength
) &&
3261 (RtlEqualMemory( OldVpb
->VolumeLabel
,
3263 Vpb
->VolumeLabelLength
))) {
3265 // Remember the old Vcb. Then set the return value to
3280 // Local support routine
3284 CdFindActiveVolDescriptor (
3285 _In_ PIRP_CONTEXT IrpContext
,
3287 _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE
)) PCHAR RawIsoVd
,
3288 _In_ BOOLEAN VerifyVolume
3293 Routine Description:
3295 This routine is called to search for a valid secondary volume descriptor that
3296 we will support. Right now we only support Joliet escape sequences for
3297 the secondary descriptor.
3299 If we don't find the secondary descriptor then we will reread the primary.
3301 This routine will update the serial number and volume label in the Vpb.
3305 Vcb - This is the Vcb for the volume being mounted.
3307 RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
3308 on input should contain the PVD (ISO) in the SECOND 'sector' of the
3311 VerifyVolume - indicates we are being called by the verify path, and should
3312 not modify the Vcb fields.
3321 BOOLEAN FoundSecondaryVd
= FALSE
;
3322 ULONG SectorOffset
= FIRST_VD_SECTOR
;
3331 // We only look for secondary volume descriptors on an Iso disk.
3334 if ((FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
) || VerifyVolume
) && !CdNoJoliet
) {
3337 // Scan the volume descriptors from the beginning looking for a valid
3338 // secondary or a terminator.
3341 SectorOffset
= FIRST_VD_SECTOR
;
3346 // Read the next sector. We should never have an error in this
3350 CdReadSectors( IrpContext
,
3351 LlBytesFromSectors( Vcb
->BaseSector
+ SectorOffset
),
3355 Vcb
->TargetDeviceObject
);
3358 // Break out if the version number or standard Id is incorrect.
3359 // Also break out if this is a terminator.
3362 if (!RtlEqualMemory( CdIsoId
, CdRvdId( RawIsoVd
, VCB_STATE_JOLIET
), VOL_ID_LEN
) ||
3363 (CdRvdVersion( RawIsoVd
, VCB_STATE_JOLIET
) != VERSION_1
) ||
3364 (CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_TERMINATOR
)) {
3370 // We have a match if this is a secondary descriptor with a matching
3374 if ((CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_SECONDARY
) &&
3375 (RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3378 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3381 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3385 if (!VerifyVolume
) {
3388 // Update the Vcb with the new volume descriptor.
3391 ClearFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
3392 SetFlag( Vcb
->VcbState
, VCB_STATE_JOLIET
);
3394 Vcb
->VdSectorOffset
= SectorOffset
;
3397 FoundSecondaryVd
= TRUE
;
3402 // Otherwise move on to the next sector.
3409 // If we didn't find the secondary then recover the original volume
3410 // descriptor stored in the second half of the RawIsoVd.
3413 if (!FoundSecondaryVd
) {
3415 RtlCopyMemory( RawIsoVd
,
3416 Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
3422 // If we're in the verify path, our work is done, since we don't want
3423 // to update any Vcb/Vpb values.
3432 // Compute the serial number and volume label from the volume descriptor.
3435 Vcb
->Vpb
->SerialNumber
= CdSerial32( RawIsoVd
, SECTOR_SIZE
);
3438 // Make sure the CD label will fit in the Vpb.
3441 NT_ASSERT( VOLUME_ID_LENGTH
* sizeof( WCHAR
) <= MAXIMUM_VOLUME_LABEL_LENGTH
);
3444 // If this is not a Unicode label we must convert it to unicode.
3447 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
3450 // Convert the label to unicode. If we get any error then use a name
3454 Vcb
->Vpb
->VolumeLabelLength
= 0;
3456 if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb
->Vpb
->VolumeLabel
[0],
3457 MAXIMUM_VOLUME_LABEL_LENGTH
,
3459 (PCH
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
3460 VOLUME_ID_LENGTH
))) {
3462 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) Length
;
3466 // We need to convert from big-endian to little endian.
3471 CdConvertBigToLittleEndian( IrpContext
,
3472 (PCHAR
) CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
3474 (PCHAR
) Vcb
->Vpb
->VolumeLabel
);
3476 Vcb
->Vpb
->VolumeLabelLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
3480 // Strip the trailing spaces or zeroes from the name.
3483 Index
= Vcb
->Vpb
->VolumeLabelLength
/ sizeof( WCHAR
);
3487 if ((Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
'\0') &&
3488 (Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
' ')) {
3497 // Now set the final length for the name.
3500 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));