xref: /reactos/drivers/filesystems/cdfs/fsctrl.c (revision 34593d93)
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     FsCtrl.c
8 
9 Abstract:
10 
11     This module implements the File System Control routines for Cdfs called
12     by the Fsd/Fsp dispatch drivers.
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 //  The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId                   (CDFS_BUG_CHECK_FSCTRL)
24 
25 //
26 //  Local constants
27 //
28 
29 BOOLEAN CdDisable = FALSE;
30 BOOLEAN CdNoJoliet = FALSE;
31 
32 //
33 //  Local support routines
34 //
35 
36 _Requires_lock_held_(_Global_critical_region_)
37 NTSTATUS
38 CdUserFsctl (
39     _Inout_ PIRP_CONTEXT IrpContext,
40     _Inout_ PIRP Irp
41     );
42 
43 VOID
44 CdReMountOldVcb (
45     _In_ PIRP_CONTEXT IrpContext,
46     _Inout_ PVCB OldVcb,
47     _Inout_ PVCB NewVcb,
48     _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo
49     );
50 
51 _Requires_lock_held_(_Global_critical_region_)
52 NTSTATUS
53 CdMountVolume (
54     _Inout_ PIRP_CONTEXT IrpContext,
55     _Inout_ PIRP Irp
56     );
57 
58 _Requires_lock_held_(_Global_critical_region_)
59 NTSTATUS
60 CdVerifyVolume (
61     _Inout_ PIRP_CONTEXT IrpContext,
62     _Inout_ PIRP Irp
63     );
64 
65 _Requires_lock_held_(_Global_critical_region_)
66 NTSTATUS
67 CdOplockRequest (
68     _Inout_ PIRP_CONTEXT IrpContext,
69     _Inout_ PIRP Irp
70     );
71 
72 _Requires_lock_held_(_Global_critical_region_)
73 NTSTATUS
74 CdLockVolume (
75     _Inout_ PIRP_CONTEXT IrpContext,
76     _Inout_ PIRP Irp
77     );
78 
79 _Requires_lock_held_(_Global_critical_region_)
80 NTSTATUS
81 CdUnlockVolume (
82     _Inout_ PIRP_CONTEXT IrpContext,
83     _Inout_ PIRP Irp
84     );
85 
86 _Requires_lock_held_(_Global_critical_region_)
87 NTSTATUS
88 CdDismountVolume (
89     _Inout_ PIRP_CONTEXT IrpContext,
90     _Inout_ PIRP Irp
91     );
92 
93 NTSTATUS
94 CdIsVolumeDirty (
95     _Inout_ PIRP_CONTEXT IrpContext,
96     _Inout_ PIRP Irp
97     );
98 
99 NTSTATUS
100 CdIsVolumeMounted (
101     _Inout_ PIRP_CONTEXT IrpContext,
102     _Inout_ PIRP Irp
103     );
104 
105 NTSTATUS
106 CdIsPathnameValid (
107     _Inout_ PIRP_CONTEXT IrpContext,
108     _Inout_ PIRP Irp
109     );
110 
111 _Requires_lock_held_(_Global_critical_region_)
112 NTSTATUS
113 CdInvalidateVolumes (
114     _Inout_ PIRP_CONTEXT IrpContext,
115     _Inout_ PIRP Irp
116     );
117 
118 NTSTATUS
119 CdAllowExtendedDasdIo (
120     _Inout_ PIRP_CONTEXT IrpContext,
121     _Inout_ PIRP Irp
122     );
123 
124 _Requires_lock_held_(_Global_critical_region_)
125 VOID
126 CdScanForDismountedVcb (
127     _Inout_ PIRP_CONTEXT IrpContext
128     );
129 
130 _Success_(return != FALSE)
131 BOOLEAN
132 CdFindPrimaryVd (
133     _In_ PIRP_CONTEXT IrpContext,
134     _Inout_ PVCB Vcb,
135     _Out_writes_bytes_(SECTOR_SIZE) PCHAR RawIsoVd,
136     _In_ ULONG BlockFactor,
137     _In_ BOOLEAN ReturnOnError,
138     _In_ BOOLEAN VerifyVolume
139     );
140 
141 _Success_(return != FALSE) BOOLEAN
142 CdIsRemount (
143     _In_ PIRP_CONTEXT IrpContext,
144     _In_ PVCB Vcb,
145     _Out_ PVCB *OldVcb
146     );
147 
148 VOID
149 CdFindActiveVolDescriptor (
150     _In_ PIRP_CONTEXT IrpContext,
151     _In_ PVCB Vcb,
152     _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE )) PCHAR RawIsoVd,
153     _In_ BOOLEAN VerifyVolume
154     );
155 
156 #ifdef ALLOC_PRAGMA
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)
173 #endif
174 
175 
176 //
177 //  Local support routine
178 //
179 
180 _Requires_lock_held_(_Global_critical_region_)
181 _Requires_lock_held_(Vcb->VcbResource)
182 NTSTATUS
CdLockVolumeInternal(_In_ PIRP_CONTEXT IrpContext,_Inout_ PVCB Vcb,_In_opt_ PFILE_OBJECT FileObject)183 CdLockVolumeInternal (
184     _In_ PIRP_CONTEXT IrpContext,
185     _Inout_ PVCB Vcb,
186     _In_opt_ PFILE_OBJECT FileObject
187     )
188 
189 /*++
190 
191 Routine Description:
192 
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.
196 
197     The volume must be held exclusive by the caller.
198 
199 Arguments:
200 
201     Vcb - The volume being locked.
202 
203     FileObject - File corresponding to the handle locking the volume.  If this
204         is not specified, a system lock is assumed.
205 
206 Return Value:
207 
208     NTSTATUS - The return status for the operation
209 
210 --*/
211 
212 {
213     NTSTATUS Status;
214     KIRQL SavedIrql;
215     NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY);
216     ULONG RemainingUserReferences = (FileObject? 1: 0);
217 
218     //
219     //  The cleanup count for the volume only reflects the fileobject that
220     //  will lock the volume.  Otherwise, we must fail the request.
221     //
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.
225     //
226 
227     CdPurgeVolume( IrpContext, Vcb, FALSE );
228 
229     //
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.
232     //
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.
237     //
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.
242     //
243 
244     CdReleaseVcb( IrpContext, Vcb );
245 
246     Status = CcWaitForCurrentLazyWriterActivity();
247 
248     //
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
251     //  the flag up.
252     //
253 
254     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
255     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
256 
257     if (!NT_SUCCESS( Status )) {
258 
259         return Status;
260     }
261 
262     CdFspClose( Vcb );
263 
264     //
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.
267     //
268 
269     IoAcquireVpbSpinLock( &SavedIrql );
270 
271     if (!FlagOn( Vcb->Vpb->Flags, VPB_LOCKED ) &&
272         (Vcb->VcbCleanup == RemainingUserReferences) &&
273         (Vcb->VcbUserReference == CDFS_RESIDUAL_USER_REFERENCE + RemainingUserReferences))  {
274 
275         SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
276         SetFlag( Vcb->Vpb->Flags, VPB_LOCKED);
277         Vcb->VolumeLockFileObject = FileObject;
278         FinalStatus = STATUS_SUCCESS;
279     }
280 
281     IoReleaseVpbSpinLock( SavedIrql );
282 
283     return FinalStatus;
284 }
285 
286 
287 NTSTATUS
CdUnlockVolumeInternal(_In_ PIRP_CONTEXT IrpContext,_Inout_ PVCB Vcb,_In_opt_ PFILE_OBJECT FileObject)288 CdUnlockVolumeInternal (
289     _In_ PIRP_CONTEXT IrpContext,
290     _Inout_ PVCB Vcb,
291     _In_opt_ PFILE_OBJECT FileObject
292     )
293 
294 /*++
295 
296 Routine Description:
297 
298     This routine performs the actual unlock volume operation.
299 
300     The volume must be held exclusive by the caller.
301 
302 Arguments:
303 
304     Vcb - The volume being locked.
305 
306     FileObject - File corresponding to the handle locking the volume.  If this
307         is not specified, a system lock is assumed.
308 
309 Return Value:
310 
311     NTSTATUS - The return status for the operation
312 
313     Attempting to remove a system lock that did not exist is OK.
314 
315 --*/
316 
317 {
318     NTSTATUS Status = STATUS_NOT_LOCKED;
319     KIRQL SavedIrql;
320 
321     UNREFERENCED_PARAMETER( IrpContext );
322 
323     //
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.
327     //
328 
329     IoAcquireVpbSpinLock( &SavedIrql );
330 
331     if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) &&
332         (FileObject == Vcb->VolumeLockFileObject))  {
333 
334         ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
335         ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED);
336         Vcb->VolumeLockFileObject = NULL;
337         Status = STATUS_SUCCESS;
338     }
339 
340     IoReleaseVpbSpinLock( SavedIrql );
341 
342     return Status;
343 }
344 
345 
346 
_Requires_lock_held_(_Global_critical_region_)347 _Requires_lock_held_(_Global_critical_region_)
348 NTSTATUS
349 CdCommonFsControl (
350     _Inout_ PIRP_CONTEXT IrpContext,
351     _Inout_ PIRP Irp
352     )
353 
354 /*++
355 
356 Routine Description:
357 
358     This is the common routine for doing FileSystem control operations called
359     by both the fsd and fsp threads
360 
361 Arguments:
362 
363     Irp - Supplies the Irp to process
364 
365 Return Value:
366 
367     NTSTATUS - The return status for the operation
368 
369 --*/
370 
371 {
372     NTSTATUS Status;
373     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
374 
375     PAGED_CODE();
376 
377     //
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
380     //  the irp.
381     //
382 
383     switch (IrpSp->MinorFunction) {
384 
385     case IRP_MN_USER_FS_REQUEST:
386 
387         Status = CdUserFsctl( IrpContext, Irp );
388         break;
389 
390     case IRP_MN_MOUNT_VOLUME:
391 
392         Status = CdMountVolume( IrpContext, Irp );
393         break;
394 
395     case IRP_MN_VERIFY_VOLUME:
396 
397         Status = CdVerifyVolume( IrpContext, Irp );
398         break;
399 
400     default:
401 
402         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
403         Status = STATUS_INVALID_DEVICE_REQUEST;
404         break;
405     }
406 
407     return Status;
408 }
409 
410 
411 //
412 //  Local support routine
413 //
414 
_Requires_lock_held_(_Global_critical_region_)415 _Requires_lock_held_(_Global_critical_region_)
416 NTSTATUS
417 CdUserFsctl (
418     _Inout_ PIRP_CONTEXT IrpContext,
419     _Inout_ PIRP Irp
420     )
421 /*++
422 
423 Routine Description:
424 
425     This is the common routine for implementing the user's requests made
426     through NtFsControlFile.
427 
428 Arguments:
429 
430     Irp - Supplies the Irp being processed
431 
432 Return Value:
433 
434     NTSTATUS - The return status for the operation
435 
436 --*/
437 
438 {
439     NTSTATUS Status;
440     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
441 
442     PAGED_CODE();
443 
444     //
445     //  Case on the control code.
446     //
447 
448     switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) {
449 
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 :
458 
459         Status = CdOplockRequest( IrpContext, Irp );
460         break;
461 
462     case FSCTL_LOCK_VOLUME :
463 
464         Status = CdLockVolume( IrpContext, Irp );
465         break;
466 
467     case FSCTL_UNLOCK_VOLUME :
468 
469         Status = CdUnlockVolume( IrpContext, Irp );
470         break;
471 
472     case FSCTL_DISMOUNT_VOLUME :
473 
474         Status = CdDismountVolume( IrpContext, Irp );
475         break;
476 
477     case FSCTL_IS_VOLUME_DIRTY :
478 
479         Status = CdIsVolumeDirty( IrpContext, Irp );
480         break;
481 
482     case FSCTL_IS_VOLUME_MOUNTED :
483 
484         Status = CdIsVolumeMounted( IrpContext, Irp );
485         break;
486 
487     case FSCTL_IS_PATHNAME_VALID :
488 
489         Status = CdIsPathnameValid( IrpContext, Irp );
490         break;
491 
492     case FSCTL_INVALIDATE_VOLUMES :
493 
494         Status = CdInvalidateVolumes( IrpContext, Irp );
495         break;
496 
497     case FSCTL_ALLOW_EXTENDED_DASD_IO:
498 
499         Status = CdAllowExtendedDasdIo( IrpContext, Irp );
500         break;
501 
502     //
503     //  We don't support any of the known or unknown requests.
504     //
505 
506     default:
507 
508         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
509         Status = STATUS_INVALID_DEVICE_REQUEST;
510         break;
511     }
512 
513     return Status;
514 }
515 
516 
517 VOID
CdReMountOldVcb(_In_ PIRP_CONTEXT IrpContext,_Inout_ PVCB OldVcb,_Inout_ PVCB NewVcb,_In_ PDEVICE_OBJECT DeviceObjectWeTalkTo)518 CdReMountOldVcb (
519     _In_ PIRP_CONTEXT IrpContext,
520     _Inout_ PVCB OldVcb,
521     _Inout_ PVCB NewVcb,
522     _In_ PDEVICE_OBJECT DeviceObjectWeTalkTo
523     )
524 {
525     KIRQL SavedIrql;
526     ULONG Index;
527     PUCHAR Buffer;
528 
529     UNREFERENCED_PARAMETER( IrpContext );
530 
531     ObDereferenceObject( OldVcb->TargetDeviceObject );
532 
533     IoAcquireVpbSpinLock( &SavedIrql );
534 
535 #ifdef _MSC_VER
536 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed")
537 #endif
538     NewVcb->Vpb->RealDevice->Vpb = OldVcb->Vpb;
539 
540     OldVcb->Vpb->RealDevice = NewVcb->Vpb->RealDevice;
541     OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo;
542 
543     CdUpdateVcbCondition( OldVcb, VcbMounted);
544     CdUpdateMediaChangeCount( OldVcb, NewVcb->MediaChangeCount);
545 
546     ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
547 
548     Buffer = OldVcb->SectorCacheBuffer = NewVcb->SectorCacheBuffer;
549     NewVcb->SectorCacheBuffer = NULL;
550 
551     if (NULL != Buffer) {
552 
553         for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
554 
555             OldVcb->SecCacheChunks[ Index].Buffer = Buffer;
556             OldVcb->SecCacheChunks[ Index].BaseLbn = (ULONG)-1;
557 
558             Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE;
559         }
560     }
561 
562     IoReleaseVpbSpinLock( SavedIrql );
563 }
564 
565 
566 //
567 //  Local support routine
568 //
569 
_Requires_lock_held_(_Global_critical_region_)570 _Requires_lock_held_(_Global_critical_region_)
571 NTSTATUS
572 CdMountVolume (
573     _Inout_ PIRP_CONTEXT IrpContext,
574     _Inout_ PIRP Irp
575     )
576 
577 /*++
578 
579 Routine Description:
580 
581     This routine performs the mount volume operation.  It is responsible for
582     either completing of enqueuing the input Irp.
583 
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:
587 
588     1. Create a new Vcb Structure, and initialize it enough to do I/O
589        through the on-disk volume descriptors.
590 
591     2. Read the disk and check if it is a Cdrom volume.
592 
593     3. If it is not a Cdrom volume then delete the Vcb and
594        complete the IRP back with an appropriate status.
595 
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.
599 
600     5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
601 
602 Arguments:
603 
604     Irp - Supplies the Irp to process
605 
606 Return Value:
607 
608     NTSTATUS - The return status for the operation
609 
610 --*/
611 
612 {
613     NTSTATUS Status;
614 
615     PVOLUME_DEVICE_OBJECT VolDo = NULL;
616     PVCB Vcb = NULL;
617     PVCB OldVcb;
618     UCHAR StackSize;
619 
620     BOOLEAN FoundPvd = FALSE;
621     BOOLEAN SetDoVerifyOnFail;
622 
623     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
624     PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
625     PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
626 
627     PFILE_OBJECT FileObjectToNotify = NULL;
628 
629     ULONG BlockFactor;
630     DISK_GEOMETRY DiskGeometry;
631 
632     IO_SCSI_CAPABILITIES Capabilities;
633 
634     IO_STATUS_BLOCK Iosb;
635 
636     PCHAR RawIsoVd = NULL;
637 
638     PCDROM_TOC_LARGE CdromToc = NULL;
639     ULONG TocLength = 0;
640     ULONG TocTrackCount = 0;
641     ULONG TocDiskFlags = 0;
642     ULONG MediaChangeCount = 0;
643 
644 #ifdef __REACTOS__
645     DEVICE_TYPE FilesystemDeviceType;
646 #endif
647 
648 #ifdef CDFS_TELEMETRY_DATA
649     GUID VolumeGuid;
650     GUID VolumeCorrelationId = { 0 };
651 #endif
652 
653     PAGED_CODE();
654 
655     //
656     //  Check that we are talking to a Cdrom device.  This request should
657     //  always be waitable.
658     //
659 
660 #ifdef __REACTOS__
661     if (IrpSp->DeviceObject == CdData.HddFileSystemDeviceObject) {
662         FilesystemDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
663     } else {
664 #endif
665     NT_ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
666 #ifdef __REACTOS__
667         FilesystemDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
668     }
669 #endif
670     NT_ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
671 
672 #ifdef CDFS_TELEMETRY_DATA
673     //
674     //  We don't want a bogus VolumeGuid to show up in our telemetry
675     //
676 
677     RtlZeroMemory( &VolumeGuid, sizeof(GUID) );
678 
679 #endif
680 
681     //
682     //  Update the real device in the IrpContext from the Vpb.  There was no available
683     //  file object when the IrpContext was created.
684     //
685 
686     IrpContext->RealDevice = Vpb->RealDevice;
687 
688     SetDoVerifyOnFail = CdRealDevNeedsVerify( IrpContext->RealDevice);
689 
690     //
691     //  Check if we have disabled the mount process.
692     //
693 
694     if (CdDisable) {
695 
696         CdCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
697         return STATUS_UNRECOGNIZED_VOLUME;
698     }
699 
700     //
701     //  If we've shutdown disallow further mounts.
702     //
703 
704     if (FlagOn( CdData.Flags, CD_FLAGS_SHUTDOWN )) {
705 
706         CdCompleteRequest( IrpContext, Irp, STATUS_SYSTEM_SHUTDOWN );
707         return STATUS_SYSTEM_SHUTDOWN;
708     }
709 
710     //
711     //  Do a CheckVerify here to lift the MediaChange ticker from the driver
712     //
713 
714     Status = CdPerformDevIoCtrl( IrpContext,
715 #ifndef __REACTOS__
716                                  IOCTL_CDROM_CHECK_VERIFY,
717 #else
718                                  (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ? IOCTL_DISK_CHECK_VERIFY : IOCTL_CDROM_CHECK_VERIFY),
719 #endif
720                                  DeviceObjectWeTalkTo,
721                                  &MediaChangeCount,
722                                  sizeof(ULONG),
723                                  FALSE,
724                                  TRUE,
725                                  &Iosb );
726 
727     if (!NT_SUCCESS( Status )) {
728 
729         CdCompleteRequest( IrpContext, Irp, Status );
730         return Status;
731     }
732 
733     if (Iosb.Information != sizeof(ULONG)) {
734 
735         //
736         //  Be safe about the count in case the driver didn't fill it in
737         //
738 
739         MediaChangeCount = 0;
740     }
741 
742     //
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.
745     //
746 
747     Status = CdPerformDevIoCtrl( IrpContext,
748 #ifndef __REACTOS__
749                                  IOCTL_CDROM_GET_DRIVE_GEOMETRY,
750 #else
751                                  (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ? IOCTL_DISK_GET_DRIVE_GEOMETRY : IOCTL_CDROM_GET_DRIVE_GEOMETRY),
752 #endif
753                                  DeviceObjectWeTalkTo,
754                                  &DiskGeometry,
755                                  sizeof( DISK_GEOMETRY ),
756                                  FALSE,
757                                  TRUE,
758                                  NULL );
759 
760     //
761     //  Return insufficient sources to our caller.
762     //
763 
764     if (Status == STATUS_INSUFFICIENT_RESOURCES) {
765 
766         CdCompleteRequest( IrpContext, Irp, Status );
767         return Status;
768     }
769 
770     //
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
773     //  block per sector.
774     //
775 
776     BlockFactor = 1;
777 
778     if (NT_SUCCESS( Status ) &&
779         (DiskGeometry.BytesPerSector != 0) &&
780         (DiskGeometry.BytesPerSector < SECTOR_SIZE)) {
781 
782         BlockFactor = SECTOR_SIZE / DiskGeometry.BytesPerSector;
783     }
784 
785     //
786     //  Acquire the global resource to do mount operations.
787     //
788 
789     CdAcquireCdData( IrpContext );
790 
791     //
792     //  Use a try-finally to facilitate cleanup.
793     //
794 
795     _SEH2_TRY {
796 
797         //
798         //  Allocate a buffer to query the TOC.
799         //
800 
801         CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
802                                              sizeof( CDROM_TOC_LARGE ),
803                                              TAG_CDROM_TOC );
804 
805         RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE ));
806 
807         //
808         //  Do a quick check to see if there any Vcb's which can be removed.
809         //
810 
811         CdScanForDismountedVcb( IrpContext );
812 
813         //
814         //  Get our device object and alignment requirement.
815         //
816 
817         Status = IoCreateDevice( CdData.DriverObject,
818                                  sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ),
819                                  NULL,
820 #ifndef __REACTOS__
821                                  FILE_DEVICE_CD_ROM_FILE_SYSTEM,
822 #else
823                                  FilesystemDeviceType,
824 #endif
825                                  0,
826                                  FALSE,
827                                  (PDEVICE_OBJECT *) &VolDo );
828 
829         if (!NT_SUCCESS( Status )) { try_leave( Status ); }
830 
831         //
832         //  Our alignment requirement is the larger of the processor alignment requirement
833         //  already in the volume device object and that in the DeviceObjectWeTalkTo
834         //
835 
836         if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
837 
838             VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
839         }
840 
841         //
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.
844         //
845 
846         ((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1);
847         StackSize = ((PDEVICE_OBJECT) VolDo)->StackSize;
848 
849         ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
850 
851         //
852         //  Initialize the overflow queue for the volume
853         //
854 
855         VolDo->OverflowQueueCount = 0;
856         InitializeListHead( &VolDo->OverflowQueue );
857 
858         VolDo->PostedRequestCount = 0;
859         KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
860 
861         //
862         //  Let's query for the Toc now and handle any error we get from this operation.
863         //
864 
865         Status = CdProcessToc( IrpContext,
866                                DeviceObjectWeTalkTo,
867                                CdromToc,
868                                &TocLength,
869                                &TocTrackCount,
870                                &TocDiskFlags );
871 
872         //
873         //  If we failed to read the TOC, then bail out.  Probably blank media.
874         //
875 
876         if (Status != STATUS_SUCCESS)  {
877 
878 #ifdef __REACTOS__
879 
880             //
881             // Don't bail out if that was a disk based ISO image, it is legit
882             //
883 
884             if (FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
885                 CdFreePool( &CdromToc );
886                 Status = STATUS_SUCCESS;
887             } else {
888 #endif
889             try_leave( Status );
890 #ifdef __REACTOS__
891             }
892 #endif
893         }
894 
895         //
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
898         //  object.
899         //
900 
901         Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
902 
903         //
904         //  Initialize the Vcb.  This routine will raise on an allocation
905         //  failure.
906         //
907 
908         CdInitializeVcb( IrpContext,
909                          &VolDo->Vcb,
910                          DeviceObjectWeTalkTo,
911                          Vpb,
912                          CdromToc,
913                          TocLength,
914                          TocTrackCount,
915                          TocDiskFlags,
916                          BlockFactor,
917                          MediaChangeCount );
918 
919         //
920         //  Show that we initialized the Vcb and can cleanup with the Vcb.
921         //
922 
923         Vcb = &VolDo->Vcb;
924         VolDo = NULL;
925         Vpb = NULL;
926         CdromToc = NULL;
927 
928 #ifdef CDFS_TELEMETRY_DATA
929 
930         //
931         //  Initialize the volume guid.
932         //
933 
934         if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb->TargetDeviceObject, &VolumeGuid ))) {
935 
936             //
937             //  We got a GUID, set it in the Telemetry structure
938             //
939 
940             RtlCopyMemory( &CdTelemetryData.VolumeGuid, &VolumeGuid, sizeof(GUID) );
941         }
942 
943         //
944         // Initialize the correlation ID.
945         //
946 
947         if (NT_SUCCESS( FsRtlVolumeDeviceToCorrelationId( Vcb->TargetDeviceObject, &VolumeCorrelationId ) )) {
948 
949             //
950             // Stash a copy away in the VCB.
951             //
952 
953             RtlCopyMemory( &Vcb->VolumeCorrelationId, &VolumeCorrelationId, sizeof( GUID ) );
954         }
955 
956 #endif // CDFS_TELEMETRY_DATA
957 
958         // Lock object is acquired and released using internal state
959         _Analysis_suppress_lock_checking_(Vcb->VcbResource);
960 
961         //
962         //  Store the Vcb in the IrpContext as we didn't have one before.
963         //
964 
965         IrpContext->Vcb = Vcb;
966 
967         CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
968 
969         //
970         //  Let's reference the Vpb to make sure we are the one to
971         //  have the last dereference.
972         //
973 
974         Vcb->Vpb->ReferenceCount += 1;
975 
976         //
977         //  Clear the verify bit for the start of mount.
978         //
979 
980         CdMarkRealDevVerifyOk( Vcb->Vpb->RealDevice);
981 
982         if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK))  {
983 
984             //
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.
987             //
988 
989             RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
990                                                  ROUND_TO_PAGES( SECTOR_SIZE ),
991                                                  TAG_VOL_DESC );
992 
993             //
994             //  Try to find the primary volume descriptor.
995             //
996 
997             FoundPvd = CdFindPrimaryVd(   IrpContext,
998                                           Vcb,
999                                           RawIsoVd,
1000                                           BlockFactor,
1001                                           TRUE,
1002                                           FALSE );
1003 
1004             if (!FoundPvd)  {
1005 
1006                 //
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.
1014                 //
1015 
1016                 if (!(TocDiskFlags & CDROM_DISK_AUDIO_TRACK) ||
1017                      BooleanFlagOn( Vcb->CdromToc->TrackData[0].Control, TOC_DATA_TRACK))  {
1018 
1019                     try_leave( Status = STATUS_UNRECOGNIZED_VOLUME);
1020                 }
1021 
1022                 SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
1023 
1024                 CdFreePool( &RawIsoVd );
1025                 RawIsoVd = NULL;
1026             }
1027         }
1028 
1029         //
1030         //  Look and see if there is a secondary volume descriptor we want to
1031         //  use.
1032         //
1033 
1034         if (FoundPvd) {
1035 
1036             //
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.
1040             //
1041 
1042             RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
1043                            RawIsoVd,
1044                            SECTOR_SIZE );
1045 
1046             //
1047             //  We have the initial volume descriptor.  Locate a secondary
1048             //  volume descriptor if present.
1049             //
1050 
1051             CdFindActiveVolDescriptor( IrpContext,
1052                                        Vcb,
1053                                        RawIsoVd,
1054                                        FALSE);
1055         }
1056 
1057         //
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.
1066         //
1067 
1068         if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK) &&
1069 #ifndef __REACTOS__
1070             ((Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack) == 0)) {
1071 #else
1072            ((FilesystemDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1073             ((Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack) == 0))) {
1074 #endif
1075 
1076             ULONG Index;
1077             PUCHAR Buffer;
1078 
1079             Buffer =
1080             Vcb->SectorCacheBuffer = FsRtlAllocatePool( CdPagedPool,
1081                                                         CD_SEC_CACHE_CHUNKS *
1082                                                         CD_SEC_CHUNK_BLOCKS *
1083                                                         SECTOR_SIZE);
1084 
1085             for (Index = 0; Index < (ULONG)CD_SEC_CACHE_CHUNKS; Index++) {
1086 
1087                 Vcb->SecCacheChunks[ Index].Buffer = Buffer;
1088                 Vcb->SecCacheChunks[ Index].BaseLbn = (ULONG)-1;
1089 
1090                 Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE;
1091             }
1092 
1093             Vcb->SectorCacheIrp = IoAllocateIrp( StackSize, FALSE);
1094 
1095             if (Vcb->SectorCacheIrp == NULL) {
1096 
1097                 try_leave( Status = STATUS_INSUFFICIENT_RESOURCES );
1098             }
1099 
1100             IoInitializeIrp( Vcb->SectorCacheIrp,
1101                              IoSizeOfIrp( StackSize),
1102                              (CCHAR)StackSize);
1103 
1104             KeInitializeEvent( &Vcb->SectorCacheEvent, SynchronizationEvent, FALSE);
1105             ExInitializeResourceLite( &Vcb->SectorCacheResource);
1106         }
1107 
1108         //
1109         //  Check if this is a remount operation.  If so then clean up
1110         //  the data structures passed in and created here.
1111         //
1112 
1113         if (CdIsRemount( IrpContext, Vcb, &OldVcb )) {
1114 
1115             NT_ASSERT( NULL != OldVcb->SwapVpb );
1116 
1117             //
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.
1121             //
1122 
1123             CdReMountOldVcb( IrpContext,
1124                              OldVcb,
1125                              Vcb,
1126                              DeviceObjectWeTalkTo);
1127 
1128             //
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.
1134             //
1135 
1136             if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
1137 
1138                 ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
1139 
1140                 FileObjectToNotify = OldVcb->RootIndexFcb->FileObject;
1141                 ObReferenceObject( FileObjectToNotify );
1142             }
1143 
1144             try_leave( Status = STATUS_SUCCESS );
1145         }
1146 
1147         //
1148         //  This is a new mount.  Go ahead and initialize the
1149         //  Vcb from the volume descriptor.
1150         //
1151 
1152         CdUpdateVcbFromVolDescriptor( IrpContext,
1153                                       Vcb,
1154                                       RawIsoVd );
1155 
1156         //
1157         //  Drop an extra reference on the root dir file so we'll be able to send
1158         //  notification.
1159         //
1160 
1161         if (Vcb->RootIndexFcb) {
1162 
1163             FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
1164             ObReferenceObject( FileObjectToNotify );
1165         }
1166 
1167         //
1168         //  Now check the maximum transfer limits on the device in case we
1169         //  get raw reads on this volume.
1170         //
1171 
1172         Status = CdPerformDevIoCtrl( IrpContext,
1173                                      IOCTL_SCSI_GET_CAPABILITIES,
1174                                      DeviceObjectWeTalkTo,
1175                                      &Capabilities,
1176                                      sizeof( IO_SCSI_CAPABILITIES ),
1177                                      FALSE,
1178                                      TRUE,
1179                                      NULL );
1180 
1181         if (NT_SUCCESS(Status)) {
1182 
1183             Vcb->MaximumTransferRawSectors = Capabilities.MaximumTransferLength / RAW_SECTOR_SIZE;
1184             Vcb->MaximumPhysicalPages = Capabilities.MaximumPhysicalPages;
1185 
1186         } else {
1187 
1188             //
1189             //  This should never happen, but we can safely assume 64k and 16 pages.
1190             //
1191 
1192             Vcb->MaximumTransferRawSectors = (64 * 1024) / RAW_SECTOR_SIZE;
1193             Vcb->MaximumPhysicalPages = 16;
1194         }
1195 
1196         //
1197         //  The new mount is complete.  Remove the additional references on this
1198         //  Vcb and the device we are mounted on top of.
1199         //
1200 
1201         Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
1202         NT_ASSERT( Vcb->VcbReference == CDFS_RESIDUAL_REFERENCE );
1203 
1204         ObDereferenceObject( Vcb->TargetDeviceObject );
1205 
1206         CdUpdateVcbCondition( Vcb, VcbMounted);
1207 
1208         CdReleaseVcb( IrpContext, Vcb );
1209         Vcb = NULL;
1210 
1211         Status = STATUS_SUCCESS;
1212 
1213     } _SEH2_FINALLY {
1214 
1215         //
1216         //  Free the TOC buffer if not in the Vcb.
1217         //
1218 
1219         if (CdromToc != NULL) {
1220 
1221             CdFreePool( &CdromToc );
1222         }
1223 
1224         //
1225         //  Free the sector buffer if allocated.
1226         //
1227 
1228         if (RawIsoVd != NULL) {
1229 
1230             CdFreePool( &RawIsoVd );
1231         }
1232 
1233         //
1234         //  If we are not mounting the device,  then set the verify bit again.
1235         //
1236 
1237         if ((_SEH2_AbnormalTermination() || (Status != STATUS_SUCCESS)) &&
1238             SetDoVerifyOnFail)  {
1239 
1240             CdMarkRealDevForVerify( IrpContext->RealDevice);
1241         }
1242 
1243         //
1244         //  If we didn't complete the mount then cleanup any remaining structures.
1245         //
1246 
1247         if (Vpb != NULL) { Vpb->DeviceObject = NULL; }
1248 
1249         if (Vcb != NULL) {
1250 
1251             //
1252             //  Make sure there is no Vcb in the IrpContext since it could go away
1253             //
1254 
1255             IrpContext->Vcb = NULL;
1256 
1257             Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
1258 
1259             if (CdDismountVcb( IrpContext, Vcb )) {
1260 
1261                 CdReleaseVcb( IrpContext, Vcb );
1262             }
1263 
1264         } else if (VolDo != NULL) {
1265 
1266             IoDeleteDevice( (PDEVICE_OBJECT) VolDo );
1267         }
1268 
1269         //
1270         //  Release the global resource.
1271         //
1272 
1273         CdReleaseCdData( IrpContext );
1274     } _SEH2_END;
1275 
1276     //
1277     //  Now send mount notification.
1278     //
1279 
1280     if (FileObjectToNotify) {
1281 
1282         FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
1283         ObDereferenceObject( FileObjectToNotify );
1284     }
1285 
1286 #ifdef CDFS_TELEMETRY_DATA
1287 
1288     //
1289     // Send Telemetry
1290     //
1291 
1292     CdTelemetryMountSafe( &VolumeCorrelationId, STATUS_SUCCESS, Vcb );
1293 
1294 #endif
1295 
1296     //
1297     //  Complete the request if no exception.
1298     //
1299 
1300     CdCompleteRequest( IrpContext, Irp, Status );
1301     return Status;
1302 }
1303 
1304 
1305 //
1306 //  Local support routine
1307 //
1308 
1309 _Requires_lock_held_(_Global_critical_region_)
1310 NTSTATUS
1311 CdVerifyVolume (
1312     _Inout_ PIRP_CONTEXT IrpContext,
1313     _Inout_ PIRP Irp
1314     )
1315 
1316 /*++
1317 
1318 Routine Description:
1319 
1320     This routine performs the verify volume operation.  It is responsible for
1321     either completing of enqueuing the input Irp.
1322 
1323 Arguments:
1324 
1325     Irp - Supplies the Irp to process
1326 
1327 Return Value:
1328 
1329     NTSTATUS - The return status for the operation
1330 
1331 --*/
1332 
1333 {
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;
1337 
1338     PCHAR RawIsoVd = NULL;
1339 
1340     PCDROM_TOC_LARGE CdromToc = NULL;
1341     ULONG TocLength = 0;
1342     ULONG TocTrackCount = 0;
1343     ULONG TocDiskFlags = 0;
1344 
1345     ULONG MediaChangeCount = Vcb->MediaChangeCount;
1346 
1347     PFILE_OBJECT FileObjectToNotify = NULL;
1348 
1349     BOOLEAN ReturnError;
1350     BOOLEAN ReleaseVcb = FALSE;
1351 
1352     IO_STATUS_BLOCK Iosb;
1353 
1354     STRING AnsiLabel;
1355     UNICODE_STRING UnicodeLabel;
1356 
1357     WCHAR VolumeLabel[ VOLUME_ID_LENGTH ];
1358     ULONG VolumeLabelLength;
1359 
1360     ULONG Index;
1361 
1362     NTSTATUS Status = STATUS_SUCCESS;
1363 
1364     PAGED_CODE();
1365 
1366     //
1367     //  We check that we are talking to a Cdrom device.
1368     //
1369 
1370     NT_ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
1371     NT_ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
1372 
1373     //
1374     //  Update the real device in the IrpContext from the Vpb.  There was no available
1375     //  file object when the IrpContext was created.
1376     //
1377 
1378     IrpContext->RealDevice = Vpb->RealDevice;
1379 
1380     //
1381     //  Acquire the global resource to synchronise against mounts and teardown,
1382     //  finally clause releases.
1383     //
1384 
1385     CdAcquireCdData( IrpContext );
1386 
1387     _SEH2_TRY {
1388 
1389         CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
1390         ReleaseVcb = TRUE;
1391 
1392         //
1393         //  Check to see if the volume is eligible for verification.
1394         //
1395 
1396         if ((Vcb->VcbCondition == VcbInvalid) ||
1397             (Vcb->VcbCondition == VcbDismountInProgress)) {
1398 
1399             try_return( Status = STATUS_WRONG_VOLUME );
1400         }
1401 
1402         //
1403         //  Verify that there is a disk here.
1404         //
1405 
1406         Status = CdPerformDevIoCtrl( IrpContext,
1407                                      IOCTL_CDROM_CHECK_VERIFY,
1408                                      Vcb->TargetDeviceObject,
1409                                      &MediaChangeCount,
1410                                      sizeof(ULONG),
1411                                      FALSE,
1412                                      TRUE,
1413                                      &Iosb );
1414 
1415         if (!NT_SUCCESS( Status )) {
1416 
1417             //
1418             //  If we will allow a raw mount then return WRONG_VOLUME to
1419             //  allow the volume to be mounted by raw.
1420             //
1421 
1422             if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
1423 
1424                 Status = STATUS_WRONG_VOLUME;
1425             }
1426 
1427             try_return( Status );
1428         }
1429 
1430         if (Iosb.Information != sizeof(ULONG)) {
1431 
1432             //
1433             //  Be safe about the count in case the driver didn't fill it in
1434             //
1435 
1436             MediaChangeCount = 0;
1437         }
1438 
1439         //
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.
1442         //
1443 
1444         if (MediaChangeCount == 0 ||
1445             (Vcb->MediaChangeCount != MediaChangeCount)) {
1446 
1447             //
1448             //  Allocate a buffer to query the TOC.
1449             //
1450 
1451             CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
1452                                                  sizeof( CDROM_TOC_LARGE ),
1453                                                  TAG_CDROM_TOC );
1454 
1455             RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE ));
1456 
1457             //
1458             //  Let's query for the Toc now and handle any error we get from this operation.
1459             //
1460 
1461             Status = CdProcessToc( IrpContext,
1462                                    Vcb->TargetDeviceObject,
1463                                    CdromToc,
1464                                    &TocLength,
1465                                    &TocTrackCount,
1466                                    &TocDiskFlags );
1467 
1468             //
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.
1471             //
1472 
1473             if (Status != STATUS_SUCCESS) {
1474 
1475                 //
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.
1480                 //
1481 
1482                 if (!CdIsRawDevice( IrpContext, Status )) {
1483 
1484                     Status = STATUS_WRONG_VOLUME;
1485                 }
1486 
1487                 try_return( Status );
1488 
1489             //
1490             //  We got a TOC.  Verify that it matches the previous Toc.
1491             //
1492 
1493             } else if ((Vcb->TocLength != TocLength) ||
1494                        (Vcb->TrackCount != TocTrackCount) ||
1495                        (Vcb->DiskFlags != TocDiskFlags) ||
1496                        !RtlEqualMemory( CdromToc,
1497                                         Vcb->CdromToc,
1498                                         TocLength )) {
1499 
1500                 try_return( Status = STATUS_WRONG_VOLUME );
1501             }
1502 
1503             //
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.
1506             //
1507 
1508             if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
1509 
1510                 //
1511                 //  Allocate a buffer for the sector buffer.
1512                 //
1513 
1514                 RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
1515                                                      ROUND_TO_PAGES( 2 * SECTOR_SIZE ),
1516                                                      TAG_VOL_DESC );
1517 
1518                 //
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.
1523                 //
1524 
1525                 ReturnError = FALSE;
1526 
1527                 if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
1528 
1529                     ReturnError = TRUE;
1530                 }
1531 
1532                 if (!CdFindPrimaryVd( IrpContext,
1533                                       Vcb,
1534                                       RawIsoVd,
1535                                       Vcb->BlockFactor,
1536                                       ReturnError,
1537                                       TRUE )) {
1538 
1539                     //
1540                     //  If the previous Vcb did not represent a raw disk
1541                     //  then show this volume was dismounted.
1542                     //
1543 
1544                     try_return( Status = STATUS_WRONG_VOLUME );
1545 
1546                 }
1547                 else {
1548 
1549                     //
1550                     //  Look for a supplementary VD.
1551                     //
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.
1555                     //
1556 
1557                     RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
1558                                    RawIsoVd,
1559                                    SECTOR_SIZE );
1560 
1561                     //
1562                     //  We have the initial volume descriptor.  Locate a secondary
1563                     //  volume descriptor if present.
1564                     //
1565 
1566                     CdFindActiveVolDescriptor( IrpContext,
1567                                                Vcb,
1568                                                RawIsoVd,
1569                                                TRUE);
1570                     //
1571                     //  Compare the serial numbers.  If they don't match, set the
1572                     //  status to wrong volume.
1573                     //
1574 
1575                     if (Vpb->SerialNumber != CdSerial32( RawIsoVd, SECTOR_SIZE )) {
1576 
1577                         try_return( Status = STATUS_WRONG_VOLUME );
1578                     }
1579 
1580                     //
1581                     //  Verify the volume labels.
1582                     //
1583 
1584                     if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
1585 
1586                         //
1587                         //  Compute the length of the volume name
1588                         //
1589 
1590                         AnsiLabel.Buffer = (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState );
1591                         AnsiLabel.MaximumLength = AnsiLabel.Length = (ULONG)VOLUME_ID_LENGTH;
1592 
1593                         UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
1594                         UnicodeLabel.Buffer = VolumeLabel;
1595 
1596                         //
1597                         //  Convert this to unicode.  If we get any error then use a name
1598                         //  length of zero.
1599                         //
1600 
1601                         VolumeLabelLength = 0;
1602 
1603                         if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel,
1604                                                                             &AnsiLabel,
1605                                                                             FALSE ))) {
1606 
1607                             VolumeLabelLength = UnicodeLabel.Length;
1608                         }
1609 
1610                     //
1611                     //  We need to convert from big-endian to little endian.
1612                     //
1613 
1614                     } else {
1615 
1616                         CdConvertBigToLittleEndian( IrpContext,
1617                                                     (PCHAR) CdRvdVolId( RawIsoVd, Vcb->VcbState ),
1618                                                     VOLUME_ID_LENGTH,
1619                                                     (PCHAR) VolumeLabel );
1620 
1621                         VolumeLabelLength = VOLUME_ID_LENGTH;
1622                     }
1623 
1624                     //
1625                     //  Strip the trailing spaces or zeroes from the name.
1626                     //
1627 
1628                     Index = VolumeLabelLength / sizeof( WCHAR );
1629 
1630                     while (Index > 0) {
1631 
1632                         if ((VolumeLabel[ Index - 1 ] != L'\0') &&
1633                             (VolumeLabel[ Index - 1 ] != L' ')) {
1634 
1635                             break;
1636                         }
1637 
1638                         Index -= 1;
1639                     }
1640 
1641                     //
1642                     //  Now set the final length for the name.
1643                     //
1644 
1645                     VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
1646 
1647                     //
1648                     //  Now check that the label matches.
1649                     //
1650                     if ((Vpb->VolumeLabelLength != VolumeLabelLength) ||
1651                         !RtlEqualMemory( Vpb->VolumeLabel,
1652                                          VolumeLabel,
1653                                          VolumeLabelLength )) {
1654 
1655                         try_return( Status = STATUS_WRONG_VOLUME );
1656                     }
1657                 }
1658             }
1659         }
1660 
1661         //
1662         //  The volume is OK, clear the verify bit.
1663         //
1664 
1665         CdUpdateVcbCondition( Vcb, VcbMounted);
1666 
1667         CdMarkRealDevVerifyOk( Vpb->RealDevice);
1668 
1669         //
1670         //  See if we will need to provide notification of the remount.  This is the readonly
1671         //  filesystem's form of dismount/mount notification.
1672         //
1673 
1674         if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
1675 
1676             ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
1677 
1678             FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
1679             ObReferenceObject( FileObjectToNotify );
1680         }
1681 
1682     try_exit: NOTHING;
1683 
1684         //
1685         //  Update the media change count to note that we have verified the volume
1686         //  at this value - regardless of the outcome.
1687         //
1688 
1689         CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
1690 
1691         //
1692         //  If the volume was already unmounted, nothing more to do.
1693         //
1694 
1695         if (Vcb->VcbCondition == VcbNotMounted) {
1696 
1697             Status = STATUS_WRONG_VOLUME;
1698 
1699         //
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.
1702         //
1703 
1704         } else if ((Vcb->VcbCondition == VcbMounted) && (Status == STATUS_WRONG_VOLUME)) {
1705 
1706             CdUpdateVcbCondition( Vcb, VcbNotMounted);
1707 
1708             if (Vcb->XASector != NULL) {
1709 
1710                 CdFreePool( &Vcb->XASector );
1711                 Vcb->XASector = 0;
1712                 Vcb->XADiskOffset = 0;
1713             }
1714 
1715             CdFreeDirCache( IrpContext);
1716 
1717             //
1718             //  Now, if there are no user handles to the volume, try to spark
1719             //  teardown by purging the volume.
1720             //
1721 
1722             if (Vcb->VcbCleanup == 0) {
1723 
1724                 if (NT_SUCCESS( CdPurgeVolume( IrpContext, Vcb, FALSE ))) {
1725 
1726                     ReleaseVcb = CdCheckForDismount( IrpContext, Vcb, FALSE );
1727                 }
1728             }
1729         }
1730 
1731     } _SEH2_FINALLY {
1732 
1733         //
1734         //  Free the TOC buffer if allocated.
1735         //
1736 
1737         if (CdromToc != NULL) {
1738 
1739             CdFreePool( &CdromToc );
1740         }
1741 
1742         if (RawIsoVd != NULL) {
1743 
1744             CdFreePool( &RawIsoVd );
1745         }
1746 
1747         if (ReleaseVcb) {
1748 
1749             CdReleaseVcb( IrpContext, Vcb );
1750         }
1751         else {
1752             _Analysis_assume_lock_not_held_(Vcb->VcbResource);
1753         }
1754 
1755         CdReleaseCdData( IrpContext );
1756     } _SEH2_END;
1757 
1758     //
1759     //  Now send mount notification.
1760     //
1761 
1762     if (FileObjectToNotify) {
1763 
1764         FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
1765         ObDereferenceObject( FileObjectToNotify );
1766     }
1767 
1768     //
1769     //  Complete the request if no exception.
1770     //
1771 
1772     CdCompleteRequest( IrpContext, Irp, Status );
1773     return Status;
1774 }
1775 
1776 
1777 //
1778 //  Local support routine
1779 //
1780 
1781 _Requires_lock_held_(_Global_critical_region_)
1782 NTSTATUS
1783 CdOplockRequest (
1784     _Inout_ PIRP_CONTEXT IrpContext,
1785     _Inout_ PIRP Irp
1786     )
1787 
1788 /*++
1789 
1790 Routine Description:
1791 
1792     This is the common routine to handle oplock requests made via the
1793     NtFsControlFile call.
1794 
1795 Arguments:
1796 
1797     Irp - Supplies the Irp being processed
1798 
1799 Return Value:
1800 
1801     NTSTATUS - The return status for the operation
1802 
1803 --*/
1804 
1805 {
1806     NTSTATUS Status = STATUS_SUCCESS;
1807     PFCB Fcb;
1808     PCCB Ccb;
1809 
1810     ULONG OplockCount = 0;
1811     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1812 
1813     PAGED_CODE();
1814 
1815     //
1816     //  We only permit oplock requests on files.
1817     //
1818 
1819     if (CdDecodeFileObject( IrpContext,
1820                             IrpSp->FileObject,
1821                             &Fcb,
1822                             &Ccb ) != UserFileOpen ) {
1823 
1824         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
1825         return STATUS_INVALID_PARAMETER;
1826     }
1827 
1828     //
1829     //  Make this a waitable Irpcontext so we don't fail to acquire
1830     //  the resources.
1831     //
1832 
1833     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1834     ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
1835 
1836     //
1837     //  Switch on the function control code.  We grab the Fcb exclusively
1838     //  for oplock requests, shared for oplock break acknowledgement.
1839     //
1840 
1841     switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
1842 
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 :
1847 
1848         CdAcquireFcbExclusive( IrpContext, Fcb, FALSE );
1849 
1850         if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
1851 
1852             if (Fcb->FileLock != NULL) {
1853 
1854 #if (NTDDI_VERSION >= NTDDI_WIN7)
1855                 OplockCount = (ULONG) FsRtlAreThereCurrentOrInProgressFileLocks( Fcb->FileLock );
1856 #else
1857                 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock );
1858 #endif
1859             }
1860 
1861         } else {
1862 
1863             OplockCount = Fcb->FcbCleanup;
1864         }
1865 
1866         break;
1867 
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:
1872 
1873         CdAcquireFcbShared( IrpContext, Fcb, FALSE );
1874         break;
1875 
1876     default:
1877 
1878         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
1879         return STATUS_INVALID_PARAMETER;
1880     }
1881 
1882     //
1883     //  Use a try finally to free the Fcb.
1884     //
1885 
1886     _SEH2_TRY {
1887 
1888         //
1889         //  Verify the Fcb.
1890         //
1891 
1892         CdVerifyFcbOperation( IrpContext, Fcb );
1893 
1894         //
1895         //  Call the FsRtl routine to grant/acknowledge oplock.
1896         //
1897 
1898         Status = FsRtlOplockFsctrl( CdGetFcbOplock(Fcb),
1899                                     Irp,
1900                                     OplockCount );
1901 
1902         //
1903         //  Set the flag indicating if Fast I/O is possible
1904         //
1905 
1906         CdLockFcb( IrpContext, Fcb );
1907         Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
1908         CdUnlockFcb( IrpContext, Fcb );
1909 
1910         //
1911         //  The oplock package will complete the Irp.
1912         //
1913 
1914         Irp = NULL;
1915 
1916     } _SEH2_FINALLY {
1917 
1918         //
1919         //  Release all of our resources
1920         //
1921 
1922         CdReleaseFcb( IrpContext, Fcb );
1923     } _SEH2_END;
1924 
1925     //
1926     //  Complete the request if there was no exception.
1927     //
1928 
1929     CdCompleteRequest( IrpContext, Irp, Status );
1930     return Status;
1931 }
1932 
1933 
1934 //
1935 //  Local support routine
1936 //
1937 
1938 _Requires_lock_held_(_Global_critical_region_)
1939 NTSTATUS
1940 CdLockVolume (
1941     _Inout_ PIRP_CONTEXT IrpContext,
1942     _Inout_ PIRP Irp
1943     )
1944 
1945 /*++
1946 
1947 Routine Description:
1948 
1949     This routine performs the lock volume operation.  It is responsible for
1950     either completing of enqueuing the input Irp.
1951 
1952 Arguments:
1953 
1954     Irp - Supplies the Irp to process
1955 
1956 Return Value:
1957 
1958     NTSTATUS - The return status for the operation
1959 
1960 --*/
1961 
1962 {
1963     NTSTATUS Status = STATUS_SUCCESS;
1964 
1965     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1966 
1967     PVCB Vcb;
1968     PFCB Fcb;
1969     PCCB Ccb;
1970 
1971     PAGED_CODE();
1972 
1973     //
1974     //  Decode the file object, the only type of opens we accept are
1975     //  user volume opens.
1976     //
1977 
1978     if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) {
1979 
1980         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
1981 
1982         return STATUS_INVALID_PARAMETER;
1983     }
1984 
1985     //
1986     //  Send our notification so that folks that like to hold handles on
1987     //  volumes can get out of the way.
1988     //
1989 
1990     FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
1991 
1992     //
1993     //  Acquire exclusive access to the Vcb.
1994     //
1995 
1996     Vcb = Fcb->Vcb;
1997     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
1998 
1999     _SEH2_TRY {
2000 
2001         //
2002         //  Verify the Vcb.
2003         //
2004 
2005         CdVerifyVcb( IrpContext, Vcb );
2006 
2007         Status = CdLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
2008 
2009     } _SEH2_FINALLY {
2010 
2011         //
2012         //  Release the Vcb.
2013         //
2014 
2015         CdReleaseVcb( IrpContext, Vcb );
2016 
2017         if (_SEH2_AbnormalTermination() || !NT_SUCCESS( Status )) {
2018 
2019             FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
2020         }
2021     } _SEH2_END;
2022 
2023     //
2024     //  Complete the request if there haven't been any exceptions.
2025     //
2026 
2027     CdCompleteRequest( IrpContext, Irp, Status );
2028     return Status;
2029 }
2030 
2031 
2032 //
2033 //  Local support routine
2034 //
2035 
2036 _Requires_lock_held_(_Global_critical_region_)
2037 NTSTATUS
2038 CdUnlockVolume (
2039     _Inout_ PIRP_CONTEXT IrpContext,
2040     _Inout_ PIRP Irp
2041     )
2042 
2043 /*++
2044 
2045 Routine Description:
2046 
2047     This routine performs the unlock volume operation.  It is responsible for
2048     either completing of enqueuing the input Irp.
2049 
2050 Arguments:
2051 
2052     Irp - Supplies the Irp to process
2053 
2054 Return Value:
2055 
2056     NTSTATUS - The return status for the operation
2057 
2058 --*/
2059 
2060 {
2061     NTSTATUS Status;
2062 
2063     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2064 
2065     PVCB Vcb;
2066     PFCB Fcb;
2067     PCCB Ccb;
2068 
2069     PAGED_CODE();
2070 
2071     //
2072     //  Decode the file object, the only type of opens we accept are
2073     //  user volume opens.
2074     //
2075 
2076     if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
2077 
2078         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2079         return STATUS_INVALID_PARAMETER;
2080     }
2081 
2082     //
2083     //  Acquire exclusive access to the Vcb.
2084     //
2085 
2086     Vcb = Fcb->Vcb;
2087 
2088     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
2089 
2090     //
2091     //  We won't check for a valid Vcb for this request.  An unlock will always
2092     //  succeed on a locked volume.
2093     //
2094 
2095     Status = CdUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
2096 
2097     //
2098     //  Release all of our resources
2099     //
2100 
2101     CdReleaseVcb( IrpContext, Vcb );
2102 
2103     //
2104     //  Send notification that the volume is avaliable.
2105     //
2106 
2107     if (NT_SUCCESS( Status )) {
2108 
2109         FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
2110     }
2111 
2112     //
2113     //  Complete the request if there haven't been any exceptions.
2114     //
2115 
2116     CdCompleteRequest( IrpContext, Irp, Status );
2117     return Status;
2118 }
2119 
2120 
2121 
2122 //
2123 //  Local support routine
2124 //
2125 
2126 _Requires_lock_held_(_Global_critical_region_)
2127 NTSTATUS
2128 CdDismountVolume (
2129     _Inout_ PIRP_CONTEXT IrpContext,
2130     _Inout_ PIRP Irp
2131     )
2132 
2133 /*++
2134 
2135 Routine Description:
2136 
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.
2142 
2143 Arguments:
2144 
2145     Irp - Supplies the Irp to process
2146 
2147 Return Value:
2148 
2149     NTSTATUS - The return status for the operation
2150 
2151 --*/
2152 
2153 {
2154     NTSTATUS Status;
2155     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2156 
2157     PVCB Vcb;
2158     PFCB Fcb;
2159     PCCB Ccb;
2160 
2161     PAGED_CODE();
2162 
2163     if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
2164 
2165         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2166         return STATUS_INVALID_PARAMETER;
2167     }
2168 
2169     Vcb = Fcb->Vcb;
2170 
2171     //
2172     //  Send dismount notification.
2173     //
2174 
2175     FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT );
2176 
2177     //
2178     //  Make this request waitable.
2179     //
2180 
2181     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2182 
2183     //
2184     //  Acquire exclusive access to the Vcb,  and take the global resource to
2185     //  sync. against mounts,  verifies etc.
2186     //
2187 
2188     CdAcquireCdData( IrpContext );
2189     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
2190 
2191     //
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.
2194     //
2195 
2196     if (Vcb->VcbCondition != VcbMounted) {
2197 
2198         Status = STATUS_VOLUME_DISMOUNTED;
2199 
2200     } else {
2201 
2202         //
2203         //  Invalidate the volume right now.
2204         //
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.
2208         //
2209 
2210         CdLockVcb( IrpContext, Vcb );
2211 
2212         if (Vcb->VcbCondition != VcbDismountInProgress) {
2213 
2214             CdUpdateVcbCondition( Vcb, VcbInvalid );
2215         }
2216 
2217         SetFlag( Vcb->VcbState, VCB_STATE_DISMOUNTED );
2218 
2219         CdUnlockVcb( IrpContext, Vcb );
2220 
2221 
2222         //
2223         //  Set flag to tell the close path that we want to force dismount
2224         //  the volume when this handle is closed.
2225         //
2226 
2227         SetFlag( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE);
2228 
2229         Status = STATUS_SUCCESS;
2230     }
2231 
2232     //
2233     //  Release all of our resources
2234     //
2235 
2236     CdReleaseVcb( IrpContext, Vcb );
2237     CdReleaseCdData( IrpContext );
2238 
2239 #if (NTDDI_VERSION >= NTDDI_WIN8)
2240 
2241     FsRtlDismountComplete( Vcb->TargetDeviceObject, Status );
2242 
2243 #endif
2244 
2245     //
2246     //  Complete the request if there haven't been any exceptions.
2247     //
2248 
2249     CdCompleteRequest( IrpContext, Irp, Status );
2250     return Status;
2251 }
2252 
2253 
2254 //
2255 //  Local support routine
2256 //
2257 
2258 NTSTATUS
2259 CdIsVolumeDirty (
2260     _Inout_ PIRP_CONTEXT IrpContext,
2261     _Inout_ PIRP Irp
2262     )
2263 
2264 /*++
2265 
2266 Routine Description:
2267 
2268     This routine determines if a volume is currently dirty.
2269 
2270 Arguments:
2271 
2272     Irp - Supplies the Irp to process
2273 
2274 Return Value:
2275 
2276     NTSTATUS - The return status for the operation
2277 
2278 --*/
2279 
2280 {
2281     PIO_STACK_LOCATION IrpSp;
2282 
2283     TYPE_OF_OPEN TypeOfOpen;
2284     PFCB Fcb;
2285     PCCB Ccb;
2286 
2287     PULONG VolumeState;
2288 
2289     PAGED_CODE();
2290 
2291     //
2292     //  Get the current stack location and extract the output
2293     //  buffer information.
2294     //
2295 
2296     IrpSp = IoGetCurrentIrpStackLocation( Irp );
2297 
2298     //
2299     //  Get a pointer to the output buffer.
2300     //
2301 
2302     if (Irp->AssociatedIrp.SystemBuffer != NULL) {
2303 
2304         VolumeState = Irp->AssociatedIrp.SystemBuffer;
2305 
2306     } else {
2307 
2308         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
2309         return STATUS_INVALID_USER_BUFFER;
2310     }
2311 
2312     //
2313     //  Make sure the output buffer is large enough and then initialize
2314     //  the answer to be that the volume isn't dirty.
2315     //
2316 
2317     if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
2318 
2319         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2320         return STATUS_INVALID_PARAMETER;
2321     }
2322 
2323     *VolumeState = 0;
2324 
2325     //
2326     //  Decode the file object
2327     //
2328 
2329     TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
2330 
2331     if (TypeOfOpen != UserVolumeOpen) {
2332 
2333         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2334         return STATUS_INVALID_PARAMETER;
2335     }
2336 
2337     if (Fcb->Vcb->VcbCondition != VcbMounted) {
2338 
2339         CdCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
2340         return STATUS_VOLUME_DISMOUNTED;
2341     }
2342 
2343     //
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.
2346     //
2347 
2348     Irp->IoStatus.Information = sizeof( ULONG );
2349 
2350     CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
2351     return STATUS_SUCCESS;
2352 }
2353 
2354 
2355 //
2356 //  Local support routine
2357 //
2358 
2359 NTSTATUS
2360 CdIsVolumeMounted (
2361     _Inout_ PIRP_CONTEXT IrpContext,
2362     _Inout_ PIRP Irp
2363     )
2364 
2365 /*++
2366 
2367 Routine Description:
2368 
2369     This routine determines if a volume is currently mounted.
2370 
2371 Arguments:
2372 
2373     Irp - Supplies the Irp to process
2374 
2375 Return Value:
2376 
2377     NTSTATUS - The return status for the operation
2378 
2379 --*/
2380 
2381 {
2382     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2383 
2384     PFCB Fcb;
2385     PCCB Ccb;
2386 
2387     PAGED_CODE();
2388 
2389     //
2390     //  Decode the file object.
2391     //
2392 
2393     CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
2394 
2395     if (Fcb != NULL) {
2396 
2397         //
2398         //  Disable PopUps, we want to return any error.
2399         //
2400 
2401         SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS );
2402 
2403         //
2404         //  Verify the Vcb.  This will raise in the error condition.
2405         //
2406 
2407         CdVerifyVcb( IrpContext, Fcb->Vcb );
2408     }
2409 
2410     CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
2411 
2412     return STATUS_SUCCESS;
2413 }
2414 
2415 
2416 //
2417 //  Local support routine
2418 //
2419 
2420 NTSTATUS
2421 CdIsPathnameValid (
2422     _Inout_ PIRP_CONTEXT IrpContext,
2423     _Inout_ PIRP Irp
2424     )
2425 
2426 /*++
2427 
2428 Routine Description:
2429 
2430     This routine determines if pathname is a valid CDFS pathname.
2431     We always succeed this request.
2432 
2433 Arguments:
2434 
2435     Irp - Supplies the Irp to process.
2436 
2437 Return Value:
2438 
2439     None
2440 
2441 --*/
2442 
2443 {
2444     PAGED_CODE();
2445 
2446     CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
2447     return STATUS_SUCCESS;
2448 }
2449 
2450 
2451 //
2452 //  Local support routine
2453 //
2454 
2455 _Requires_lock_held_(_Global_critical_region_)
2456 NTSTATUS
2457 CdInvalidateVolumes (
2458     _Inout_ PIRP_CONTEXT IrpContext,
2459     _Inout_ PIRP Irp
2460     )
2461 
2462 /*++
2463 
2464 Routine Description:
2465 
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.
2469 
2470 Arguments:
2471 
2472     Irp - Supplies the Irp to process
2473 
2474 Return Value:
2475 
2476     NTSTATUS - The return status for the operation
2477 
2478 --*/
2479 
2480 {
2481     NTSTATUS Status;
2482     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2483     KIRQL SavedIrql;
2484 
2485     BOOLEAN UnlockVcb = FALSE;
2486 
2487     LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
2488 
2489     HANDLE Handle;
2490 
2491     PVCB Vcb;
2492 
2493     PLIST_ENTRY Links;
2494 
2495     PFILE_OBJECT FileToMarkBad;
2496     PDEVICE_OBJECT DeviceToMarkBad;
2497 
2498     //
2499     //  We only allow the invalidate call to come in on our file system devices.
2500     //
2501 
2502 #ifndef __REACTOS__
2503     if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject)  {
2504 #else
2505     if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject &&
2506         IrpSp->DeviceObject != CdData.HddFileSystemDeviceObject)  {
2507 #endif
2508 
2509         CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
2510 
2511         return STATUS_INVALID_DEVICE_REQUEST;
2512     }
2513 
2514     //
2515     //  Check for the correct security access.
2516     //  The caller must have the SeTcbPrivilege.
2517     //
2518 
2519     if (!SeSinglePrivilegeCheck( TcbPrivilege, Irp->RequestorMode )) {
2520 
2521         CdCompleteRequest( IrpContext, Irp, STATUS_PRIVILEGE_NOT_HELD );
2522 
2523         return STATUS_PRIVILEGE_NOT_HELD;
2524     }
2525 
2526     //
2527     //  Try to get a pointer to the device object from the handle passed in.
2528     //
2529 
2530 #if defined(_WIN64) && BUILD_WOW64_ENABLED
2531 
2532     if (IoIs32bitProcess( Irp )) {
2533 
2534         if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( UINT32 )) {
2535 
2536             CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2537             return STATUS_INVALID_PARAMETER;
2538         }
2539 
2540         Handle = (HANDLE) LongToHandle( *((PUINT32) Irp->AssociatedIrp.SystemBuffer) );
2541 
2542     } else
2543 
2544 #endif
2545 
2546     {
2547         if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) {
2548 
2549             CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
2550             return STATUS_INVALID_PARAMETER;
2551         }
2552 
2553         Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer);
2554     }
2555 
2556     Status = ObReferenceObjectByHandle( Handle,
2557                                         0,
2558                                         *IoFileObjectType,
2559                                         KernelMode,
2560                                         (PVOID*)&FileToMarkBad, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
2561                                         NULL );
2562 
2563     if (!NT_SUCCESS(Status)) {
2564 
2565         CdCompleteRequest( IrpContext, Irp, Status );
2566         return Status;
2567     }
2568 
2569     //
2570     //  Grab the DeviceObject from the FileObject.
2571     //
2572 
2573     DeviceToMarkBad = FileToMarkBad->DeviceObject;
2574 
2575     //
2576     //  We only needed the device object involved, not a reference to the file.
2577     //
2578 
2579     ObDereferenceObject( FileToMarkBad );
2580 
2581     //
2582     //  Make sure this request can wait.
2583     //
2584 
2585     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
2586     ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
2587 
2588     //
2589     //  Synchronise with pnp/mount/verify paths.
2590     //
2591 
2592     CdAcquireCdData( IrpContext );
2593 
2594     //
2595     //  Nothing can go wrong now.
2596     //
2597 
2598     //
2599     //  Now walk through all the mounted Vcb's looking for candidates to
2600     //  mark invalid.
2601     //
2602     //  On volumes we mark invalid, check for dismount possibility (which is
2603     //  why we have to get the next link so early).
2604     //
2605 
2606     Links = CdData.VcbQueue.Flink;
2607 
2608     while (Links != &CdData.VcbQueue) {
2609 
2610         Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks);
2611 
2612         Links = Links->Flink;
2613 
2614         //
2615         //  If we get a match, mark the volume Bad, and also check to
2616         //  see if the volume should go away.
2617         //
2618 
2619         CdLockVcb( IrpContext, Vcb );
2620 
2621         if (Vcb->Vpb->RealDevice == DeviceToMarkBad) {
2622 
2623             //
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
2626             //  off immediately.
2627             //
2628 
2629             IoAcquireVpbSpinLock( &SavedIrql );
2630 
2631 #ifdef _MSC_VER
2632 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed")
2633 #endif
2634             if (DeviceToMarkBad->Vpb == Vcb->Vpb)  {
2635 
2636                 PVPB NewVpb = Vcb->SwapVpb;
2637 
2638                 NT_ASSERT( FlagOn( Vcb->Vpb->Flags, VPB_MOUNTED));
2639                 NT_ASSERT( NULL != NewVpb);
2640 
2641                 RtlZeroMemory( NewVpb, sizeof( VPB ) );
2642 
2643                 NewVpb->Type = IO_TYPE_VPB;
2644                 NewVpb->Size = sizeof( VPB );
2645                 NewVpb->RealDevice = DeviceToMarkBad;
2646 
2647 #ifdef _MSC_VER
2648 #pragma prefast(push)
2649 #pragma prefast(disable: 28175, "this is a filesystem driver, touching the vpb is allowed")
2650 #endif
2651                 NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
2652                 DeviceToMarkBad->Vpb = NewVpb;
2653 #ifdef _MSC_VER
2654 #pragma prefast(pop)
2655 #endif
2656 
2657                 Vcb->SwapVpb = NULL;
2658             }
2659 
2660             IoReleaseVpbSpinLock( SavedIrql );
2661 
2662             if (Vcb->VcbCondition != VcbDismountInProgress) {
2663 
2664                 CdUpdateVcbCondition( Vcb, VcbInvalid);
2665             }
2666 
2667             CdUnlockVcb( IrpContext, Vcb );
2668 
2669             CdAcquireVcbExclusive( IrpContext, Vcb, FALSE);
2670 
2671             CdPurgeVolume( IrpContext, Vcb, FALSE );
2672 
2673             UnlockVcb = CdCheckForDismount( IrpContext, Vcb, FALSE );
2674 
2675             //
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.
2678             //
2679 
2680             __analysis_assert( UnlockVcb == TRUE );
2681 
2682             if (UnlockVcb)  {
2683 
2684                 CdReleaseVcb( IrpContext, Vcb);
2685             }
2686 
2687         } else {
2688 
2689             CdUnlockVcb( IrpContext, Vcb );
2690         }
2691     }
2692 
2693     CdReleaseCdData( IrpContext );
2694 
2695     CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
2696     return STATUS_SUCCESS;
2697 }
2698 
2699 
2700 //
2701 //  Local support routine
2702 //
2703 
2704 NTSTATUS
2705 CdAllowExtendedDasdIo (
2706     _Inout_ PIRP_CONTEXT IrpContext,
2707     _Inout_ PIRP Irp
2708     )
2709 
2710 /*++
2711 
2712 Routine Description:
2713 
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.
2717 
2718 Arguments:
2719 
2720     Irp - Supplies the Irp to process
2721 
2722 Return Value:
2723 
2724     NTSTATUS - The return status for the operation
2725 
2726 --*/
2727 
2728 {
2729     NTSTATUS Status;
2730     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2731 
2732     PFCB Fcb;
2733     PCCB Ccb;
2734 
2735     PAGED_CODE();
2736 
2737     //
2738     //  Decode the file object, the only type of opens we accept are
2739     //  user volume opens.
2740     //
2741 
2742     if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
2743 
2744         Status = STATUS_INVALID_PARAMETER;
2745     }
2746     else {
2747 
2748         SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO );
2749         Status = STATUS_SUCCESS;
2750     }
2751 
2752     CdCompleteRequest( IrpContext, Irp, Status );
2753     return Status;
2754 }
2755 
2756 
2757 //
2758 //  Local support routine
2759 //
2760 
2761 _Requires_lock_held_(_Global_critical_region_)
2762 VOID
2763 CdScanForDismountedVcb (
2764     _Inout_ PIRP_CONTEXT IrpContext
2765     )
2766 
2767 /*++
2768 
2769 Routine Description:
2770 
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.
2774 
2775 Arguments:
2776 
2777 Return Value:
2778 
2779     None
2780 
2781 --*/
2782 
2783 {
2784     PVCB Vcb;
2785     PLIST_ENTRY Links;
2786 
2787     PAGED_CODE();
2788 
2789     //
2790     //  Walk through all of the Vcb's attached to the global data.
2791     //
2792 
2793     Links = CdData.VcbQueue.Flink;
2794 
2795     while (Links != &CdData.VcbQueue) {
2796 
2797         Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
2798 
2799         //
2800         //  Move to the next link now since the current Vcb may be deleted.
2801         //
2802 
2803         Links = Links->Flink;
2804 
2805         //
2806         //  If dismount is already underway then check if this Vcb can
2807         //  go away.
2808         //
2809 
2810         if ((Vcb->VcbCondition == VcbDismountInProgress) ||
2811             (Vcb->VcbCondition == VcbInvalid) ||
2812             ((Vcb->VcbCondition == VcbNotMounted) && (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE))) {
2813 
2814             CdCheckForDismount( IrpContext, Vcb, FALSE );
2815         }
2816     }
2817 
2818     return;
2819 }
2820 
2821 
2822 //
2823 //  Local support routine
2824 //
2825 _Success_(return != FALSE)
2826 BOOLEAN
2827 CdFindPrimaryVd (
2828     _In_ PIRP_CONTEXT IrpContext,
2829     _Inout_ PVCB Vcb,
2830     _Out_writes_bytes_(SECTOR_SIZE) PCHAR RawIsoVd,
2831     _In_ ULONG BlockFactor,
2832     _In_ BOOLEAN ReturnOnError,
2833     _In_ BOOLEAN VerifyVolume
2834     )
2835 
2836 /*++
2837 
2838 Routine Description:
2839 
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.
2844 
2845 Arguments:
2846 
2847     Vcb - Pointer to the VCB for the volume.
2848 
2849     RawIsoVd - Pointer to a sector buffer which will contain the primary
2850                volume descriptor on exit, if successful.
2851 
2852     BlockFactor - Block factor used by the current device for the TableOfContents.
2853 
2854     ReturnOnError - Indicates that we should raise on I/O errors rather than
2855         returning a FALSE value.
2856 
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
2859         the verify path.
2860 
2861 Return Value:
2862 
2863     BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
2864               otherwise.
2865 
2866 --*/
2867 
2868 {
2869     NTSTATUS Status;
2870     ULONG ThisPass = 1;
2871     BOOLEAN FoundVd = FALSE;
2872 
2873     ULONG BaseSector;
2874     ULONG SectorOffset;
2875 
2876     PCDROM_TOC_LARGE CdromToc;
2877 
2878     ULONG VolumeFlags;
2879 
2880     PAGED_CODE();
2881 
2882     //
2883     //  If there are no data tracks, don't even bother hunting for descriptors.
2884     //
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.
2892     //
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.
2895     //
2896 
2897     if (FlagOn(Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
2898 
2899         return FALSE;
2900     }
2901 
2902     //
2903     //  We will make at most two passes through the volume descriptor sequence.
2904     //
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
2908     //  information.
2909     //
2910     //  On the second pass we will start offset from sector zero.
2911     //
2912 
2913     while (!FoundVd && (ThisPass <= 2)) {
2914 
2915         //
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.
2918         //
2919 
2920         BaseSector = 0;
2921 
2922         if (ThisPass == 1) {
2923 
2924             CdromToc = NULL;
2925 
2926             //
2927             //  Check for whether this device supports XA and multi-session.
2928             //
2929 
2930             _SEH2_TRY {
2931 
2932                 //
2933                 //  Allocate a buffer for the last session information.
2934                 //
2935 
2936                 CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
2937                                                      sizeof( CDROM_TOC_LARGE ),
2938                                                      TAG_CDROM_TOC );
2939 
2940                 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE ));
2941 
2942                 //
2943                 //  Query the last session information from the driver.
2944                 //
2945 
2946                 Status = CdPerformDevIoCtrl( IrpContext,
2947                                              IOCTL_CDROM_GET_LAST_SESSION,
2948                                              Vcb->TargetDeviceObject,
2949                                              CdromToc,
2950                                              sizeof( CDROM_TOC_LARGE ),
2951                                              FALSE,
2952                                              TRUE,
2953                                              NULL );
2954 
2955                 //
2956                 //  Raise an exception if there was an allocation failure.
2957                 //
2958 
2959                 if (Status == STATUS_INSUFFICIENT_RESOURCES) {
2960 
2961                     CdRaiseStatus( IrpContext, Status );
2962                 }
2963 
2964                 //
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.
2968                 //
2969 
2970                 if (NT_SUCCESS( Status ) &&
2971                     (CdromToc->FirstTrack != CdromToc->LastTrack)) {
2972 
2973                     PCHAR Source, Dest;
2974                     ULONG Count;
2975 
2976                     Count = 4;
2977 
2978                     //
2979                     //  The track address is BigEndian, we need to flip the bytes.
2980                     //
2981 
2982                     Source = (PCHAR) &CdromToc->TrackData[0].Address[3];
2983                     Dest = (PCHAR) &BaseSector;
2984 
2985                     do {
2986 
2987                         *Dest++ = *Source--;
2988 
2989                     } while (--Count);
2990 
2991                     //
2992                     //  Now adjust the base sector by the block factor of the
2993                     //  device.
2994                     //
2995 
2996                     BaseSector /= BlockFactor;
2997 
2998                 //
2999                 //  Make this look like the second pass since we are only using the
3000                 //  first session.  No reason to retry on error.
3001                 //
3002 
3003                 } else {
3004 
3005                     ThisPass += 1;
3006                 }
3007 
3008             } _SEH2_FINALLY {
3009 
3010                 if (CdromToc != NULL) { CdFreePool( &CdromToc ); }
3011             } _SEH2_END;
3012         }
3013 
3014         //
3015         //  Compute the starting sector offset from the start of the session.
3016         //
3017 
3018         SectorOffset = FIRST_VD_SECTOR;
3019 
3020         //
3021         //  Start by assuming we have neither Hsg or Iso volumes.
3022         //
3023 
3024         VolumeFlags = 0;
3025 
3026         //
3027         //  Loop until either error encountered, primary volume descriptor is
3028         //  found or a terminal volume descriptor is found.
3029         //
3030 
3031         while (TRUE) {
3032 
3033             //
3034             //  Attempt to read the desired sector. Exit directly if operation
3035             //  not completed.
3036             //
3037             //  If this is pass 1 we will ignore errors in read sectors and just
3038             //  go to the next pass.
3039             //
3040 
3041             if (!CdReadSectors( IrpContext,
3042                                 LlBytesFromSectors( BaseSector + SectorOffset ),
3043                                 SECTOR_SIZE,
3044                                 (BOOLEAN) ((ThisPass == 1) || ReturnOnError),
3045                                 RawIsoVd,
3046                                 Vcb->TargetDeviceObject )) {
3047 
3048                 break;
3049             }
3050 
3051             //
3052             //  Check if either an ISO or HSG volume.
3053             //
3054 
3055             if (RtlEqualMemory( CdIsoId,
3056                                 CdRvdId( RawIsoVd, VCB_STATE_ISO ),
3057                                 VOL_ID_LEN )) {
3058 
3059                 SetFlag( VolumeFlags, VCB_STATE_ISO );
3060 
3061             } else if (RtlEqualMemory( CdHsgId,
3062                                        CdRvdId( RawIsoVd, VCB_STATE_HSG ),
3063                                        VOL_ID_LEN )) {
3064 
3065                 SetFlag( VolumeFlags, VCB_STATE_HSG );
3066 
3067             //
3068             //  We have neither so break out of the loop.
3069             //
3070 
3071             } else {
3072 
3073                  break;
3074             }
3075 
3076             //
3077             //  Break out if the version number is incorrect or this is
3078             //  a terminator.
3079             //
3080 
3081             if ((CdRvdVersion( RawIsoVd, VolumeFlags ) != VERSION_1) ||
3082                 (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_TERMINATOR)) {
3083 
3084                 break;
3085             }
3086 
3087             //
3088             //  If this is a primary volume descriptor then our search is over.
3089             //
3090 
3091             if (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_PRIMARY) {
3092 
3093                 //
3094                 //  If we are not in the verify path then initialize the
3095                 //  fields in the Vcb with basic information from this
3096                 //  descriptor.
3097                 //
3098 
3099                 if (!VerifyVolume) {
3100 
3101                     //
3102                     //  Set the flag for the volume type.
3103                     //
3104 
3105                     SetFlag( Vcb->VcbState, VolumeFlags );
3106 
3107                     //
3108                     //  Store the base sector and sector offset for the
3109                     //  primary volume descriptor.
3110                     //
3111 
3112                     Vcb->BaseSector = BaseSector;
3113                     Vcb->VdSectorOffset = SectorOffset;
3114                     Vcb->PrimaryVdSectorOffset = SectorOffset;
3115                 }
3116 
3117                 FoundVd = TRUE;
3118                 break;
3119             }
3120 
3121             //
3122             //  Indicate that we're at the next sector.
3123             //
3124 
3125             SectorOffset += 1;
3126         }
3127 
3128         ThisPass += 1;
3129     }
3130 
3131     return FoundVd;
3132 }
3133 
3134 
3135 //
3136 //  Local support routine
3137 //
3138 
3139 _Success_(return != FALSE) BOOLEAN
3140 CdIsRemount (
3141     _In_ PIRP_CONTEXT IrpContext,
3142     _In_ PVCB Vcb,
3143     _Out_ PVCB *OldVcb
3144     )
3145 /*++
3146 
3147 Routine Description:
3148 
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:
3152 
3153         If the new Vcb is a device only Mvcb and there is a previous
3154         device only Mvcb.
3155 
3156         Otherwise following conditions must be matched.
3157 
3158             1 - The 32 serial in the current VPB matches that in a previous
3159                 VPB.
3160 
3161             2 - The volume label in the Vpb matches that in the previous
3162                 Vpb.
3163 
3164             3 - The system pointer to the real device object in the current
3165                 VPB matches that in the same previous VPB.
3166 
3167             4 - Finally the previous Vcb cannot be invalid or have a dismount
3168                 underway.
3169 
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.
3172 
3173     Skip over the current Vcb.
3174 
3175 Arguments:
3176 
3177     Vcb - This is the Vcb we are checking for a remount.
3178 
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
3181               a pointer)
3182 
3183 Return Value:
3184 
3185     BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
3186 
3187 --*/
3188 
3189 {
3190     PLIST_ENTRY Link;
3191 
3192     PVPB Vpb = Vcb->Vpb;
3193     PVPB OldVpb;
3194 
3195     BOOLEAN Remount = FALSE;
3196 
3197     PAGED_CODE();
3198 
3199     UNREFERENCED_PARAMETER( IrpContext );
3200 
3201     //
3202     //  Check whether we are looking for a device only Mvcb.
3203     //
3204 
3205     for (Link = CdData.VcbQueue.Flink;
3206          Link != &CdData.VcbQueue;
3207          Link = Link->Flink) {
3208 
3209         *OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks );
3210 
3211         //
3212         //  Skip ourselves.
3213         //
3214 
3215         if (Vcb == *OldVcb) { continue; }
3216 
3217         //
3218         //  Look at the Vpb and state of the previous Vcb.
3219         //
3220 
3221         OldVpb = (*OldVcb)->Vpb;
3222 
3223         if ((OldVpb != Vpb) &&
3224             (OldVpb->RealDevice == Vpb->RealDevice) &&
3225             ((*OldVcb)->VcbCondition == VcbNotMounted)) {
3226 
3227             //
3228             //  If the current disk is a raw disk then it can match a previous music or
3229             //  raw disk.
3230             //
3231 
3232             if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
3233 
3234                 if (FlagOn( (*OldVcb)->VcbState, VCB_STATE_AUDIO_DISK )) {
3235 
3236                     //
3237                     //  If we have both TOC then fail the remount if the lengths
3238                     //  are different or they don't match.
3239                     //
3240 
3241                     if ((Vcb->TocLength != (*OldVcb)->TocLength) ||
3242                         ((Vcb->TocLength != 0) &&
3243                          !RtlEqualMemory( Vcb->CdromToc,
3244                                           (*OldVcb)->CdromToc,
3245                                           Vcb->TocLength ))) {
3246 
3247                         continue;
3248                     }
3249 
3250                     Remount = TRUE;
3251                     break;
3252                 }
3253 
3254             //
3255             //  The current disk is not a raw disk.  Go ahead and compare
3256             //  serial numbers, volume label and TOC.
3257             //
3258 
3259             }
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,
3267                                         Vpb->VolumeLabel,
3268                                         Vpb->VolumeLabelLength ))) {
3269                 //
3270                 //  Remember the old Vcb.  Then set the return value to
3271                 //  TRUE and break.
3272                 //
3273 
3274                 Remount = TRUE;
3275                 break;
3276             }
3277         }
3278     }
3279 
3280     return Remount;
3281 }
3282 
3283 
3284 //
3285 //  Local support routine
3286 //
3287 
3288 VOID
3289 CdFindActiveVolDescriptor (
3290     _In_ PIRP_CONTEXT IrpContext,
3291     _In_ PVCB Vcb,
3292     _Inout_updates_bytes_(ROUND_TO_PAGES( SECTOR_SIZE )) PCHAR RawIsoVd,
3293     _In_ BOOLEAN VerifyVolume
3294     )
3295 
3296 /*++
3297 
3298 Routine Description:
3299 
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.
3303 
3304     If we don't find the secondary descriptor then we will reread the primary.
3305 
3306     This routine will update the serial number and volume label in the Vpb.
3307 
3308 Arguments:
3309 
3310     Vcb - This is the Vcb for the volume being mounted.
3311 
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
3314                buffer.
3315 
3316     VerifyVolume - indicates we are being called by the verify path, and should
3317                    not modify the Vcb fields.
3318 
3319 Return Value:
3320 
3321     None
3322 
3323 --*/
3324 
3325 {
3326     BOOLEAN FoundSecondaryVd = FALSE;
3327     ULONG SectorOffset = FIRST_VD_SECTOR;
3328 
3329     ULONG Length;
3330 
3331     ULONG Index;
3332 
3333     PAGED_CODE();
3334 
3335     //
3336     //  We only look for secondary volume descriptors on an Iso disk.
3337     //
3338 
3339     if ((FlagOn( Vcb->VcbState, VCB_STATE_ISO) || VerifyVolume) && !CdNoJoliet) {
3340 
3341         //
3342         //  Scan the volume descriptors from the beginning looking for a valid
3343         //  secondary or a terminator.
3344         //
3345 
3346         SectorOffset = FIRST_VD_SECTOR;
3347 
3348         while (TRUE) {
3349 
3350             //
3351             //  Read the next sector.  We should never have an error in this
3352             //  path.
3353             //
3354 
3355             CdReadSectors( IrpContext,
3356                            LlBytesFromSectors( Vcb->BaseSector + SectorOffset ),
3357                            SECTOR_SIZE,
3358                            FALSE,
3359                            RawIsoVd,
3360                            Vcb->TargetDeviceObject );
3361 
3362             //
3363             //  Break out if the version number or standard Id is incorrect.
3364             //  Also break out if this is a terminator.
3365             //
3366 
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)) {
3370 
3371                 break;
3372             }
3373 
3374             //
3375             //  We have a match if this is a secondary descriptor with a matching
3376             //  escape sequence.
3377             //
3378 
3379             if ((CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_SECONDARY) &&
3380                 (RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
3381                                  CdJolietEscape[0],
3382                                  ESC_SEQ_LEN ) ||
3383                  RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
3384                                  CdJolietEscape[1],
3385                                  ESC_SEQ_LEN ) ||
3386                  RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
3387                                  CdJolietEscape[2],
3388                                  ESC_SEQ_LEN ))) {
3389 
3390                 if (!VerifyVolume)  {
3391 
3392                     //
3393                     //  Update the Vcb with the new volume descriptor.
3394                     //
3395 
3396                     ClearFlag( Vcb->VcbState, VCB_STATE_ISO );
3397                     SetFlag( Vcb->VcbState, VCB_STATE_JOLIET );
3398 
3399                     Vcb->VdSectorOffset = SectorOffset;
3400                 }
3401 
3402                 FoundSecondaryVd = TRUE;
3403                 break;
3404             }
3405 
3406             //
3407             //  Otherwise move on to the next sector.
3408             //
3409 
3410             SectorOffset += 1;
3411         }
3412 
3413         //
3414         //  If we didn't find the secondary then recover the original volume
3415         //  descriptor stored in the second half of the RawIsoVd.
3416         //
3417 
3418         if (!FoundSecondaryVd) {
3419 
3420             RtlCopyMemory( RawIsoVd,
3421                            Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
3422                            SECTOR_SIZE );
3423         }
3424     }
3425 
3426     //
3427     //  If we're in the verify path,  our work is done,  since we don't want
3428     //  to update any Vcb/Vpb values.
3429     //
3430 
3431     if (VerifyVolume)  {
3432 
3433         return;
3434     }
3435 
3436     //
3437     //  Compute the serial number and volume label from the volume descriptor.
3438     //
3439 
3440     Vcb->Vpb->SerialNumber = CdSerial32( RawIsoVd, SECTOR_SIZE );
3441 
3442     //
3443     //  Make sure the CD label will fit in the Vpb.
3444     //
3445 
3446     NT_ASSERT( VOLUME_ID_LENGTH * sizeof( WCHAR ) <= MAXIMUM_VOLUME_LABEL_LENGTH );
3447 
3448     //
3449     //  If this is not a Unicode label we must convert it to unicode.
3450     //
3451 
3452     if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
3453 
3454         //
3455         //  Convert the label to unicode.  If we get any error then use a name
3456         //  length of zero.
3457         //
3458 
3459         Vcb->Vpb->VolumeLabelLength = 0;
3460 
3461         if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb->Vpb->VolumeLabel[0],
3462                                           MAXIMUM_VOLUME_LABEL_LENGTH,
3463                                           &Length,
3464                                           (PCH)CdRvdVolId( RawIsoVd, Vcb->VcbState ),
3465                                           VOLUME_ID_LENGTH ))) {
3466 
3467             Vcb->Vpb->VolumeLabelLength = (USHORT) Length;
3468         }
3469 
3470     //
3471     //  We need to convert from big-endian to little endian.
3472     //
3473 
3474     } else {
3475 
3476         CdConvertBigToLittleEndian( IrpContext,
3477                                     (PCHAR) CdRvdVolId( RawIsoVd, Vcb->VcbState ),
3478                                     VOLUME_ID_LENGTH,
3479                                     (PCHAR) Vcb->Vpb->VolumeLabel );
3480 
3481         Vcb->Vpb->VolumeLabelLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
3482     }
3483 
3484     //
3485     //  Strip the trailing spaces or zeroes from the name.
3486     //
3487 
3488     Index = Vcb->Vpb->VolumeLabelLength / sizeof( WCHAR );
3489 
3490     while (Index > 0) {
3491 
3492         if ((Vcb->Vpb->VolumeLabel[ Index - 1 ] != L'\0') &&
3493             (Vcb->Vpb->VolumeLabel[ Index - 1 ] != L' ')) {
3494 
3495             break;
3496         }
3497 
3498         Index -= 1;
3499     }
3500 
3501     //
3502     //  Now set the final length for the name.
3503     //
3504 
3505     Vcb->Vpb->VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
3506 }
3507 
3508 
3509 
3510