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
) &&
1070 ((Vcb
->CdromToc
->LastTrack
- Vcb
->CdromToc
->FirstTrack
) == 0)) {
1072 ((FilesystemDeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1073 ((Vcb
->CdromToc
->LastTrack
- Vcb
->CdromToc
->FirstTrack
) == 0))) {
1080 Vcb
->SectorCacheBuffer
= FsRtlAllocatePool( CdPagedPool
,
1081 CD_SEC_CACHE_CHUNKS
*
1082 CD_SEC_CHUNK_BLOCKS
*
1085 for (Index
= 0; Index
< (ULONG
)CD_SEC_CACHE_CHUNKS
; Index
++) {
1087 Vcb
->SecCacheChunks
[ Index
].Buffer
= Buffer
;
1088 Vcb
->SecCacheChunks
[ Index
].BaseLbn
= (ULONG
)-1;
1090 Buffer
+= CD_SEC_CHUNK_BLOCKS
* SECTOR_SIZE
;
1093 Vcb
->SectorCacheIrp
= IoAllocateIrp( StackSize
, FALSE
);
1095 if (Vcb
->SectorCacheIrp
== NULL
) {
1097 try_leave( Status
= STATUS_INSUFFICIENT_RESOURCES
);
1100 IoInitializeIrp( Vcb
->SectorCacheIrp
,
1101 IoSizeOfIrp( StackSize
),
1104 KeInitializeEvent( &Vcb
->SectorCacheEvent
, SynchronizationEvent
, FALSE
);
1105 ExInitializeResourceLite( &Vcb
->SectorCacheResource
);
1109 // Check if this is a remount operation. If so then clean up
1110 // the data structures passed in and created here.
1113 if (CdIsRemount( IrpContext
, Vcb
, &OldVcb
)) {
1115 NT_ASSERT( NULL
!= OldVcb
->SwapVpb
);
1118 // Link the old Vcb to point to the new device object that we
1119 // should be talking to, dereferencing the previous. Call a
1120 // nonpaged routine to do this since we take the Vpb spinlock.
1123 CdReMountOldVcb( IrpContext
,
1126 DeviceObjectWeTalkTo
);
1129 // See if we will need to provide notification of the remount. This is the readonly
1130 // filesystem's form of dismount/mount notification - we promise that whenever a
1131 // volume is "dismounted", that a mount notification will occur when it is revalidated.
1132 // Note that we do not send mount on normal remounts - that would duplicate the media
1133 // arrival notification of the device driver.
1136 if (FlagOn( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1138 ClearFlag( OldVcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1140 FileObjectToNotify
= OldVcb
->RootIndexFcb
->FileObject
;
1141 ObReferenceObject( FileObjectToNotify
);
1144 try_leave( Status
= STATUS_SUCCESS
);
1148 // This is a new mount. Go ahead and initialize the
1149 // Vcb from the volume descriptor.
1152 CdUpdateVcbFromVolDescriptor( IrpContext
,
1157 // Drop an extra reference on the root dir file so we'll be able to send
1161 if (Vcb
->RootIndexFcb
) {
1163 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1164 ObReferenceObject( FileObjectToNotify
);
1168 // Now check the maximum transfer limits on the device in case we
1169 // get raw reads on this volume.
1172 Status
= CdPerformDevIoCtrl( IrpContext
,
1173 IOCTL_SCSI_GET_CAPABILITIES
,
1174 DeviceObjectWeTalkTo
,
1176 sizeof( IO_SCSI_CAPABILITIES
),
1181 if (NT_SUCCESS(Status
)) {
1183 Vcb
->MaximumTransferRawSectors
= Capabilities
.MaximumTransferLength
/ RAW_SECTOR_SIZE
;
1184 Vcb
->MaximumPhysicalPages
= Capabilities
.MaximumPhysicalPages
;
1189 // This should never happen, but we can safely assume 64k and 16 pages.
1192 Vcb
->MaximumTransferRawSectors
= (64 * 1024) / RAW_SECTOR_SIZE
;
1193 Vcb
->MaximumPhysicalPages
= 16;
1197 // The new mount is complete. Remove the additional references on this
1198 // Vcb and the device we are mounted on top of.
1201 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1202 NT_ASSERT( Vcb
->VcbReference
== CDFS_RESIDUAL_REFERENCE
);
1204 ObDereferenceObject( Vcb
->TargetDeviceObject
);
1206 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1208 CdReleaseVcb( IrpContext
, Vcb
);
1211 Status
= STATUS_SUCCESS
;
1216 // Free the TOC buffer if not in the Vcb.
1219 if (CdromToc
!= NULL
) {
1221 CdFreePool( &CdromToc
);
1225 // Free the sector buffer if allocated.
1228 if (RawIsoVd
!= NULL
) {
1230 CdFreePool( &RawIsoVd
);
1234 // If we are not mounting the device, then set the verify bit again.
1237 if ((_SEH2_AbnormalTermination() || (Status
!= STATUS_SUCCESS
)) &&
1238 SetDoVerifyOnFail
) {
1240 CdMarkRealDevForVerify( IrpContext
->RealDevice
);
1244 // If we didn't complete the mount then cleanup any remaining structures.
1247 if (Vpb
!= NULL
) { Vpb
->DeviceObject
= NULL
; }
1252 // Make sure there is no Vcb in the IrpContext since it could go away
1255 IrpContext
->Vcb
= NULL
;
1257 Vcb
->VcbReference
-= CDFS_RESIDUAL_REFERENCE
;
1259 if (CdDismountVcb( IrpContext
, Vcb
)) {
1261 CdReleaseVcb( IrpContext
, Vcb
);
1264 } else if (VolDo
!= NULL
) {
1266 IoDeleteDevice( (PDEVICE_OBJECT
) VolDo
);
1270 // Release the global resource.
1273 CdReleaseCdData( IrpContext
);
1277 // Now send mount notification.
1280 if (FileObjectToNotify
) {
1282 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1283 ObDereferenceObject( FileObjectToNotify
);
1286 #ifdef CDFS_TELEMETRY_DATA
1292 CdTelemetryMountSafe( &VolumeCorrelationId
, STATUS_SUCCESS
, Vcb
);
1297 // Complete the request if no exception.
1300 CdCompleteRequest( IrpContext
, Irp
, Status
);
1306 // Local support routine
1309 _Requires_lock_held_(_Global_critical_region_
)
1312 _Inout_ PIRP_CONTEXT IrpContext
,
1318 Routine Description:
1320 This routine performs the verify volume operation. It is responsible for
1321 either completing of enqueuing the input Irp.
1325 Irp - Supplies the Irp to process
1329 NTSTATUS - The return status for the operation
1334 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1335 PVPB Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
1336 PVCB Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->Parameters
.VerifyVolume
.DeviceObject
)->Vcb
;
1338 PCHAR RawIsoVd
= NULL
;
1340 PCDROM_TOC_LARGE CdromToc
= NULL
;
1341 ULONG TocLength
= 0;
1342 ULONG TocTrackCount
= 0;
1343 ULONG TocDiskFlags
= 0;
1345 ULONG MediaChangeCount
= Vcb
->MediaChangeCount
;
1347 PFILE_OBJECT FileObjectToNotify
= NULL
;
1349 BOOLEAN ReturnError
;
1350 BOOLEAN ReleaseVcb
= FALSE
;
1352 IO_STATUS_BLOCK Iosb
;
1355 UNICODE_STRING UnicodeLabel
;
1357 WCHAR VolumeLabel
[ VOLUME_ID_LENGTH
];
1358 ULONG VolumeLabelLength
;
1362 NTSTATUS Status
= STATUS_SUCCESS
;
1367 // We check that we are talking to a Cdrom device.
1370 NT_ASSERT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
);
1371 NT_ASSERT( FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
));
1374 // Update the real device in the IrpContext from the Vpb. There was no available
1375 // file object when the IrpContext was created.
1378 IrpContext
->RealDevice
= Vpb
->RealDevice
;
1381 // Acquire the global resource to synchronise against mounts and teardown,
1382 // finally clause releases.
1385 CdAcquireCdData( IrpContext
);
1389 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
1393 // Check to see if the volume is eligible for verification.
1396 if ((Vcb
->VcbCondition
== VcbInvalid
) ||
1397 (Vcb
->VcbCondition
== VcbDismountInProgress
)) {
1399 try_return( Status
= STATUS_WRONG_VOLUME
);
1403 // Verify that there is a disk here.
1406 Status
= CdPerformDevIoCtrl( IrpContext
,
1407 IOCTL_CDROM_CHECK_VERIFY
,
1408 Vcb
->TargetDeviceObject
,
1415 if (!NT_SUCCESS( Status
)) {
1418 // If we will allow a raw mount then return WRONG_VOLUME to
1419 // allow the volume to be mounted by raw.
1422 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1424 Status
= STATUS_WRONG_VOLUME
;
1427 try_return( Status
);
1430 if (Iosb
.Information
!= sizeof(ULONG
)) {
1433 // Be safe about the count in case the driver didn't fill it in
1436 MediaChangeCount
= 0;
1440 // Verify that the device actually saw a change. If the driver does not
1441 // support the MCC, then we must verify the volume in any case.
1444 if (MediaChangeCount
== 0 ||
1445 (Vcb
->MediaChangeCount
!= MediaChangeCount
)) {
1448 // Allocate a buffer to query the TOC.
1451 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
1452 sizeof( CDROM_TOC_LARGE
),
1455 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC_LARGE
));
1458 // Let's query for the Toc now and handle any error we get from this operation.
1461 Status
= CdProcessToc( IrpContext
,
1462 Vcb
->TargetDeviceObject
,
1469 // If we failed to read the TOC, then give up now. Drives will fail
1470 // a TOC read on, for example, erased CD-RW media.
1473 if (Status
!= STATUS_SUCCESS
) {
1476 // For any errors other than no media and not ready, commute the
1477 // status to ensure that the current VPB is kicked off the device
1478 // below - there is probably blank media in the drive, since we got
1479 // further than the check verify.
1482 if (!CdIsRawDevice( IrpContext
, Status
)) {
1484 Status
= STATUS_WRONG_VOLUME
;
1487 try_return( Status
);
1490 // We got a TOC. Verify that it matches the previous Toc.
1493 } else if ((Vcb
->TocLength
!= TocLength
) ||
1494 (Vcb
->TrackCount
!= TocTrackCount
) ||
1495 (Vcb
->DiskFlags
!= TocDiskFlags
) ||
1496 !RtlEqualMemory( CdromToc
,
1500 try_return( Status
= STATUS_WRONG_VOLUME
);
1504 // If the disk to verify is an audio disk then we already have a
1505 // match. Otherwise we need to check the volume descriptor.
1508 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
1511 // Allocate a buffer for the sector buffer.
1514 RawIsoVd
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
1515 ROUND_TO_PAGES( 2 * SECTOR_SIZE
),
1519 // Read the primary volume descriptor for this volume. If we
1520 // get an io error and this verify was a the result of DASD open,
1521 // commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
1522 // expect a music disk then this request should fail.
1525 ReturnError
= FALSE
;
1527 if (FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
1532 if (!CdFindPrimaryVd( IrpContext
,
1540 // If the previous Vcb did not represent a raw disk
1541 // then show this volume was dismounted.
1544 try_return( Status
= STATUS_WRONG_VOLUME
);
1550 // Look for a supplementary VD.
1552 // Store the primary volume descriptor in the second half of
1553 // RawIsoVd. Then if our search for a secondary fails we can
1554 // recover this immediately.
1557 RtlCopyMemory( Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
1562 // We have the initial volume descriptor. Locate a secondary
1563 // volume descriptor if present.
1566 CdFindActiveVolDescriptor( IrpContext
,
1571 // Compare the serial numbers. If they don't match, set the
1572 // status to wrong volume.
1575 if (Vpb
->SerialNumber
!= CdSerial32( RawIsoVd
, SECTOR_SIZE
)) {
1577 try_return( Status
= STATUS_WRONG_VOLUME
);
1581 // Verify the volume labels.
1584 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
1587 // Compute the length of the volume name
1590 AnsiLabel
.Buffer
= (PCHAR
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
);
1591 AnsiLabel
.MaximumLength
= AnsiLabel
.Length
= (ULONG
)VOLUME_ID_LENGTH
;
1593 UnicodeLabel
.MaximumLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
1594 UnicodeLabel
.Buffer
= VolumeLabel
;
1597 // Convert this to unicode. If we get any error then use a name
1601 VolumeLabelLength
= 0;
1603 if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel
,
1607 VolumeLabelLength
= UnicodeLabel
.Length
;
1611 // We need to convert from big-endian to little endian.
1616 CdConvertBigToLittleEndian( IrpContext
,
1617 (PCHAR
) CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
1619 (PCHAR
) VolumeLabel
);
1621 VolumeLabelLength
= VOLUME_ID_LENGTH
;
1625 // Strip the trailing spaces or zeroes from the name.
1628 Index
= VolumeLabelLength
/ sizeof( WCHAR
);
1632 if ((VolumeLabel
[ Index
- 1 ] != L
'\0') &&
1633 (VolumeLabel
[ Index
- 1 ] != L
' ')) {
1642 // Now set the final length for the name.
1645 VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));
1648 // Now check that the label matches.
1650 if ((Vpb
->VolumeLabelLength
!= VolumeLabelLength
) ||
1651 !RtlEqualMemory( Vpb
->VolumeLabel
,
1653 VolumeLabelLength
)) {
1655 try_return( Status
= STATUS_WRONG_VOLUME
);
1662 // The volume is OK, clear the verify bit.
1665 CdUpdateVcbCondition( Vcb
, VcbMounted
);
1667 CdMarkRealDevVerifyOk( Vpb
->RealDevice
);
1670 // See if we will need to provide notification of the remount. This is the readonly
1671 // filesystem's form of dismount/mount notification.
1674 if (FlagOn( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
)) {
1676 ClearFlag( Vcb
->VcbState
, VCB_STATE_NOTIFY_REMOUNT
);
1678 FileObjectToNotify
= Vcb
->RootIndexFcb
->FileObject
;
1679 ObReferenceObject( FileObjectToNotify
);
1685 // Update the media change count to note that we have verified the volume
1686 // at this value - regardless of the outcome.
1689 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
1692 // If the volume was already unmounted, nothing more to do.
1695 if (Vcb
->VcbCondition
== VcbNotMounted
) {
1697 Status
= STATUS_WRONG_VOLUME
;
1700 // If we got the wrong volume then free any remaining XA sector in
1701 // the current Vcb. Also mark the Vcb as not mounted.
1704 } else if ((Vcb
->VcbCondition
== VcbMounted
) && (Status
== STATUS_WRONG_VOLUME
)) {
1706 CdUpdateVcbCondition( Vcb
, VcbNotMounted
);
1708 if (Vcb
->XASector
!= NULL
) {
1710 CdFreePool( &Vcb
->XASector
);
1712 Vcb
->XADiskOffset
= 0;
1715 CdFreeDirCache( IrpContext
);
1718 // Now, if there are no user handles to the volume, try to spark
1719 // teardown by purging the volume.
1722 if (Vcb
->VcbCleanup
== 0) {
1724 if (NT_SUCCESS( CdPurgeVolume( IrpContext
, Vcb
, FALSE
))) {
1726 ReleaseVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
1734 // Free the TOC buffer if allocated.
1737 if (CdromToc
!= NULL
) {
1739 CdFreePool( &CdromToc
);
1742 if (RawIsoVd
!= NULL
) {
1744 CdFreePool( &RawIsoVd
);
1749 CdReleaseVcb( IrpContext
, Vcb
);
1752 _Analysis_assume_lock_not_held_(Vcb
->VcbResource
);
1755 CdReleaseCdData( IrpContext
);
1759 // Now send mount notification.
1762 if (FileObjectToNotify
) {
1764 FsRtlNotifyVolumeEvent( FileObjectToNotify
, FSRTL_VOLUME_MOUNT
);
1765 ObDereferenceObject( FileObjectToNotify
);
1769 // Complete the request if no exception.
1772 CdCompleteRequest( IrpContext
, Irp
, Status
);
1778 // Local support routine
1781 _Requires_lock_held_(_Global_critical_region_
)
1784 _Inout_ PIRP_CONTEXT IrpContext
,
1790 Routine Description:
1792 This is the common routine to handle oplock requests made via the
1793 NtFsControlFile call.
1797 Irp - Supplies the Irp being processed
1801 NTSTATUS - The return status for the operation
1806 NTSTATUS Status
= STATUS_SUCCESS
;
1810 ULONG OplockCount
= 0;
1811 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1816 // We only permit oplock requests on files.
1819 if (CdDecodeFileObject( IrpContext
,
1822 &Ccb
) != UserFileOpen
) {
1824 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1825 return STATUS_INVALID_PARAMETER
;
1829 // Make this a waitable Irpcontext so we don't fail to acquire
1833 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1834 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1837 // Switch on the function control code. We grab the Fcb exclusively
1838 // for oplock requests, shared for oplock break acknowledgement.
1841 switch (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
) {
1843 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
1844 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
1845 case FSCTL_REQUEST_BATCH_OPLOCK
:
1846 case FSCTL_REQUEST_FILTER_OPLOCK
:
1848 CdAcquireFcbExclusive( IrpContext
, Fcb
, FALSE
);
1850 if (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_REQUEST_OPLOCK_LEVEL_2
) {
1852 if (Fcb
->FileLock
!= NULL
) {
1854 #if (NTDDI_VERSION >= NTDDI_WIN7)
1855 OplockCount
= (ULONG
) FsRtlAreThereCurrentOrInProgressFileLocks( Fcb
->FileLock
);
1857 OplockCount
= (ULONG
) FsRtlAreThereCurrentFileLocks( Fcb
->FileLock
);
1863 OplockCount
= Fcb
->FcbCleanup
;
1868 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
1869 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
1870 case FSCTL_OPLOCK_BREAK_NOTIFY
:
1871 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
1873 CdAcquireFcbShared( IrpContext
, Fcb
, FALSE
);
1878 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1879 return STATUS_INVALID_PARAMETER
;
1883 // Use a try finally to free the Fcb.
1892 CdVerifyFcbOperation( IrpContext
, Fcb
);
1895 // Call the FsRtl routine to grant/acknowledge oplock.
1898 Status
= FsRtlOplockFsctrl( CdGetFcbOplock(Fcb
),
1903 // Set the flag indicating if Fast I/O is possible
1906 CdLockFcb( IrpContext
, Fcb
);
1907 Fcb
->IsFastIoPossible
= CdIsFastIoPossible( Fcb
);
1908 CdUnlockFcb( IrpContext
, Fcb
);
1911 // The oplock package will complete the Irp.
1919 // Release all of our resources
1922 CdReleaseFcb( IrpContext
, Fcb
);
1926 // Complete the request if there was no exception.
1929 CdCompleteRequest( IrpContext
, Irp
, Status
);
1935 // Local support routine
1938 _Requires_lock_held_(_Global_critical_region_
)
1941 _Inout_ PIRP_CONTEXT IrpContext
,
1947 Routine Description:
1949 This routine performs the lock volume operation. It is responsible for
1950 either completing of enqueuing the input Irp.
1954 Irp - Supplies the Irp to process
1958 NTSTATUS - The return status for the operation
1963 NTSTATUS Status
= STATUS_SUCCESS
;
1965 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1974 // Decode the file object, the only type of opens we accept are
1975 // user volume opens.
1978 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
1980 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
1982 return STATUS_INVALID_PARAMETER
;
1986 // Send our notification so that folks that like to hold handles on
1987 // volumes can get out of the way.
1990 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
1993 // Acquire exclusive access to the Vcb.
1997 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2005 CdVerifyVcb( IrpContext
, Vcb
);
2007 Status
= CdLockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2015 CdReleaseVcb( IrpContext
, Vcb
);
2017 if (_SEH2_AbnormalTermination() || !NT_SUCCESS( Status
)) {
2019 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
2024 // Complete the request if there haven't been any exceptions.
2027 CdCompleteRequest( IrpContext
, Irp
, Status
);
2033 // Local support routine
2036 _Requires_lock_held_(_Global_critical_region_
)
2039 _Inout_ PIRP_CONTEXT IrpContext
,
2045 Routine Description:
2047 This routine performs the unlock volume operation. It is responsible for
2048 either completing of enqueuing the input Irp.
2052 Irp - Supplies the Irp to process
2056 NTSTATUS - The return status for the operation
2063 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2072 // Decode the file object, the only type of opens we accept are
2073 // user volume opens.
2076 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2078 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2079 return STATUS_INVALID_PARAMETER
;
2083 // Acquire exclusive access to the Vcb.
2088 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2091 // We won't check for a valid Vcb for this request. An unlock will always
2092 // succeed on a locked volume.
2095 Status
= CdUnlockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2098 // Release all of our resources
2101 CdReleaseVcb( IrpContext
, Vcb
);
2104 // Send notification that the volume is avaliable.
2107 if (NT_SUCCESS( Status
)) {
2109 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
2113 // Complete the request if there haven't been any exceptions.
2116 CdCompleteRequest( IrpContext
, Irp
, Status
);
2123 // Local support routine
2126 _Requires_lock_held_(_Global_critical_region_
)
2129 _Inout_ PIRP_CONTEXT IrpContext
,
2135 Routine Description:
2137 This routine performs the dismount volume operation. It is responsible for
2138 either completing of enqueuing the input Irp. We only dismount a volume which
2139 has been locked. The intent here is that someone has locked the volume (they are the
2140 only remaining handle). We set the verify bit here and the user will close his handle.
2141 We will dismount a volume with no user's handles in the verify path.
2145 Irp - Supplies the Irp to process
2149 NTSTATUS - The return status for the operation
2155 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2163 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2165 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2166 return STATUS_INVALID_PARAMETER
;
2172 // Send dismount notification.
2175 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_DISMOUNT
);
2178 // Make this request waitable.
2181 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2184 // Acquire exclusive access to the Vcb, and take the global resource to
2185 // sync. against mounts, verifies etc.
2188 CdAcquireCdData( IrpContext
);
2189 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2192 // Mark the volume as needs to be verified, but only do it if
2193 // the vcb is locked by this handle and the volume is currently mounted.
2196 if (Vcb
->VcbCondition
!= VcbMounted
) {
2198 Status
= STATUS_VOLUME_DISMOUNTED
;
2203 // Invalidate the volume right now.
2205 // The intent here is to make every subsequent operation
2206 // on the volume fail and grease the rails toward dismount.
2207 // By definition there is no going back from a SURPRISE.
2210 CdLockVcb( IrpContext
, Vcb
);
2212 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2214 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2217 SetFlag( Vcb
->VcbState
, VCB_STATE_DISMOUNTED
);
2219 CdUnlockVcb( IrpContext
, Vcb
);
2223 // Set flag to tell the close path that we want to force dismount
2224 // the volume when this handle is closed.
2227 SetFlag( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
);
2229 Status
= STATUS_SUCCESS
;
2233 // Release all of our resources
2236 CdReleaseVcb( IrpContext
, Vcb
);
2237 CdReleaseCdData( IrpContext
);
2239 #if (NTDDI_VERSION >= NTDDI_WIN8)
2241 FsRtlDismountComplete( Vcb
->TargetDeviceObject
, Status
);
2246 // Complete the request if there haven't been any exceptions.
2249 CdCompleteRequest( IrpContext
, Irp
, Status
);
2255 // Local support routine
2260 _Inout_ PIRP_CONTEXT IrpContext
,
2266 Routine Description:
2268 This routine determines if a volume is currently dirty.
2272 Irp - Supplies the Irp to process
2276 NTSTATUS - The return status for the operation
2281 PIO_STACK_LOCATION IrpSp
;
2283 TYPE_OF_OPEN TypeOfOpen
;
2292 // Get the current stack location and extract the output
2293 // buffer information.
2296 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2299 // Get a pointer to the output buffer.
2302 if (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
) {
2304 VolumeState
= Irp
->AssociatedIrp
.SystemBuffer
;
2308 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_USER_BUFFER
);
2309 return STATUS_INVALID_USER_BUFFER
;
2313 // Make sure the output buffer is large enough and then initialize
2314 // the answer to be that the volume isn't dirty.
2317 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
)) {
2319 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2320 return STATUS_INVALID_PARAMETER
;
2326 // Decode the file object
2329 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2331 if (TypeOfOpen
!= UserVolumeOpen
) {
2333 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2334 return STATUS_INVALID_PARAMETER
;
2337 if (Fcb
->Vcb
->VcbCondition
!= VcbMounted
) {
2339 CdCompleteRequest( IrpContext
, Irp
, STATUS_VOLUME_DISMOUNTED
);
2340 return STATUS_VOLUME_DISMOUNTED
;
2344 // Now set up to return the clean state. CDs obviously can never be dirty
2345 // but we want to make sure we have enforced the full semantics of this call.
2348 Irp
->IoStatus
.Information
= sizeof( ULONG
);
2350 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2351 return STATUS_SUCCESS
;
2356 // Local support routine
2361 _Inout_ PIRP_CONTEXT IrpContext
,
2367 Routine Description:
2369 This routine determines if a volume is currently mounted.
2373 Irp - Supplies the Irp to process
2377 NTSTATUS - The return status for the operation
2382 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2390 // Decode the file object.
2393 CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
2398 // Disable PopUps, we want to return any error.
2401 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
2404 // Verify the Vcb. This will raise in the error condition.
2407 CdVerifyVcb( IrpContext
, Fcb
->Vcb
);
2410 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2412 return STATUS_SUCCESS
;
2417 // Local support routine
2422 _Inout_ PIRP_CONTEXT IrpContext
,
2428 Routine Description:
2430 This routine determines if pathname is a valid CDFS pathname.
2431 We always succeed this request.
2435 Irp - Supplies the Irp to process.
2446 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2447 return STATUS_SUCCESS
;
2452 // Local support routine
2455 _Requires_lock_held_(_Global_critical_region_
)
2457 CdInvalidateVolumes (
2458 _Inout_ PIRP_CONTEXT IrpContext
,
2464 Routine Description:
2466 This routine searches for all the volumes mounted on the same real device
2467 of the current DASD handle, and marks them all bad. The only operation
2468 that can be done on such handles is cleanup and close.
2472 Irp - Supplies the Irp to process
2476 NTSTATUS - The return status for the operation
2482 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2485 BOOLEAN UnlockVcb
= FALSE
;
2487 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
2495 PFILE_OBJECT FileToMarkBad
;
2496 PDEVICE_OBJECT DeviceToMarkBad
;
2499 // We only allow the invalidate call to come in on our file system devices.
2503 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
2505 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
&&
2506 IrpSp
->DeviceObject
!= CdData
.HddFileSystemDeviceObject
) {
2509 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
2511 return STATUS_INVALID_DEVICE_REQUEST
;
2515 // Check for the correct security access.
2516 // The caller must have the SeTcbPrivilege.
2519 if (!SeSinglePrivilegeCheck( TcbPrivilege
, Irp
->RequestorMode
)) {
2521 CdCompleteRequest( IrpContext
, Irp
, STATUS_PRIVILEGE_NOT_HELD
);
2523 return STATUS_PRIVILEGE_NOT_HELD
;
2527 // Try to get a pointer to the device object from the handle passed in.
2530 #if defined(_WIN64) && BUILD_WOW64_ENABLED
2532 if (IoIs32bitProcess( Irp
)) {
2534 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( UINT32
)) {
2536 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2537 return STATUS_INVALID_PARAMETER
;
2540 Handle
= (HANDLE
) LongToHandle( *((PUINT32
) Irp
->AssociatedIrp
.SystemBuffer
) );
2547 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof( HANDLE
)) {
2549 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2550 return STATUS_INVALID_PARAMETER
;
2553 Handle
= *((PHANDLE
) Irp
->AssociatedIrp
.SystemBuffer
);
2556 Status
= ObReferenceObjectByHandle( Handle
,
2560 (PVOID
*)&FileToMarkBad
, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
2563 if (!NT_SUCCESS(Status
)) {
2565 CdCompleteRequest( IrpContext
, Irp
, Status
);
2570 // Grab the DeviceObject from the FileObject.
2573 DeviceToMarkBad
= FileToMarkBad
->DeviceObject
;
2576 // We only needed the device object involved, not a reference to the file.
2579 ObDereferenceObject( FileToMarkBad
);
2582 // Make sure this request can wait.
2585 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2586 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
2589 // Synchronise with pnp/mount/verify paths.
2592 CdAcquireCdData( IrpContext
);
2595 // Nothing can go wrong now.
2599 // Now walk through all the mounted Vcb's looking for candidates to
2602 // On volumes we mark invalid, check for dismount possibility (which is
2603 // why we have to get the next link so early).
2606 Links
= CdData
.VcbQueue
.Flink
;
2608 while (Links
!= &CdData
.VcbQueue
) {
2610 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2612 Links
= Links
->Flink
;
2615 // If we get a match, mark the volume Bad, and also check to
2616 // see if the volume should go away.
2619 CdLockVcb( IrpContext
, Vcb
);
2621 if (Vcb
->Vpb
->RealDevice
== DeviceToMarkBad
) {
2624 // Take the VPB spinlock, and look to see if this volume is the
2625 // one currently mounted on the actual device. If it is, pull it
2629 IoAcquireVpbSpinLock( &SavedIrql
);
2632 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed")
2634 if (DeviceToMarkBad
->Vpb
== Vcb
->Vpb
) {
2636 PVPB NewVpb
= Vcb
->SwapVpb
;
2638 NT_ASSERT( FlagOn( Vcb
->Vpb
->Flags
, VPB_MOUNTED
));
2639 NT_ASSERT( NULL
!= NewVpb
);
2641 RtlZeroMemory( NewVpb
, sizeof( VPB
) );
2643 NewVpb
->Type
= IO_TYPE_VPB
;
2644 NewVpb
->Size
= sizeof( VPB
);
2645 NewVpb
->RealDevice
= DeviceToMarkBad
;
2648 #pragma prefast(push)
2649 #pragma prefast(disable: 28175, "this is a filesystem driver, touching the vpb is allowed")
2651 NewVpb
->Flags
= FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_REMOVE_PENDING
);
2652 DeviceToMarkBad
->Vpb
= NewVpb
;
2654 #pragma prefast(pop)
2657 Vcb
->SwapVpb
= NULL
;
2660 IoReleaseVpbSpinLock( SavedIrql
);
2662 if (Vcb
->VcbCondition
!= VcbDismountInProgress
) {
2664 CdUpdateVcbCondition( Vcb
, VcbInvalid
);
2667 CdUnlockVcb( IrpContext
, Vcb
);
2669 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
2671 CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
2673 UnlockVcb
= CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2676 // prefast: if UnlockVcb is false, then the VCB was already deleted, so we better not touch the Vcb.
2677 // tell Prefast something nice so it stops complaining about us leaking it.
2680 __analysis_assert( UnlockVcb
== TRUE
);
2684 CdReleaseVcb( IrpContext
, Vcb
);
2689 CdUnlockVcb( IrpContext
, Vcb
);
2693 CdReleaseCdData( IrpContext
);
2695 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
2696 return STATUS_SUCCESS
;
2701 // Local support routine
2705 CdAllowExtendedDasdIo (
2706 _Inout_ PIRP_CONTEXT IrpContext
,
2712 Routine Description:
2714 This routine marks the CCB to indicate that the handle
2715 may be used to read past the end of the volume file. The
2716 handle must be a dasd handle.
2720 Irp - Supplies the Irp to process
2724 NTSTATUS - The return status for the operation
2730 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2738 // Decode the file object, the only type of opens we accept are
2739 // user volume opens.
2742 if (CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2744 Status
= STATUS_INVALID_PARAMETER
;
2748 SetFlag( Ccb
->Flags
, CCB_FLAG_ALLOW_EXTENDED_DASD_IO
);
2749 Status
= STATUS_SUCCESS
;
2752 CdCompleteRequest( IrpContext
, Irp
, Status
);
2758 // Local support routine
2761 _Requires_lock_held_(_Global_critical_region_
)
2763 CdScanForDismountedVcb (
2764 _Inout_ PIRP_CONTEXT IrpContext
2769 Routine Description:
2771 This routine walks through the list of Vcb's looking for any which may
2772 now be deleted. They may have been left on the list because there were
2773 outstanding references.
2790 // Walk through all of the Vcb's attached to the global data.
2793 Links
= CdData
.VcbQueue
.Flink
;
2795 while (Links
!= &CdData
.VcbQueue
) {
2797 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
2800 // Move to the next link now since the current Vcb may be deleted.
2803 Links
= Links
->Flink
;
2806 // If dismount is already underway then check if this Vcb can
2810 if ((Vcb
->VcbCondition
== VcbDismountInProgress
) ||
2811 (Vcb
->VcbCondition
== VcbInvalid
) ||
2812 ((Vcb
->VcbCondition
== VcbNotMounted
) && (Vcb
->VcbReference
<= CDFS_RESIDUAL_REFERENCE
))) {
2814 CdCheckForDismount( IrpContext
, Vcb
, FALSE
);
2823 // Local support routine
2825 _Success_(return != FALSE
)
2828 _In_ PIRP_CONTEXT IrpContext
,
2830 _Out_writes_bytes_(SECTOR_SIZE
) PCHAR RawIsoVd
,
2831 _In_ ULONG BlockFactor
,
2832 _In_ BOOLEAN ReturnOnError
,
2833 _In_ BOOLEAN VerifyVolume
2838 Routine Description:
2840 This routine is called to walk through the volume descriptors looking
2841 for a primary volume descriptor. When/if a primary is found a 32-bit
2842 serial number is generated and stored into the Vpb. We also store the
2843 location of the primary volume descriptor in the Vcb.
2847 Vcb - Pointer to the VCB for the volume.
2849 RawIsoVd - Pointer to a sector buffer which will contain the primary
2850 volume descriptor on exit, if successful.
2852 BlockFactor - Block factor used by the current device for the TableOfContents.
2854 ReturnOnError - Indicates that we should raise on I/O errors rather than
2855 returning a FALSE value.
2857 VerifyVolume - Indicates if we were called from the verify path. We
2858 do a few things different in this path. We don't update the Vcb in
2863 BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
2871 BOOLEAN FoundVd
= FALSE
;
2876 PCDROM_TOC_LARGE CdromToc
;
2883 // If there are no data tracks, don't even bother hunting for descriptors.
2885 // This explicitly breaks various non-BlueBook compliant CDs that scribble
2886 // an ISO filesystem on media claiming only audio tracks. Since these
2887 // disks can cause serious problems in some CDROM units, fail fast. I admit
2888 // that it is possible that someone can still record the descriptors in the
2889 // audio track, record a data track (but fail to record descriptors there)
2890 // and still have the disk work. As this form of error worked in NT 4.0, and
2891 // since these disks really do exist, I don't want to change them.
2893 // If we wished to support all such media (we don't), it would be neccesary
2894 // to clear this flag on finding ISO or HSG descriptors below.
2897 if (FlagOn(Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
2903 // We will make at most two passes through the volume descriptor sequence.
2905 // On the first pass we will query for the last session. Using this
2906 // as a starting offset we will attempt to mount the volume. On any failure
2907 // we will go to the second pass and try without using any multi-session
2910 // On the second pass we will start offset from sector zero.
2913 while (!FoundVd
&& (ThisPass
<= 2)) {
2916 // If we aren't at pass 1 then we start at sector 0. Otherwise we
2917 // try to look up the multi-session information.
2922 if (ThisPass
== 1) {
2927 // Check for whether this device supports XA and multi-session.
2933 // Allocate a buffer for the last session information.
2936 CdromToc
= FsRtlAllocatePoolWithTag( CdPagedPool
,
2937 sizeof( CDROM_TOC_LARGE
),
2940 RtlZeroMemory( CdromToc
, sizeof( CDROM_TOC_LARGE
));
2943 // Query the last session information from the driver.
2946 Status
= CdPerformDevIoCtrl( IrpContext
,
2947 IOCTL_CDROM_GET_LAST_SESSION
,
2948 Vcb
->TargetDeviceObject
,
2950 sizeof( CDROM_TOC_LARGE
),
2956 // Raise an exception if there was an allocation failure.
2959 if (Status
== STATUS_INSUFFICIENT_RESOURCES
) {
2961 CdRaiseStatus( IrpContext
, Status
);
2965 // We don't handle any errors yet. We will hit that below
2966 // as we try to scan the disk. If we have last session information
2967 // then modify the base sector.
2970 if (NT_SUCCESS( Status
) &&
2971 (CdromToc
->FirstTrack
!= CdromToc
->LastTrack
)) {
2979 // The track address is BigEndian, we need to flip the bytes.
2982 Source
= (PCHAR
) &CdromToc
->TrackData
[0].Address
[3];
2983 Dest
= (PCHAR
) &BaseSector
;
2987 *Dest
++ = *Source
--;
2992 // Now adjust the base sector by the block factor of the
2996 BaseSector
/= BlockFactor
;
2999 // Make this look like the second pass since we are only using the
3000 // first session. No reason to retry on error.
3010 if (CdromToc
!= NULL
) { CdFreePool( &CdromToc
); }
3015 // Compute the starting sector offset from the start of the session.
3018 SectorOffset
= FIRST_VD_SECTOR
;
3021 // Start by assuming we have neither Hsg or Iso volumes.
3027 // Loop until either error encountered, primary volume descriptor is
3028 // found or a terminal volume descriptor is found.
3034 // Attempt to read the desired sector. Exit directly if operation
3037 // If this is pass 1 we will ignore errors in read sectors and just
3038 // go to the next pass.
3041 if (!CdReadSectors( IrpContext
,
3042 LlBytesFromSectors( BaseSector
+ SectorOffset
),
3044 (BOOLEAN
) ((ThisPass
== 1) || ReturnOnError
),
3046 Vcb
->TargetDeviceObject
)) {
3052 // Check if either an ISO or HSG volume.
3055 if (RtlEqualMemory( CdIsoId
,
3056 CdRvdId( RawIsoVd
, VCB_STATE_ISO
),
3059 SetFlag( VolumeFlags
, VCB_STATE_ISO
);
3061 } else if (RtlEqualMemory( CdHsgId
,
3062 CdRvdId( RawIsoVd
, VCB_STATE_HSG
),
3065 SetFlag( VolumeFlags
, VCB_STATE_HSG
);
3068 // We have neither so break out of the loop.
3077 // Break out if the version number is incorrect or this is
3081 if ((CdRvdVersion( RawIsoVd
, VolumeFlags
) != VERSION_1
) ||
3082 (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_TERMINATOR
)) {
3088 // If this is a primary volume descriptor then our search is over.
3091 if (CdRvdDescType( RawIsoVd
, VolumeFlags
) == VD_PRIMARY
) {
3094 // If we are not in the verify path then initialize the
3095 // fields in the Vcb with basic information from this
3099 if (!VerifyVolume
) {
3102 // Set the flag for the volume type.
3105 SetFlag( Vcb
->VcbState
, VolumeFlags
);
3108 // Store the base sector and sector offset for the
3109 // primary volume descriptor.
3112 Vcb
->BaseSector
= BaseSector
;
3113 Vcb
->VdSectorOffset
= SectorOffset
;
3114 Vcb
->PrimaryVdSectorOffset
= SectorOffset
;
3122 // Indicate that we're at the next sector.
3136 // Local support routine
3139 _Success_(return != FALSE
) BOOLEAN
3141 _In_ PIRP_CONTEXT IrpContext
,
3147 Routine Description:
3149 This routine walks through the links of the Vcb chain in the global
3150 data structure. The remount condition is met when the following
3151 conditions are all met:
3153 If the new Vcb is a device only Mvcb and there is a previous
3156 Otherwise following conditions must be matched.
3158 1 - The 32 serial in the current VPB matches that in a previous
3161 2 - The volume label in the Vpb matches that in the previous
3164 3 - The system pointer to the real device object in the current
3165 VPB matches that in the same previous VPB.
3167 4 - Finally the previous Vcb cannot be invalid or have a dismount
3170 If a VPB is found which matches these conditions, then the address of
3171 the VCB for that VPB is returned via the pointer Vcb.
3173 Skip over the current Vcb.
3177 Vcb - This is the Vcb we are checking for a remount.
3179 OldVcb - A pointer to the address to store the address for the Vcb
3180 for the volume if this is a remount. (This is a pointer to
3185 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
3192 PVPB Vpb
= Vcb
->Vpb
;
3195 BOOLEAN Remount
= FALSE
;
3199 UNREFERENCED_PARAMETER( IrpContext
);
3202 // Check whether we are looking for a device only Mvcb.
3205 for (Link
= CdData
.VcbQueue
.Flink
;
3206 Link
!= &CdData
.VcbQueue
;
3207 Link
= Link
->Flink
) {
3209 *OldVcb
= CONTAINING_RECORD( Link
, VCB
, VcbLinks
);
3215 if (Vcb
== *OldVcb
) { continue; }
3218 // Look at the Vpb and state of the previous Vcb.
3221 OldVpb
= (*OldVcb
)->Vpb
;
3223 if ((OldVpb
!= Vpb
) &&
3224 (OldVpb
->RealDevice
== Vpb
->RealDevice
) &&
3225 ((*OldVcb
)->VcbCondition
== VcbNotMounted
)) {
3228 // If the current disk is a raw disk then it can match a previous music or
3232 if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
3234 if (FlagOn( (*OldVcb
)->VcbState
, VCB_STATE_AUDIO_DISK
)) {
3237 // If we have both TOC then fail the remount if the lengths
3238 // are different or they don't match.
3241 if ((Vcb
->TocLength
!= (*OldVcb
)->TocLength
) ||
3242 ((Vcb
->TocLength
!= 0) &&
3243 !RtlEqualMemory( Vcb
->CdromToc
,
3244 (*OldVcb
)->CdromToc
,
3245 Vcb
->TocLength
))) {
3255 // The current disk is not a raw disk. Go ahead and compare
3256 // serial numbers, volume label and TOC.
3260 else if ((OldVpb
->SerialNumber
== Vpb
->SerialNumber
) &&
3261 (Vcb
->TocLength
== (*OldVcb
)->TocLength
) &&
3262 ((Vcb
->TocLength
== 0) || RtlEqualMemory( Vcb
->CdromToc
,
3263 (*OldVcb
)->CdromToc
,
3264 Vcb
->TocLength
)) &&
3265 (Vpb
->VolumeLabelLength
== OldVpb
->VolumeLabelLength
) &&
3266 (RtlEqualMemory( OldVpb
->VolumeLabel
,
3268 Vpb
->VolumeLabelLength
))) {
3270 // Remember the old Vcb. Then set the return value to
3285 // Local support routine
3289 CdFindActiveVolDescriptor (
3290 _In_ PIRP_CONTEXT IrpContext
,
3292 _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE
)) PCHAR RawIsoVd
,
3293 _In_ BOOLEAN VerifyVolume
3298 Routine Description:
3300 This routine is called to search for a valid secondary volume descriptor that
3301 we will support. Right now we only support Joliet escape sequences for
3302 the secondary descriptor.
3304 If we don't find the secondary descriptor then we will reread the primary.
3306 This routine will update the serial number and volume label in the Vpb.
3310 Vcb - This is the Vcb for the volume being mounted.
3312 RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
3313 on input should contain the PVD (ISO) in the SECOND 'sector' of the
3316 VerifyVolume - indicates we are being called by the verify path, and should
3317 not modify the Vcb fields.
3326 BOOLEAN FoundSecondaryVd
= FALSE
;
3327 ULONG SectorOffset
= FIRST_VD_SECTOR
;
3336 // We only look for secondary volume descriptors on an Iso disk.
3339 if ((FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
) || VerifyVolume
) && !CdNoJoliet
) {
3342 // Scan the volume descriptors from the beginning looking for a valid
3343 // secondary or a terminator.
3346 SectorOffset
= FIRST_VD_SECTOR
;
3351 // Read the next sector. We should never have an error in this
3355 CdReadSectors( IrpContext
,
3356 LlBytesFromSectors( Vcb
->BaseSector
+ SectorOffset
),
3360 Vcb
->TargetDeviceObject
);
3363 // Break out if the version number or standard Id is incorrect.
3364 // Also break out if this is a terminator.
3367 if (!RtlEqualMemory( CdIsoId
, CdRvdId( RawIsoVd
, VCB_STATE_JOLIET
), VOL_ID_LEN
) ||
3368 (CdRvdVersion( RawIsoVd
, VCB_STATE_JOLIET
) != VERSION_1
) ||
3369 (CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_TERMINATOR
)) {
3375 // We have a match if this is a secondary descriptor with a matching
3379 if ((CdRvdDescType( RawIsoVd
, VCB_STATE_JOLIET
) == VD_SECONDARY
) &&
3380 (RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3383 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3386 RtlEqualMemory( CdRvdEsc( RawIsoVd
, VCB_STATE_JOLIET
),
3390 if (!VerifyVolume
) {
3393 // Update the Vcb with the new volume descriptor.
3396 ClearFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
3397 SetFlag( Vcb
->VcbState
, VCB_STATE_JOLIET
);
3399 Vcb
->VdSectorOffset
= SectorOffset
;
3402 FoundSecondaryVd
= TRUE
;
3407 // Otherwise move on to the next sector.
3414 // If we didn't find the secondary then recover the original volume
3415 // descriptor stored in the second half of the RawIsoVd.
3418 if (!FoundSecondaryVd
) {
3420 RtlCopyMemory( RawIsoVd
,
3421 Add2Ptr( RawIsoVd
, SECTOR_SIZE
, PVOID
),
3427 // If we're in the verify path, our work is done, since we don't want
3428 // to update any Vcb/Vpb values.
3437 // Compute the serial number and volume label from the volume descriptor.
3440 Vcb
->Vpb
->SerialNumber
= CdSerial32( RawIsoVd
, SECTOR_SIZE
);
3443 // Make sure the CD label will fit in the Vpb.
3446 NT_ASSERT( VOLUME_ID_LENGTH
* sizeof( WCHAR
) <= MAXIMUM_VOLUME_LABEL_LENGTH
);
3449 // If this is not a Unicode label we must convert it to unicode.
3452 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_JOLIET
)) {
3455 // Convert the label to unicode. If we get any error then use a name
3459 Vcb
->Vpb
->VolumeLabelLength
= 0;
3461 if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb
->Vpb
->VolumeLabel
[0],
3462 MAXIMUM_VOLUME_LABEL_LENGTH
,
3464 (PCH
)CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
3465 VOLUME_ID_LENGTH
))) {
3467 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) Length
;
3471 // We need to convert from big-endian to little endian.
3476 CdConvertBigToLittleEndian( IrpContext
,
3477 (PCHAR
) CdRvdVolId( RawIsoVd
, Vcb
->VcbState
),
3479 (PCHAR
) Vcb
->Vpb
->VolumeLabel
);
3481 Vcb
->Vpb
->VolumeLabelLength
= VOLUME_ID_LENGTH
* sizeof( WCHAR
);
3485 // Strip the trailing spaces or zeroes from the name.
3488 Index
= Vcb
->Vpb
->VolumeLabelLength
/ sizeof( WCHAR
);
3492 if ((Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
'\0') &&
3493 (Vcb
->Vpb
->VolumeLabel
[ Index
- 1 ] != L
' ')) {
3502 // Now set the final length for the name.
3505 Vcb
->Vpb
->VolumeLabelLength
= (USHORT
) (Index
* sizeof( WCHAR
));