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