4 Copyright (c) 1989-2000 Microsoft Corporation
12 This module implements the File System Control routines for Fat called
13 by the dispatch driver.
21 // The Bug check file id for this module
24 #define BugCheckFileId (FAT_BUG_CHECK_FSCTRL)
27 // The local debug trace level
30 #define Dbg (DEBUG_TRACE_FSCTRL)
33 // Local procedure prototypes
38 IN PIRP_CONTEXT IrpContext
,
39 IN PDEVICE_OBJECT TargetDeviceObject
,
41 IN PDEVICE_OBJECT FsDeviceObject
46 IN PIRP_CONTEXT IrpContext
,
51 FatIsMediaWriteProtected (
52 IN PIRP_CONTEXT IrpContext
,
53 IN PDEVICE_OBJECT TargetDeviceObject
58 IN PIRP_CONTEXT IrpContext
,
64 IN PIRP_CONTEXT IrpContext
,
70 IN PIRP_CONTEXT IrpContext
,
76 IN PIRP_CONTEXT IrpContext
,
82 IN PIRP_CONTEXT IrpContext
,
88 IN PIRP_CONTEXT IrpContext
,
94 IN PIRP_CONTEXT IrpContext
,
100 IN PIRP_CONTEXT IrpContext
,
106 IN PIRP_CONTEXT IrpContext
,
111 FatInvalidateVolumes (
116 FatScanForDismountedVcb (
117 IN PIRP_CONTEXT IrpContext
121 FatPerformVerifyDiskRead (
122 IN PIRP_CONTEXT IrpContext
,
126 IN ULONG NumberOfBytesToRead
,
127 IN BOOLEAN ReturnOnError
131 FatQueryRetrievalPointers (
132 IN PIRP_CONTEXT IrpContext
,
138 IN PIRP_CONTEXT IrpContext
,
144 IN PIRP_CONTEXT IrpContext
,
149 FatAllowExtendedDasdIo (
150 IN PIRP_CONTEXT IrpContext
,
155 // Local support routine prototypes
160 IN PIRP_CONTEXT IrpContext
,
165 FatGetRetrievalPointers (
166 IN PIRP_CONTEXT IrpContext
,
172 IN PIRP_CONTEXT IrpContext
,
177 FatComputeMoveFileSplicePoints (
178 PIRP_CONTEXT IrpContext
,
182 ULONG BytesToReallocate
,
183 PULONG FirstSpliceSourceCluster
,
184 PULONG FirstSpliceTargetCluster
,
185 PULONG SecondSpliceSourceCluster
,
186 PULONG SecondSpliceTargetCluster
,
191 FatComputeMoveFileParameter (
192 IN PIRP_CONTEXT IrpContext
,
196 IN OUT PULONG ByteCount
,
197 OUT PULONG BytesToReallocate
,
198 OUT PULONG BytesToWrite
,
199 OUT PLARGE_INTEGER SourceLbo
203 FatSearchBufferForLabel(
204 IN PIRP_CONTEXT IrpContext
,
208 OUT PBOOLEAN LabelFound
212 FatVerifyLookupFatEntry (
213 IN PIRP_CONTEXT IrpContext
,
216 IN OUT PULONG FatEntry
221 #pragma alloc_text(PAGE, FatAddMcbEntry)
222 #pragma alloc_text(PAGE, FatAllowExtendedDasdIo)
223 #pragma alloc_text(PAGE, FatCommonFileSystemControl)
224 #pragma alloc_text(PAGE, FatComputeMoveFileParameter)
225 #pragma alloc_text(PAGE, FatComputeMoveFileSplicePoints)
226 #pragma alloc_text(PAGE, FatDirtyVolume)
227 #pragma alloc_text(PAGE, FatDismountVolume)
228 #pragma alloc_text(PAGE, FatFsdFileSystemControl)
229 #pragma alloc_text(PAGE, FatGetRetrievalPointers)
230 #pragma alloc_text(PAGE, FatGetStatistics)
231 #pragma alloc_text(PAGE, FatGetVolumeBitmap)
232 #pragma alloc_text(PAGE, FatIsMediaWriteProtected)
233 #pragma alloc_text(PAGE, FatIsPathnameValid)
234 #pragma alloc_text(PAGE, FatIsVolumeDirty)
235 #pragma alloc_text(PAGE, FatIsVolumeMounted)
236 #pragma alloc_text(PAGE, FatLockVolume)
237 #pragma alloc_text(PAGE, FatLookupLastMcbEntry)
238 #pragma alloc_text(PAGE, FatMountVolume)
239 #pragma alloc_text(PAGE, FatMoveFile)
240 #pragma alloc_text(PAGE, FatOplockRequest)
241 #pragma alloc_text(PAGE, FatPerformVerifyDiskRead)
242 #pragma alloc_text(PAGE, FatQueryBpb)
243 #pragma alloc_text(PAGE, FatQueryRetrievalPointers)
244 #pragma alloc_text(PAGE, FatRemoveMcbEntry)
245 #pragma alloc_text(PAGE, FatScanForDismountedVcb)
246 #pragma alloc_text(PAGE, FatSearchBufferForLabel)
247 #pragma alloc_text(PAGE, FatUnlockVolume)
248 #pragma alloc_text(PAGE, FatUserFsCtrl)
249 #pragma alloc_text(PAGE, FatVerifyLookupFatEntry)
250 #pragma alloc_text(PAGE, FatVerifyVolume)
255 BOOLEAN FatMoveFileDebug
= 0;
260 // These wrappers go around the MCB package; we scale the LBO's passed
261 // in (which can be bigger than 32 bits on fat32) by the volume's sector
264 // Note we now use the real large mcb package. This means these shims
265 // now also convert the -1 unused LBN number to the 0 of the original
269 #define MCB_SCALE_LOG2 (Vcb->AllocationSupport.LogOfBytesPerSector)
270 #define MCB_SCALE (1 << MCB_SCALE_LOG2)
271 #define MCB_SCALE_MODULO (MCB_SCALE - 1)
289 // Round up sectors, but be careful as SectorCount approaches 4Gb.
290 // Note that for x>0, (x+m-1)/m = ((x-1)/m)+(m/m) = ((x-1)/m)+1
294 SectorCount
>>= MCB_SCALE_LOG2
;
298 Vbo
>>= MCB_SCALE_LOG2
;
299 Lbo
>>= MCB_SCALE_LOG2
;
301 return FsRtlAddLargeMcbEntry( Mcb
,
304 ((LONGLONG
) SectorCount
) );
314 OUT PULONG SectorCount OPTIONAL
,
315 OUT PULONG Index OPTIONAL
320 LONGLONG LiSectorCount
;
326 Remainder
= Vbo
& MCB_SCALE_MODULO
;
328 Results
= FsRtlLookupLargeMcbEntry( Mcb
,
329 (Vbo
>> MCB_SCALE_LOG2
),
331 ARGUMENT_PRESENT(SectorCount
) ? &LiSectorCount
: NULL
,
336 if ((ULONG
) LiLbo
!= -1) {
338 *Lbo
= (((LBO
) LiLbo
) << MCB_SCALE_LOG2
);
350 if (ARGUMENT_PRESENT(SectorCount
)) {
352 *SectorCount
= (ULONG
) LiSectorCount
;
356 *SectorCount
<<= MCB_SCALE_LOG2
;
358 if (*SectorCount
== 0) {
360 *SectorCount
= (ULONG
) -1;
365 *SectorCount
-= Remainder
;
375 // NOTE: Vbo/Lbn undefined if MCB is empty & return code false.
379 FatLookupLastMcbEntry (
398 Results
= FsRtlLookupLastLargeMcbEntryAndIndex( Mcb
,
403 *Vbo
= ((VBO
) LiVbo
) << MCB_SCALE_LOG2
;
405 if (((ULONG
) LiLbo
) != -1) {
407 *Lbo
= ((LBO
) LiLbo
) << MCB_SCALE_LOG2
;
409 *Lbo
+= (MCB_SCALE
- 1);
410 *Vbo
+= (MCB_SCALE
- 1);
432 OUT PULONG SectorCount
439 LONGLONG LiSectorCount
;
445 Results
= FsRtlGetNextLargeMcbEntry( Mcb
,
453 *Vbo
= ((VBO
) LiVbo
) << MCB_SCALE_LOG2
;
455 if (((ULONG
) LiLbo
) != -1) {
457 *Lbo
= ((LBO
) LiLbo
) << MCB_SCALE_LOG2
;
464 *SectorCount
= ((ULONG
) LiSectorCount
) << MCB_SCALE_LOG2
;
466 if ((*SectorCount
== 0) && (LiSectorCount
!= 0)) {
467 *SectorCount
= (ULONG
) -1; /* it overflowed */
484 if ((SectorCount
) && (SectorCount
!= 0xFFFFFFFF)) {
487 SectorCount
>>= MCB_SCALE_LOG2
;
491 Vbo
>>= MCB_SCALE_LOG2
;
497 FsRtlRemoveLargeMcbEntry( Mcb
,
499 (LONGLONG
) SectorCount
);
502 } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) {
513 FatFsdFileSystemControl (
514 IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
522 This routine implements the FSD part of FileSystem control operations
526 VolumeDeviceObject - Supplies the volume device object where the
529 Irp - Supplies the Irp being processed
533 NTSTATUS - The FSD status for the IRP
540 PIRP_CONTEXT IrpContext
= NULL
;
544 DebugTrace(+1, Dbg
,"FatFsdFileSystemControl\n", 0);
547 // Call the common FileSystem Control routine, with blocking allowed if
548 // synchronous. This opeation needs to special case the mount
549 // and verify suboperations because we know they are allowed to block.
550 // We identify these suboperations by looking at the file object field
551 // and seeing if its null.
554 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
== NULL
) {
560 Wait
= CanFsdWait( Irp
);
563 FsRtlEnterFileSystem();
565 TopLevel
= FatIsIrpTopLevel( Irp
);
569 PIO_STACK_LOCATION IrpSp
;
571 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
574 // We need to made a special check here for the InvalidateVolumes
575 // FSCTL as that comes in with a FileSystem device object instead
576 // of a volume device object.
579 if (FatDeviceIsFatFsdo( IrpSp
->DeviceObject
) &&
580 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
581 (IrpSp
->MinorFunction
== IRP_MN_USER_FS_REQUEST
) &&
582 (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
==
583 FSCTL_INVALIDATE_VOLUMES
)) {
585 Status
= FatInvalidateVolumes( Irp
);
589 IrpContext
= FatCreateIrpContext( Irp
, Wait
);
591 Status
= FatCommonFileSystemControl( IrpContext
, Irp
);
594 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
597 // We had some trouble trying to perform the requested
598 // operation, so we'll abort the I/O request with
599 // the error status that we get back from the
603 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
606 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
608 FsRtlExitFileSystem();
611 // And return to our caller
614 DebugTrace(-1, Dbg
, "FatFsdFileSystemControl -> %08lx\n", Status
);
621 FatCommonFileSystemControl (
622 IN PIRP_CONTEXT IrpContext
,
630 This is the common routine for doing FileSystem control operations called
631 by both the fsd and fsp threads
635 Irp - Supplies the Irp to process
639 NTSTATUS - The return status for the operation
645 PIO_STACK_LOCATION IrpSp
;
648 // Get a pointer to the current Irp stack location
651 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
653 DebugTrace(+1, Dbg
,"FatCommonFileSystemControl\n", 0);
654 DebugTrace( 0, Dbg
,"Irp = %08lx\n", Irp
);
655 DebugTrace( 0, Dbg
,"MinorFunction = %08lx\n", IrpSp
->MinorFunction
);
658 // We know this is a file system control so we'll case on the
659 // minor function, and call a internal worker routine to complete
663 switch (IrpSp
->MinorFunction
) {
665 case IRP_MN_USER_FS_REQUEST
:
667 Status
= FatUserFsCtrl( IrpContext
, Irp
);
670 case IRP_MN_MOUNT_VOLUME
:
672 Status
= FatMountVolume( IrpContext
,
673 IrpSp
->Parameters
.MountVolume
.DeviceObject
,
674 IrpSp
->Parameters
.MountVolume
.Vpb
,
675 IrpSp
->DeviceObject
);
678 // Complete the request.
680 // We do this here because FatMountVolume can be called recursively,
681 // but the Irp is only to be completed once.
683 // NOTE: I don't think this is true anymore (danlo 3/15/1999). Probably
684 // an artifact of the old doublespace attempt.
687 FatCompleteRequest( IrpContext
, Irp
, Status
);
690 case IRP_MN_VERIFY_VOLUME
:
692 Status
= FatVerifyVolume( IrpContext
, Irp
);
697 DebugTrace( 0, Dbg
, "Invalid FS Control Minor Function %08lx\n", IrpSp
->MinorFunction
);
699 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
700 Status
= STATUS_INVALID_DEVICE_REQUEST
;
704 DebugTrace(-1, Dbg
, "FatCommonFileSystemControl -> %08lx\n", Status
);
711 // Local Support Routine
716 IN PIRP_CONTEXT IrpContext
,
717 IN PDEVICE_OBJECT TargetDeviceObject
,
719 IN PDEVICE_OBJECT FsDeviceObject
726 This routine performs the mount volume operation. It is responsible for
727 either completing of enqueuing the input Irp.
729 Its job is to verify that the volume denoted in the IRP is a Fat volume,
730 and create the VCB and root DCB structures. The algorithm it uses is
731 essentially as follows:
733 1. Create a new Vcb Structure, and initialize it enough to do cached
736 2. Read the disk and check if it is a Fat volume.
738 3. If it is not a Fat volume then free the cached volume file, delete
739 the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME
741 4. Check if the volume was previously mounted and if it was then do a
742 remount operation. This involves reinitializing the cached volume
743 file, checking the dirty bit, resetting up the allocation support,
744 deleting the VCB, hooking in the old VCB, and completing the IRP.
746 5. Otherwise create a root DCB, create Fsp threads as necessary, and
751 TargetDeviceObject - This is where we send all of our requests.
753 Vpb - This gives us additional information needed to complete the mount.
757 NTSTATUS - The return status for the operation
762 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( IrpContext
->OriginatingIrp
);
766 PPACKED_BOOT_SECTOR BootSector
;
772 BOOLEAN MountNewVolume
= FALSE
;
773 BOOLEAN WeClearedVerifyRequiredBit
= FALSE
;
774 BOOLEAN DoARemount
= FALSE
;
779 PDEVICE_OBJECT RealDevice
;
780 PVOLUME_DEVICE_OBJECT VolDo
= NULL
;
782 PFILE_OBJECT RootDirectoryFile
= NULL
;
786 IO_STATUS_BLOCK Iosb
;
787 ULONG ChangeCount
= 0;
789 DISK_GEOMETRY Geometry
;
791 PARTITION_INFORMATION_EX PartitionInformation
;
792 NTSTATUS StatusPartInfo
;
794 DebugTrace(+1, Dbg
, "FatMountVolume\n", 0);
795 DebugTrace( 0, Dbg
, "TargetDeviceObject = %08lx\n", TargetDeviceObject
);
796 DebugTrace( 0, Dbg
, "Vpb = %08lx\n", Vpb
);
798 ASSERT( FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) );
799 ASSERT( FatDeviceIsFatFsdo( FsDeviceObject
));
802 // Verify that there is a disk here and pick up the change count.
805 Status
= FatPerformDevIoCtrl( IrpContext
,
806 IOCTL_DISK_CHECK_VERIFY
,
814 if (!NT_SUCCESS( Status
)) {
817 // If we will allow a raw mount then avoid sending the popup.
819 // Only send this on "true" disk devices to handle the accidental
820 // legacy of FAT. No other FS will throw a harderror on empty
823 // Cmd should really handle this per 9x.
826 if (!FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
) &&
827 Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_DISK
) {
829 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
835 if (Iosb
.Information
!= sizeof(ULONG
)) {
838 // Be safe about the count in case the driver didn't fill it in
845 // If this is a CD class device, then check to see if there is a
846 // 'data track' or not. This is to avoid issuing paging reads which will
847 // fail later in the mount process (e.g. CD-DA or blank CD media)
850 if ((TargetDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) &&
851 !FatScanForDataTrack( IrpContext
, TargetDeviceObject
)) {
853 return STATUS_UNRECOGNIZED_VOLUME
;
857 // Ping the volume with a partition query and pick up the partition
858 // type. We'll check this later to avoid some scurrilous volumes.
861 StatusPartInfo
= FatPerformDevIoCtrl( IrpContext
,
862 IOCTL_DISK_GET_PARTITION_INFO_EX
,
864 &PartitionInformation
,
865 sizeof(PARTITION_INFORMATION_EX
),
871 // Make sure we can wait.
874 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
877 // Do a quick check to see if there any Vcb's which can be removed.
880 FatScanForDismountedVcb( IrpContext
);
883 // Initialize the Bcbs and our final state so that the termination
884 // handlers will know what to free or unpin
892 MountNewVolume
= FALSE
;
897 // Synchronize with FatCheckForDismount(), which modifies the vpb.
900 (VOID
)FatAcquireExclusiveGlobal( IrpContext
);
903 // Create a new volume device object. This will have the Vcb
904 // hanging off of its end, and set its alignment requirement
905 // from the device we talk to.
908 if (!NT_SUCCESS(Status
= IoCreateDevice( FatData
.DriverObject
,
909 sizeof(VOLUME_DEVICE_OBJECT
) - sizeof(DEVICE_OBJECT
),
911 FILE_DEVICE_DISK_FILE_SYSTEM
,
914 (PDEVICE_OBJECT
*)&VolDo
))) {
916 try_return( Status
);
921 // This driver doesn't talk directly to a device, and (at the moment)
922 // isn't otherwise concerned about power management.
925 VolDo
->DeviceObject
.DeviceObjectExtension
->PowerControlNeeded
= FALSE
;
929 // Our alignment requirement is the larger of the processor alignment requirement
930 // already in the volume device object and that in the TargetDeviceObject
933 if (TargetDeviceObject
->AlignmentRequirement
> VolDo
->DeviceObject
.AlignmentRequirement
) {
935 VolDo
->DeviceObject
.AlignmentRequirement
= TargetDeviceObject
->AlignmentRequirement
;
939 // Initialize the overflow queue for the volume
942 VolDo
->OverflowQueueCount
= 0;
943 InitializeListHead( &VolDo
->OverflowQueue
);
945 VolDo
->PostedRequestCount
= 0;
946 KeInitializeSpinLock( &VolDo
->OverflowQueueSpinLock
);
949 // We must initialize the stack size in our device object before
950 // the following reads, because the I/O system has not done it yet.
951 // This must be done before we clear the device initializing flag
952 // otherwise a filter could attach and copy the wrong stack size into
953 // it's device object.
956 VolDo
->DeviceObject
.StackSize
= (CCHAR
)(TargetDeviceObject
->StackSize
+ 1);
959 // We must also set the sector size correctly in our device object
960 // before clearing the device initializing flag.
963 Status
= FatPerformDevIoCtrl( IrpContext
,
964 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
967 sizeof( DISK_GEOMETRY
),
972 VolDo
->DeviceObject
.SectorSize
= (USHORT
)Geometry
.BytesPerSector
;
975 // Indicate that this device object is now completely initialized
978 ClearFlag(VolDo
->DeviceObject
.Flags
, DO_DEVICE_INITIALIZING
);
981 // Now Before we can initialize the Vcb we need to set up the device
982 // object field in the Vpb to point to our new volume device object.
983 // This is needed when we create the virtual volume file's file object
984 // in initialize vcb.
987 Vpb
->DeviceObject
= (PDEVICE_OBJECT
)VolDo
;
990 // If the real device needs verification, temporarily clear the
994 RealDevice
= Vpb
->RealDevice
;
996 if ( FlagOn(RealDevice
->Flags
, DO_VERIFY_VOLUME
) ) {
998 ClearFlag(RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1000 WeClearedVerifyRequiredBit
= TRUE
;
1004 // Initialize the new vcb
1007 FatInitializeVcb( IrpContext
,
1013 // Get a reference to the Vcb hanging off the end of the device object
1019 // Read in the boot sector, and have the read be the minumum size
1020 // needed. We know we can wait.
1024 // We need to commute errors on CD so that CDFS will get its crack. Audio
1025 // and even data media may not be universally readable on sector zero.
1030 FatReadVolumeFile( IrpContext
,
1033 sizeof(PACKED_BOOT_SECTOR
),
1035 (PVOID
*)&BootSector
);
1037 } _SEH2_EXCEPT( Vpb
->RealDevice
->DeviceType
== FILE_DEVICE_CD_ROM
?
1038 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
1044 // Call a routine to check the boot sector to see if it is fat
1047 if (BootBcb
== NULL
|| !FatIsBootSectorFat( BootSector
)) {
1049 DebugTrace(0, Dbg
, "Not a Fat Volume\n", 0);
1052 // Complete the request and return to our caller
1055 try_return( Status
= STATUS_UNRECOGNIZED_VOLUME
);
1059 // Unpack the BPB. We used to do some sanity checking of the FATs at
1060 // this point, but authoring errors on third-party devices prevent
1061 // us from continuing to safeguard ourselves. We can only hope the
1062 // boot sector check is good enough.
1064 // (read: digital cameras)
1066 // Win9x does the same.
1069 FatUnpackBios( &Vcb
->Bpb
, &BootSector
->PackedBpb
);
1072 // Check if we have an OS/2 Boot Manager partition and treat it as an
1073 // unknown file system. We'll check the partition type in from the
1074 // partition table and we ensure that it has less than 0x80 sectors,
1075 // which is just a heuristic that will capture all real OS/2 BM partitions
1076 // and avoid the chance we'll discover partitions which erroneously
1077 // (but to this point, harmlessly) put down the OS/2 BM type.
1079 // Note that this is only conceivable on good old MBR media.
1081 // The OS/2 Boot Manager boot format mimics a FAT16 partition in sector
1082 // zero but does is not a real FAT16 file system. For example, the boot
1083 // sector indicates it has 2 FATs but only really has one, with the boot
1084 // manager code overlaying the second FAT. If we then set clean bits in
1085 // FAT[0] we'll corrupt that code.
1088 if (NT_SUCCESS( StatusPartInfo
) &&
1089 (PartitionInformation
.PartitionStyle
== PARTITION_STYLE_MBR
&&
1090 PartitionInformation
.Mbr
.PartitionType
== PARTITION_OS2BOOTMGR
) &&
1091 (Vcb
->Bpb
.Sectors
!= 0 &&
1092 Vcb
->Bpb
.Sectors
< 0x80)) {
1094 DebugTrace( 0, Dbg
, "OS/2 Boot Manager volume detected, volume not mounted. \n", 0 );
1097 // Complete the request and return to our caller
1100 try_return( Status
= STATUS_UNRECOGNIZED_VOLUME
);
1104 // Verify that the sector size recorded in the Bpb matches what the
1105 // device currently reports it's sector size to be.
1108 if ( !NT_SUCCESS( Status
) ||
1109 (Geometry
.BytesPerSector
!= Vcb
->Bpb
.BytesPerSector
)) {
1111 try_return( Status
= STATUS_UNRECOGNIZED_VOLUME
);
1115 // This is a fat volume, so extract the bpb, serial number. The
1116 // label we'll get later after we've created the root dcb.
1118 // Note that the way data caching is done, we set neither the
1119 // direct I/O or Buffered I/O bit in the device object flags.
1122 if (Vcb
->Bpb
.Sectors
!= 0) { Vcb
->Bpb
.LargeSectors
= 0; }
1124 if (IsBpbFat32(&BootSector
->PackedBpb
)) {
1126 CopyUchar4( &Vpb
->SerialNumber
, ((PPACKED_BOOT_SECTOR_EX
)BootSector
)->Id
);
1130 CopyUchar4( &Vpb
->SerialNumber
, BootSector
->Id
);
1133 // Allocate space for the stashed boot sector chunk. This only has meaning on
1134 // FAT12/16 volumes since this only is kept for the FSCTL_QUERY_FAT_BPB and it and
1135 // its users are a bit wierd, thinking that a BPB exists wholly in the first 0x24
1139 Vcb
->First0x24BytesOfBootSector
=
1140 FsRtlAllocatePoolWithTag( PagedPool
,
1145 // Stash a copy of the first 0x24 bytes
1148 RtlCopyMemory( Vcb
->First0x24BytesOfBootSector
,
1154 // Now unpin the boot sector, so when we set up allocation eveything
1158 FatUnpinBcb( IrpContext
, BootBcb
);
1161 // Compute a number of fields for Vcb.AllocationSupport
1164 FatSetupAllocationSupport( IrpContext
, Vcb
);
1167 // Sanity check the FsInfo information for FAT32 volumes. Silently deal
1168 // with messed up information by effectively disabling FsInfo updates.
1171 if (FatIsFat32( Vcb
)) {
1173 if (Vcb
->Bpb
.FsInfoSector
>= Vcb
->Bpb
.ReservedSectors
) {
1175 Vcb
->Bpb
.FsInfoSector
= 0;
1180 // Create a root Dcb so we can read in the volume label. If this is FAT32, we can
1181 // discover corruption in the FAT chain.
1183 // NOTE: this exception handler presumes that this is the only spot where we can
1184 // discover corruption in the mount process. If this ever changes, this handler
1185 // MUST be expanded. The reason we have this guy here is because we have to rip
1186 // the structures down now (in the finally below) and can't wait for the outer
1187 // exception handling to do it for us, at which point everything will have vanished.
1192 FatCreateRootDcb( IrpContext
, Vcb
);
1194 } _SEH2_EXCEPT (_SEH2_GetExceptionCode() == STATUS_FILE_CORRUPT_ERROR
? EXCEPTION_EXECUTE_HANDLER
:
1195 EXCEPTION_CONTINUE_SEARCH
) {
1198 // The volume needs to be dirtied, do it now. Note that at this point we have built
1199 // enough of the Vcb to pull this off.
1202 FatMarkVolume( IrpContext
, Vcb
, VolumeDirty
);
1205 // Now keep bailing out ...
1208 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1211 FatLocateVolumeLabel( IrpContext
,
1218 (PVBO
)&ByteOffset
);
1221 if (Dirent
!= NULL
) {
1223 OEM_STRING OemString
;
1224 UNICODE_STRING UnicodeString
;
1227 // Compute the length of the volume name
1231 OemString
.Buffer
= &Dirent
->FileName
[0];
1233 OemString
.Buffer
= (PCHAR
)&Dirent
->FileName
[0];
1235 OemString
.MaximumLength
= 11;
1237 for ( OemString
.Length
= 11;
1238 OemString
.Length
> 0;
1239 OemString
.Length
-= 1) {
1241 if ( (Dirent
->FileName
[OemString
.Length
-1] != 0x00) &&
1242 (Dirent
->FileName
[OemString
.Length
-1] != 0x20) ) { break; }
1245 UnicodeString
.MaximumLength
= MAXIMUM_VOLUME_LABEL_LENGTH
;
1246 UnicodeString
.Buffer
= &Vcb
->Vpb
->VolumeLabel
[0];
1248 Status
= RtlOemStringToCountedUnicodeString( &UnicodeString
,
1252 if ( !NT_SUCCESS( Status
) ) {
1254 try_return( Status
);
1257 Vpb
->VolumeLabelLength
= UnicodeString
.Length
;
1261 Vpb
->VolumeLabelLength
= 0;
1265 // Use the change count we noted initially *before* doing any work.
1266 // If something came along in the midst of this operation, we'll
1267 // verify and discover the problem.
1270 Vcb
->ChangeCount
= ChangeCount
;
1273 // Now scan the list of previously mounted volumes and compare
1274 // serial numbers and volume labels off not currently mounted
1275 // volumes to see if we have a match.
1278 for (Links
= FatData
.VcbQueue
.Flink
;
1279 Links
!= &FatData
.VcbQueue
;
1280 Links
= Links
->Flink
) {
1282 OldVcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
1283 OldVpb
= OldVcb
->Vpb
;
1286 // Skip over ourselves since we're already in the VcbQueue
1289 if (OldVpb
== Vpb
) { continue; }
1292 // Check for a match:
1294 // Serial Number, VolumeLabel and Bpb must all be the same.
1295 // Also the volume must have failed a verify before (ie.
1296 // VolumeNotMounted), and it must be in the same physical
1297 // drive than it was mounted in before.
1300 if ( (OldVpb
->SerialNumber
== Vpb
->SerialNumber
) &&
1301 (OldVcb
->VcbCondition
== VcbNotMounted
) &&
1302 (OldVpb
->RealDevice
== RealDevice
) &&
1303 (OldVpb
->VolumeLabelLength
== Vpb
->VolumeLabelLength
) &&
1304 (RtlEqualMemory(&OldVpb
->VolumeLabel
[0],
1305 &Vpb
->VolumeLabel
[0],
1306 Vpb
->VolumeLabelLength
)) &&
1307 (RtlEqualMemory(&OldVcb
->Bpb
,
1309 IsBpbFat32(&Vcb
->Bpb
) ?
1310 sizeof(BIOS_PARAMETER_BLOCK
) :
1311 FIELD_OFFSET(BIOS_PARAMETER_BLOCK
,
1312 LargeSectorsPerFat
) ))) {
1324 DebugTrace(0, Dbg
, "Doing a remount\n", 0);
1325 DebugTrace(0, Dbg
, "Vcb = %08lx\n", Vcb
);
1326 DebugTrace(0, Dbg
, "Vpb = %08lx\n", Vpb
);
1327 DebugTrace(0, Dbg
, "OldVcb = %08lx\n", OldVcb
);
1328 DebugTrace(0, Dbg
, "OldVpb = %08lx\n", OldVpb
);
1331 // Swap target device objects between the VCBs. That way
1332 // the old VCB will start using the new target device object,
1333 // and the new VCB will be torn down and deference the old
1334 // target device object.
1337 Vcb
->TargetDeviceObject
= OldVcb
->TargetDeviceObject
;
1338 OldVcb
->TargetDeviceObject
= TargetDeviceObject
;
1341 // This is a remount, so link the old vpb in place
1344 ASSERT( !FlagOn( OldVcb
->VcbState
, VCB_STATE_FLAG_VPB_MUST_BE_FREED
) );
1346 OldVpb
->RealDevice
= Vpb
->RealDevice
;
1347 OldVpb
->RealDevice
->Vpb
= OldVpb
;
1349 OldVcb
->VcbCondition
= VcbGood
;
1352 // Use the new changecount.
1355 OldVcb
->ChangeCount
= Vcb
->ChangeCount
;
1358 // If the new VPB is the VPB referenced in the original Irp, set
1359 // that reference back to the old VPB.
1362 IrpVpb
= &IoGetCurrentIrpStackLocation(IrpContext
->OriginatingIrp
)->Parameters
.MountVolume
.Vpb
;
1364 if (*IrpVpb
== Vpb
) {
1370 // We do not want to touch this VPB again. It will get cleaned up when
1371 // the new VCB is cleaned up.
1374 ASSERT( Vcb
->Vpb
== Vpb
);
1378 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VPB_MUST_BE_FREED
);
1379 FatSetVcbCondition( Vcb
, VcbBad
);
1382 // Reinitialize the volume file cache and allocation support.
1386 CC_FILE_SIZES FileSizes
;
1388 FileSizes
.AllocationSize
.QuadPart
=
1389 FileSizes
.FileSize
.QuadPart
= ( 0x40000 + 0x1000 );
1390 FileSizes
.ValidDataLength
= FatMaxLarge
;
1392 DebugTrace(0, Dbg
, "Truncate and reinitialize the volume file\n", 0);
1394 CcInitializeCacheMap( OldVcb
->VirtualVolumeFile
,
1397 &FatData
.CacheManagerNoOpCallbacks
,
1401 // Redo the allocation support
1404 FatSetupAllocationSupport( IrpContext
, OldVcb
);
1407 // Get the state of the dirty bit.
1410 FatCheckDirtyBit( IrpContext
, OldVcb
);
1413 // Check for write protected media.
1416 if (FatIsMediaWriteProtected(IrpContext
, TargetDeviceObject
)) {
1418 SetFlag( OldVcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
1422 ClearFlag( OldVcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
1427 // Complete the request and return to our caller
1430 try_return( Status
= STATUS_SUCCESS
);
1433 DebugTrace(0, Dbg
, "Mount a new volume\n", 0);
1436 // This is a new mount
1438 // Create a blank ea data file fcb, just not for Fat32.
1441 if (!FatIsFat32(Vcb
)) {
1446 RtlZeroMemory( &TempDirent
, sizeof(DIRENT
) );
1447 RtlCopyMemory( &TempDirent
.FileName
[0], "EA DATA SF", 11 );
1449 EaFcb
= FatCreateFcb( IrpContext
,
1460 // Deny anybody who trys to open the file.
1463 SetFlag( EaFcb
->FcbState
, FCB_STATE_SYSTEM_FILE
);
1469 // Get the state of the dirty bit.
1472 FatCheckDirtyBit( IrpContext
, Vcb
);
1475 // Check for write protected media.
1478 if (FatIsMediaWriteProtected(IrpContext
, TargetDeviceObject
)) {
1480 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
1484 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
1488 // Lock volume in drive if we just mounted the boot drive.
1491 if (FlagOn(RealDevice
->Flags
, DO_SYSTEM_BOOT_PARTITION
)) {
1493 SetFlag(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
);
1495 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
)) {
1497 FatToggleMediaEjectDisable( IrpContext
, Vcb
, TRUE
);
1502 // Indicate to our termination handler that we have mounted
1506 MountNewVolume
= TRUE
;
1509 // Complete the request
1512 Status
= STATUS_SUCCESS
;
1515 // Ref the root dir stream object so we can send mount notification.
1518 RootDirectoryFile
= Vcb
->RootDcb
->Specific
.Dcb
.DirectoryFile
;
1519 ObReferenceObject( RootDirectoryFile
);
1522 // Remove the extra reference to this target DO made on behalf of us
1523 // by the IO system. In the remount case, we permit regular Vcb
1524 // deletion to do this work.
1527 ObDereferenceObject( TargetDeviceObject
);
1534 DebugUnwind( FatMountVolume
);
1536 FatUnpinBcb( IrpContext
, BootBcb
);
1537 FatUnpinBcb( IrpContext
, DirentBcb
);
1540 // Check if a volume was mounted. If not then we need to
1541 // mark the Vpb not mounted again.
1544 if ( !MountNewVolume
) {
1546 if ( Vcb
!= NULL
) {
1549 // A VCB was created and initialized. we need to try to tear it down.
1552 FatCheckForDismount( IrpContext
,
1556 IrpContext
->Vcb
= NULL
;
1557 } else if ( VolDo
!= NULL
) {
1559 // The VCB was never initialized, so we need to delete the
1560 // device right here.
1563 IoDeleteDevice( &VolDo
->DeviceObject
);
1567 // see if a remount failed.
1570 if (DoARemount
&& _SEH2_AbnormalTermination()) {
1573 // The remount failed. Try to tear down the old VCB as well.
1576 FatCheckForDismount( IrpContext
,
1582 if ( WeClearedVerifyRequiredBit
== TRUE
) {
1584 SetFlag(RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1587 FatReleaseGlobal( IrpContext
);
1589 DebugTrace(-1, Dbg
, "FatMountVolume -> %08lx\n", Status
);
1593 // Now send mount notification. Note that since this is outside of any
1594 // synchronization since the synchronous delivery of this may go to
1595 // folks that provoke re-entrance to the FS.
1598 if (RootDirectoryFile
!= NULL
) {
1600 FsRtlNotifyVolumeEvent( RootDirectoryFile
, FSRTL_VOLUME_MOUNT
);
1601 ObDereferenceObject( RootDirectoryFile
);
1609 // Local Support Routine
1614 IN PIRP_CONTEXT IrpContext
,
1620 Routine Description:
1622 This routine performs the verify volume operation by checking the volume
1623 label and serial number physically on the media with the the Vcb
1624 currently claiming to have the volume mounted. It is responsible for
1625 either completing or enqueuing the input Irp.
1627 Regardless of whether the verify operation succeeds, the following
1628 operations are performed:
1630 - Set Vcb->VirtualEaFile back to its virgin state.
1631 - Purge all cached data (flushing first if verify succeeds)
1632 - Mark all Fcbs as needing verification
1634 If the volumes verifies correctly we also must:
1636 - Check the volume dirty bit.
1637 - Reinitialize the allocation support
1638 - Flush any dirty data
1640 If the volume verify fails, it may never be mounted again. If it is
1641 mounted again, it will happen as a remount operation. In preparation
1642 for that, and to leave the volume in a state that can be "lazy deleted"
1643 the following operations are performed:
1645 - Set the Vcb condition to VcbNotMounted
1646 - Uninitialize the volume file cachemap
1647 - Tear down the allocation support
1649 In the case of an abnormal termination we haven't determined the state
1650 of the volume, so we set the Device Object as needing verification again.
1654 Irp - Supplies the Irp to process
1658 NTSTATUS - If the verify operation completes, it will return either
1659 STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. If an IO or
1660 other error is encountered, that status will be returned.
1665 NTSTATUS Status
= STATUS_SUCCESS
;
1667 PIO_STACK_LOCATION IrpSp
;
1669 PDIRENT RootDirectory
= NULL
;
1670 PPACKED_BOOT_SECTOR BootSector
= NULL
;
1672 BIOS_PARAMETER_BLOCK Bpb
;
1674 PVOLUME_DEVICE_OBJECT VolDo
;
1679 BOOLEAN ClearVerify
= FALSE
;
1680 BOOLEAN ReleaseEntireVolume
= FALSE
;
1681 BOOLEAN VerifyAlreadyDone
= FALSE
;
1683 DISK_GEOMETRY DiskGeometry
;
1685 LBO RootDirectoryLbo
;
1686 ULONG RootDirectorySize
;
1689 ULONG ChangeCount
= 0;
1690 IO_STATUS_BLOCK Iosb
;
1693 // Get the current Irp stack location
1696 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1698 DebugTrace(+1, Dbg
, "FatVerifyVolume\n", 0);
1699 DebugTrace( 0, Dbg
, "DeviceObject = %08lx\n", IrpSp
->Parameters
.VerifyVolume
.DeviceObject
);
1700 DebugTrace( 0, Dbg
, "Vpb = %08lx\n", IrpSp
->Parameters
.VerifyVolume
.Vpb
);
1703 // Save some references to make our life a little easier. Note the Vcb for the purposes
1704 // of exception handling.
1707 VolDo
= (PVOLUME_DEVICE_OBJECT
)IrpSp
->Parameters
.VerifyVolume
.DeviceObject
;
1709 Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
1710 IrpContext
->Vcb
= Vcb
= &VolDo
->Vcb
;
1713 // If we cannot wait then enqueue the irp to the fsp and
1714 // return the status to our caller.
1717 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
1719 DebugTrace(0, Dbg
, "Cannot wait for verify.\n", 0);
1721 Status
= FatFsdPostRequest( IrpContext
, Irp
);
1723 DebugTrace(-1, Dbg
, "FatVerifyVolume -> %08lx\n", Status
);
1728 // We are serialized at this point allowing only one thread to
1729 // actually perform the verify operation. Any others will just
1730 // wait and then no-op when checking if the volume still needs
1734 (VOID
)FatAcquireExclusiveGlobal( IrpContext
);
1735 (VOID
)FatAcquireExclusiveVcb( IrpContext
, Vcb
);
1739 BOOLEAN AllowRawMount
= BooleanFlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
);
1742 // Mark ourselves as verifying this volume so that recursive I/Os
1743 // will be able to complete.
1746 ASSERT( Vcb
->VerifyThread
== NULL
);
1747 Vcb
->VerifyThread
= KeGetCurrentThread();
1750 // Check if the real device still needs to be verified. If it doesn't
1751 // then obviously someone beat us here and already did the work
1752 // so complete the verify irp with success. Otherwise reenable
1753 // the real device and get to work.
1756 if (!FlagOn(Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
)) {
1758 DebugTrace(0, Dbg
, "RealDevice has already been verified\n", 0);
1760 VerifyAlreadyDone
= TRUE
;
1761 try_return( Status
= STATUS_SUCCESS
);
1765 // Ping the volume with a partition query to make Jeff happy.
1769 PARTITION_INFORMATION_EX PartitionInformation
;
1771 (VOID
) FatPerformDevIoCtrl( IrpContext
,
1772 IOCTL_DISK_GET_PARTITION_INFO_EX
,
1773 Vcb
->TargetDeviceObject
,
1774 &PartitionInformation
,
1775 sizeof(PARTITION_INFORMATION_EX
),
1782 // Verify that there is a disk here and pick up the change count.
1785 Status
= FatPerformDevIoCtrl( IrpContext
,
1786 IOCTL_DISK_CHECK_VERIFY
,
1787 Vcb
->TargetDeviceObject
,
1794 if (!NT_SUCCESS( Status
)) {
1797 // If we will allow a raw mount then return WRONG_VOLUME to
1798 // allow the volume to be mounted by raw.
1801 if (AllowRawMount
) {
1803 try_return( Status
= STATUS_WRONG_VOLUME
);
1806 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
1809 if (Iosb
.Information
!= sizeof(ULONG
)) {
1812 // Be safe about the count in case the driver didn't fill it in
1819 // Whatever happens we will have verified this volume at this change
1820 // count, so record that fact.
1823 Vcb
->ChangeCount
= ChangeCount
;
1826 // If this is a CD class device, then check to see if there is a
1827 // 'data track' or not. This is to avoid issuing paging reads which will
1828 // fail later in the mount process (e.g. CD-DA or blank CD media)
1831 if ((Vcb
->TargetDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) &&
1832 !FatScanForDataTrack( IrpContext
, Vcb
->TargetDeviceObject
)) {
1834 try_return( Status
= STATUS_WRONG_VOLUME
);
1838 // Some devices can change sector sizes on the fly. Obviously, it
1839 // isn't the same volume if that happens.
1842 Status
= FatPerformDevIoCtrl( IrpContext
,
1843 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1844 Vcb
->TargetDeviceObject
,
1846 sizeof( DISK_GEOMETRY
),
1851 if (!NT_SUCCESS( Status
)) {
1854 // If we will allow a raw mount then return WRONG_VOLUME to
1855 // allow the volume to be mounted by raw.
1858 if (AllowRawMount
) {
1860 try_return( Status
= STATUS_WRONG_VOLUME
);
1863 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
1867 // Read in the boot sector
1870 SectorSize
= (ULONG
)Vcb
->Bpb
.BytesPerSector
;
1872 if (SectorSize
!= DiskGeometry
.BytesPerSector
) {
1874 try_return( Status
= STATUS_WRONG_VOLUME
);
1877 BootSector
= FsRtlAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1878 (ULONG
) ROUND_TO_PAGES( SectorSize
),
1879 TAG_VERIFY_BOOTSECTOR
);
1882 // If this verify is on behalf of a DASD open, allow a RAW mount.
1885 if (!FatPerformVerifyDiskRead( IrpContext
,
1892 try_return( Status
= STATUS_WRONG_VOLUME
);
1896 // Call a routine to check the boot sector to see if it is fat.
1897 // If it is not fat then mark the vcb as not mounted tell our
1898 // caller its the wrong volume
1901 if (!FatIsBootSectorFat( BootSector
)) {
1903 DebugTrace(0, Dbg
, "Not a Fat Volume\n", 0);
1905 try_return( Status
= STATUS_WRONG_VOLUME
);
1909 // This is a fat volume, so extract serial number and see if it is
1916 if (IsBpbFat32(&BootSector
->PackedBpb
)) {
1917 CopyUchar4( &SerialNumber
, ((PPACKED_BOOT_SECTOR_EX
)BootSector
)->Id
);
1919 CopyUchar4( &SerialNumber
, BootSector
->Id
);
1922 if (SerialNumber
!= Vpb
->SerialNumber
) {
1924 DebugTrace(0, Dbg
, "Not our serial number\n", 0);
1926 try_return( Status
= STATUS_WRONG_VOLUME
);
1931 // Make sure the Bpbs are not different. We have to zero out our
1932 // stack version of the Bpb since unpacking leaves holes.
1935 RtlZeroMemory( &Bpb
, sizeof(BIOS_PARAMETER_BLOCK
) );
1937 FatUnpackBios( &Bpb
, &BootSector
->PackedBpb
);
1938 if (Bpb
.Sectors
!= 0) { Bpb
.LargeSectors
= 0; }
1940 if ( !RtlEqualMemory( &Bpb
,
1943 sizeof(BIOS_PARAMETER_BLOCK
) :
1944 FIELD_OFFSET(BIOS_PARAMETER_BLOCK
,
1945 LargeSectorsPerFat
) )) {
1947 DebugTrace(0, Dbg
, "Bpb is different\n", 0);
1949 try_return( Status
= STATUS_WRONG_VOLUME
);
1953 // Check the volume label. We do this by trying to locate the
1954 // volume label, making two strings one for the saved volume label
1955 // and the other for the new volume label and then we compare the
1959 if (FatRootDirectorySize(&Bpb
) > 0) {
1961 RootDirectorySize
= FatRootDirectorySize(&Bpb
);
1965 RootDirectorySize
= FatBytesPerCluster(&Bpb
);
1968 RootDirectory
= FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned
,
1969 (ULONG
) ROUND_TO_PAGES( RootDirectorySize
),
1970 TAG_VERIFY_ROOTDIR
);
1972 if (!IsBpbFat32(&BootSector
->PackedBpb
)) {
1975 // The Fat12/16 case is simple -- read the root directory in and
1979 RootDirectoryLbo
= FatRootDirectoryLbo(&Bpb
);
1981 if (!FatPerformVerifyDiskRead( IrpContext
,
1988 try_return( Status
= STATUS_WRONG_VOLUME
);
1991 Status
= FatSearchBufferForLabel(IrpContext
, Vpb
,
1992 RootDirectory
, RootDirectorySize
,
1995 if (!NT_SUCCESS(Status
)) {
1997 try_return( Status
);
2000 if (!LabelFound
&& Vpb
->VolumeLabelLength
> 0) {
2002 try_return( Status
= STATUS_WRONG_VOLUME
);
2007 ULONG RootDirectoryCluster
;
2009 RootDirectoryCluster
= Bpb
.RootDirFirstCluster
;
2011 while (RootDirectoryCluster
!= FAT_CLUSTER_LAST
) {
2013 RootDirectoryLbo
= FatGetLboFromIndex(Vcb
, RootDirectoryCluster
);
2015 if (!FatPerformVerifyDiskRead( IrpContext
,
2022 try_return( Status
= STATUS_WRONG_VOLUME
);
2025 Status
= FatSearchBufferForLabel(IrpContext
, Vpb
,
2026 RootDirectory
, RootDirectorySize
,
2029 if (!NT_SUCCESS(Status
)) {
2031 try_return( Status
);
2037 // Found a matching label.
2044 // Set ourselves up for the next loop iteration.
2047 FatVerifyLookupFatEntry( IrpContext
, Vcb
,
2048 RootDirectoryCluster
,
2049 &RootDirectoryCluster
);
2051 switch (FatInterpretClusterType(Vcb
, RootDirectoryCluster
)) {
2053 case FatClusterAvailable
:
2054 case FatClusterReserved
:
2058 // Bail all the way out if we have a bad root.
2061 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
2071 if (RootDirectoryCluster
== FAT_CLUSTER_LAST
&&
2072 Vpb
->VolumeLabelLength
> 0) {
2075 // Should have found a label, didn't find any.
2078 try_return( Status
= STATUS_WRONG_VOLUME
);
2086 // Note that we have previously acquired the Vcb to serialize
2087 // the EA file stuff the marking all the Fcbs as NeedToBeVerified.
2089 // Put the Ea file back in a virgin state.
2092 FatCloseEaFile( IrpContext
, Vcb
, (BOOLEAN
)(Status
== STATUS_SUCCESS
) );
2095 // Mark all Fcbs as needing verification, but only if we really have
2099 if (!VerifyAlreadyDone
) {
2101 FatMarkFcbCondition( IrpContext
, Vcb
->RootDcb
, FcbNeedsToBeVerified
, TRUE
);
2105 // If the verify didn't succeed, get the volume ready for a
2106 // remount or eventual deletion.
2109 if (Vcb
->VcbCondition
== VcbNotMounted
) {
2112 // If the volume was already in an unmounted state, just bail
2113 // and make sure we return STATUS_WRONG_VOLUME.
2116 Status
= STATUS_WRONG_VOLUME
;
2118 } else if ( Status
== STATUS_WRONG_VOLUME
) {
2121 // Grab everything so we can safely transition the volume state without
2122 // having a thread stumble into the torn-down allocation engine.
2125 FatAcquireExclusiveVolume( IrpContext
, Vcb
);
2126 ReleaseEntireVolume
= TRUE
;
2129 // Get rid of any cached data, without flushing
2132 FatPurgeReferencedFileObjects( IrpContext
, Vcb
->RootDcb
, NoFlush
);
2135 // Uninitialize the volume file cache map. Note that we cannot
2136 // do a "FatSyncUninit" because of deadlock problems. However,
2137 // since this FileObject is referenced by us, and thus included
2138 // in the Vpb residual count, it is OK to do a normal CcUninit.
2141 CcUninitializeCacheMap( Vcb
->VirtualVolumeFile
,
2145 FatTearDownAllocationSupport( IrpContext
, Vcb
);
2147 Vcb
->VcbCondition
= VcbNotMounted
;
2151 } else if (!VerifyAlreadyDone
) {
2154 // Grab everything so we can safely transition the volume state without
2155 // having a thread stumble into the torn-down allocation engine.
2158 FatAcquireExclusiveVolume( IrpContext
, Vcb
);
2159 ReleaseEntireVolume
= TRUE
;
2162 // Get rid of any cached data, flushing first.
2164 // Future work (and for bonus points, around the other flush points)
2165 // could address the possibility that the dirent filesize hasn't been
2166 // updated yet, causing us to fail the re-verification of a file in
2167 // DetermineAndMark. This is pretty subtle and very very uncommon.
2170 FatPurgeReferencedFileObjects( IrpContext
, Vcb
->RootDcb
, Flush
);
2173 // Flush and Purge the volume file.
2176 (VOID
)FatFlushFat( IrpContext
, Vcb
);
2177 CcPurgeCacheSection( &Vcb
->SectionObjectPointers
, NULL
, 0, FALSE
);
2180 // Redo the allocation support with newly paged stuff.
2183 FatTearDownAllocationSupport( IrpContext
, Vcb
);
2184 FatSetupAllocationSupport( IrpContext
, Vcb
);
2186 FatCheckDirtyBit( IrpContext
, Vcb
);
2189 // Check for write protected media.
2192 if (FatIsMediaWriteProtected(IrpContext
, Vcb
->TargetDeviceObject
)) {
2194 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
2198 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
);
2207 // Mark the device as no longer needing verification.
2210 ClearFlag( Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
2215 DebugUnwind( FatVerifyVolume
);
2218 // Free any buffer we may have allocated
2221 if ( BootSector
!= NULL
) { ExFreePool( BootSector
); }
2222 if ( RootDirectory
!= NULL
) { ExFreePool( RootDirectory
); }
2225 // Show that we are done with this volume.
2228 ASSERT( Vcb
->VerifyThread
== KeGetCurrentThread() );
2229 Vcb
->VerifyThread
= NULL
;
2231 if (ReleaseEntireVolume
) {
2233 FatReleaseVolume( IrpContext
, Vcb
);
2236 FatReleaseVcb( IrpContext
, Vcb
);
2237 FatReleaseGlobal( IrpContext
);
2240 // If this was not an abnormal termination, complete the irp.
2243 if (!_SEH2_AbnormalTermination()) {
2245 FatCompleteRequest( IrpContext
, Irp
, Status
);
2248 DebugTrace(-1, Dbg
, "FatVerifyVolume -> %08lx\n", Status
);
2256 // Local Support Routine
2260 FatIsBootSectorFat (
2261 IN PPACKED_BOOT_SECTOR BootSector
2266 Routine Description:
2268 This routine checks if the boot sector is for a fat file volume.
2272 BootSector - Supplies the packed boot sector to check
2276 BOOLEAN - TRUE if the volume is Fat and FALSE otherwise.
2282 BIOS_PARAMETER_BLOCK Bpb
;
2284 DebugTrace(+1, Dbg
, "FatIsBootSectorFat, BootSector = %08lx\n", BootSector
);
2287 // The result is true unless we decide that it should be false
2293 // Unpack the bios and then test everything
2296 FatUnpackBios( &Bpb
, &BootSector
->PackedBpb
);
2297 if (Bpb
.Sectors
!= 0) { Bpb
.LargeSectors
= 0; }
2299 if ((BootSector
->Jump
[0] != 0xe9) &&
2300 (BootSector
->Jump
[0] != 0xeb) &&
2301 (BootSector
->Jump
[0] != 0x49)) {
2306 // Enforce some sanity on the sector size (easy check)
2309 } else if ((Bpb
.BytesPerSector
!= 128) &&
2310 (Bpb
.BytesPerSector
!= 256) &&
2311 (Bpb
.BytesPerSector
!= 512) &&
2312 (Bpb
.BytesPerSector
!= 1024) &&
2313 (Bpb
.BytesPerSector
!= 2048) &&
2314 (Bpb
.BytesPerSector
!= 4096)) {
2319 // Likewise on the clustering.
2322 } else if ((Bpb
.SectorsPerCluster
!= 1) &&
2323 (Bpb
.SectorsPerCluster
!= 2) &&
2324 (Bpb
.SectorsPerCluster
!= 4) &&
2325 (Bpb
.SectorsPerCluster
!= 8) &&
2326 (Bpb
.SectorsPerCluster
!= 16) &&
2327 (Bpb
.SectorsPerCluster
!= 32) &&
2328 (Bpb
.SectorsPerCluster
!= 64) &&
2329 (Bpb
.SectorsPerCluster
!= 128)) {
2334 // Likewise on the reserved sectors (must reflect at least the boot sector!)
2337 } else if (Bpb
.ReservedSectors
== 0) {
2342 // No FATs? Wrong ...
2345 } else if (Bpb
.Fats
== 0) {
2350 // Prior to DOS 3.2 might contains value in both of Sectors and
2354 } else if ((Bpb
.Sectors
== 0) && (Bpb
.LargeSectors
== 0)) {
2359 // Check that FAT32 (SectorsPerFat == 0) claims some FAT space and
2360 // is of a version we recognize, currently Version 0.0.
2363 } else if (Bpb
.SectorsPerFat
== 0 && ( Bpb
.LargeSectorsPerFat
== 0 ||
2364 Bpb
.FsVersion
!= 0 )) {
2368 } else if ((Bpb
.Media
!= 0xf0) &&
2369 (Bpb
.Media
!= 0xf8) &&
2370 (Bpb
.Media
!= 0xf9) &&
2371 (Bpb
.Media
!= 0xfb) &&
2372 (Bpb
.Media
!= 0xfc) &&
2373 (Bpb
.Media
!= 0xfd) &&
2374 (Bpb
.Media
!= 0xfe) &&
2375 (Bpb
.Media
!= 0xff) &&
2376 (!FatData
.FujitsuFMR
|| ((Bpb
.Media
!= 0x00) &&
2377 (Bpb
.Media
!= 0x01) &&
2378 (Bpb
.Media
!= 0xfa)))) {
2383 // If this isn't FAT32, then there better be a claimed root directory
2387 } else if (Bpb
.SectorsPerFat
!= 0 && Bpb
.RootEntries
== 0) {
2392 // If this is FAT32 (i.e., extended BPB), look for and refuse to mount
2393 // mirror-disabled volumes. If we did, we would need to only write to
2394 // the FAT# indicated in the ActiveFat field. The only user of this is
2395 // the FAT->FAT32 converter after the first pass of protected mode work
2396 // (booting into realmode) and NT should absolutely not be attempting
2397 // to mount such an in-transition volume.
2400 } else if (Bpb
.SectorsPerFat
== 0 && Bpb
.MirrorDisabled
) {
2405 DebugTrace(-1, Dbg
, "FatIsBootSectorFat -> %08lx\n", Result
);
2412 // Local Support Routine
2416 FatIsMediaWriteProtected (
2417 IN PIRP_CONTEXT IrpContext
,
2418 IN PDEVICE_OBJECT TargetDeviceObject
2423 Routine Description:
2425 This routine determines if the target media is write protected.
2429 TargetDeviceObject - The target of the query
2433 NTSTATUS - The return status for the operation
2441 IO_STATUS_BLOCK Iosb
;
2444 // Query the partition table
2447 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
2450 // See if the media is write protected. On success or any kind
2451 // of error (possibly illegal device function), assume it is
2452 // writeable, and only complain if he tells us he is write protected.
2455 Irp
= IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE
,
2466 // Just return FALSE in the unlikely event we couldn't allocate an Irp.
2469 if ( Irp
== NULL
) {
2474 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
2476 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
2478 if ( Status
== STATUS_PENDING
) {
2480 (VOID
) KeWaitForSingleObject( &Event
,
2484 (PLARGE_INTEGER
)NULL
);
2486 Status
= Iosb
.Status
;
2489 return (BOOLEAN
)(Status
== STATUS_MEDIA_WRITE_PROTECTED
);
2494 // Local Support Routine
2499 IN PIRP_CONTEXT IrpContext
,
2505 Routine Description:
2507 This is the common routine for implementing the user's requests made
2508 through NtFsControlFile.
2512 Irp - Supplies the Irp being processed
2516 NTSTATUS - The return status for the operation
2522 ULONG FsControlCode
;
2524 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2527 // Save some references to make our life a little easier
2530 FsControlCode
= IrpSp
->Parameters
.FileSystemControl
.FsControlCode
;
2532 DebugTrace(+1, Dbg
,"FatUserFsCtrl...\n", 0);
2533 DebugTrace( 0, Dbg
,"FsControlCode = %08lx\n", FsControlCode
);
2536 // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode
2537 // of the caller was userspace and this is a METHOD_NEITHER, we have the choice
2538 // of realy buffering the request through so we can possibly post, or making the
2539 // request synchronous. Since the former was not done by design, do the latter.
2542 if (Irp
->RequestorMode
!= KernelMode
&& (FsControlCode
& 3) == METHOD_NEITHER
) {
2544 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2548 // Case on the control code.
2551 switch ( FsControlCode
) {
2553 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
2554 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
2555 case FSCTL_REQUEST_BATCH_OPLOCK
:
2556 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
2557 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
2558 case FSCTL_OPLOCK_BREAK_NOTIFY
:
2559 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
2560 case FSCTL_REQUEST_FILTER_OPLOCK
:
2562 Status
= FatOplockRequest( IrpContext
, Irp
);
2565 case FSCTL_LOCK_VOLUME
:
2567 Status
= FatLockVolume( IrpContext
, Irp
);
2570 case FSCTL_UNLOCK_VOLUME
:
2572 Status
= FatUnlockVolume( IrpContext
, Irp
);
2575 case FSCTL_DISMOUNT_VOLUME
:
2577 Status
= FatDismountVolume( IrpContext
, Irp
);
2580 case FSCTL_MARK_VOLUME_DIRTY
:
2582 Status
= FatDirtyVolume( IrpContext
, Irp
);
2585 case FSCTL_IS_VOLUME_DIRTY
:
2587 Status
= FatIsVolumeDirty( IrpContext
, Irp
);
2590 case FSCTL_IS_VOLUME_MOUNTED
:
2592 Status
= FatIsVolumeMounted( IrpContext
, Irp
);
2595 case FSCTL_IS_PATHNAME_VALID
:
2596 Status
= FatIsPathnameValid( IrpContext
, Irp
);
2599 case FSCTL_QUERY_RETRIEVAL_POINTERS
:
2600 Status
= FatQueryRetrievalPointers( IrpContext
, Irp
);
2603 case FSCTL_QUERY_FAT_BPB
:
2604 Status
= FatQueryBpb( IrpContext
, Irp
);
2607 case FSCTL_FILESYSTEM_GET_STATISTICS
:
2608 Status
= FatGetStatistics( IrpContext
, Irp
);
2611 case FSCTL_GET_VOLUME_BITMAP
:
2612 Status
= FatGetVolumeBitmap( IrpContext
, Irp
);
2615 case FSCTL_GET_RETRIEVAL_POINTERS
:
2616 Status
= FatGetRetrievalPointers( IrpContext
, Irp
);
2619 case FSCTL_MOVE_FILE
:
2620 Status
= FatMoveFile( IrpContext
, Irp
);
2623 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
2624 Status
= FatAllowExtendedDasdIo( IrpContext
, Irp
);
2629 DebugTrace(0, Dbg
, "Invalid control code -> %08lx\n", FsControlCode
);
2631 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
2632 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2636 DebugTrace(-1, Dbg
, "FatUserFsCtrl -> %08lx\n", Status
);
2643 // Local support routine
2648 IN PIRP_CONTEXT IrpContext
,
2654 Routine Description:
2656 This is the common routine to handle oplock requests made via the
2657 NtFsControlFile call.
2661 Irp - Supplies the Irp being processed
2665 NTSTATUS - The return status for the operation
2671 ULONG FsControlCode
;
2676 ULONG OplockCount
= 0;
2678 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2680 BOOLEAN AcquiredVcb
= FALSE
;
2681 BOOLEAN AcquiredFcb
= FALSE
;
2684 // Save some references to make our life a little easier
2687 FsControlCode
= IrpSp
->Parameters
.FileSystemControl
.FsControlCode
;
2689 DebugTrace(+1, Dbg
, "FatOplockRequest...\n", 0);
2690 DebugTrace( 0, Dbg
, "FsControlCode = %08lx\n", FsControlCode
);
2693 // We only permit oplock requests on files.
2696 if ( FatDecodeFileObject( IrpSp
->FileObject
,
2699 &Ccb
) != UserFileOpen
) {
2701 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2702 DebugTrace(-1, Dbg
, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
2703 return STATUS_INVALID_PARAMETER
;
2707 // Make this a waitable Irpcontext so we don't fail to acquire
2711 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
2714 // Use a try finally to free the Fcb/Vcb
2720 // Switch on the function control code. We grab the Fcb exclusively
2721 // for oplock requests, shared for oplock break acknowledgement.
2724 switch ( FsControlCode
) {
2726 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
2727 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
2728 case FSCTL_REQUEST_BATCH_OPLOCK
:
2729 case FSCTL_REQUEST_FILTER_OPLOCK
:
2731 FatAcquireSharedVcb( IrpContext
, Fcb
->Vcb
);
2733 FatAcquireExclusiveFcb( IrpContext
, Fcb
);
2736 if (FsControlCode
== FSCTL_REQUEST_OPLOCK_LEVEL_2
) {
2738 OplockCount
= (ULONG
) FsRtlAreThereCurrentFileLocks( &Fcb
->Specific
.Fcb
.FileLock
);
2742 OplockCount
= Fcb
->UncleanCount
;
2747 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
2748 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
2749 case FSCTL_OPLOCK_BREAK_NOTIFY
:
2750 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
2752 FatAcquireSharedFcb( IrpContext
, Fcb
);
2758 FatBugCheck( FsControlCode
, 0, 0 );
2762 // Call the FsRtl routine to grant/acknowledge oplock.
2765 Status
= FsRtlOplockFsctrl( &Fcb
->Specific
.Fcb
.Oplock
,
2770 // Set the flag indicating if Fast I/O is possible
2773 Fcb
->Header
.IsFastIoPossible
= FatIsFastIoPossible( Fcb
);
2777 DebugUnwind( FatOplockRequest
);
2780 // Release all of our resources
2785 FatReleaseVcb( IrpContext
, Fcb
->Vcb
);
2790 FatReleaseFcb( IrpContext
, Fcb
);
2793 if (!_SEH2_AbnormalTermination()) {
2795 FatCompleteRequest( IrpContext
, FatNull
, 0 );
2798 DebugTrace(-1, Dbg
, "FatOplockRequest -> %08lx\n", Status
);
2806 // Local Support Routine
2811 IN PIRP_CONTEXT IrpContext
,
2817 Routine Description:
2819 This routine performs the lock volume operation. It is responsible for
2820 either completing of enqueuing the input Irp.
2824 Irp - Supplies the Irp to process
2828 NTSTATUS - The return status for the operation
2835 PIO_STACK_LOCATION IrpSp
;
2841 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2843 DebugTrace(+1, Dbg
, "FatLockVolume...\n", 0);
2846 // Decode the file object, the only type of opens we accept are
2847 // user volume opens.
2850 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2852 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2854 DebugTrace(-1, Dbg
, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
2855 return STATUS_INVALID_PARAMETER
;
2858 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
2860 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2862 DebugTrace(-1, Dbg
, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
2863 return STATUS_INVALID_PARAMETER
;
2867 // Send our notification so that folks that like to hold handles on
2868 // volumes can get out of the way.
2871 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
2874 // Acquire exclusive access to the Vcb and enqueue the Irp if we
2875 // didn't get access.
2878 if (!FatAcquireExclusiveVcb( IrpContext
, Vcb
)) {
2880 DebugTrace( 0, Dbg
, "Cannot acquire Vcb\n", 0);
2882 Status
= FatFsdPostRequest( IrpContext
, Irp
);
2884 DebugTrace(-1, Dbg
, "FatUnlockVolume -> %08lx\n", Status
);
2890 Status
= FatLockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2895 // Since we drop and release the vcb while trying to punch the volume
2896 // down, it may be the case that we decide the operation should not
2897 // continue if the user raced a CloeseHandle() with us (and it finished
2898 // the cleanup) while we were waiting for our closes to finish.
2900 // In this case, we will have been raised out of the acquire logic with
2901 // STATUS_FILE_CLOSED, and the volume will not be held.
2904 if (!_SEH2_AbnormalTermination() || ExIsResourceAcquiredExclusiveLite( &Vcb
->Resource
)) {
2906 FatReleaseVcb( IrpContext
, Vcb
);
2909 if (!NT_SUCCESS( Status
) || _SEH2_AbnormalTermination()) {
2912 // The volume lock will be failing.
2915 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
2919 FatCompleteRequest( IrpContext
, Irp
, Status
);
2921 DebugTrace(-1, Dbg
, "FatLockVolume -> %08lx\n", Status
);
2928 // Local Support Routine
2933 IN PIRP_CONTEXT IrpContext
,
2939 Routine Description:
2941 This routine performs the unlock volume operation. It is responsible for
2942 either completing of enqueuing the input Irp.
2946 Irp - Supplies the Irp to process
2950 NTSTATUS - The return status for the operation
2957 PIO_STACK_LOCATION IrpSp
;
2963 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2965 DebugTrace(+1, Dbg
, "FatUnlockVolume...\n", 0);
2968 // Decode the file object, the only type of opens we accept are
2969 // user volume opens.
2972 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
2974 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2976 DebugTrace(-1, Dbg
, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
2977 return STATUS_INVALID_PARAMETER
;
2980 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
2982 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
2984 DebugTrace(-1, Dbg
, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
2985 return STATUS_INVALID_PARAMETER
;
2988 Status
= FatUnlockVolumeInternal( IrpContext
, Vcb
, IrpSp
->FileObject
);
2991 // Send notification that the volume is avaliable.
2994 if (NT_SUCCESS( Status
)) {
2996 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
2999 FatCompleteRequest( IrpContext
, Irp
, Status
);
3001 DebugTrace(-1, Dbg
, "FatUnlockVolume -> %08lx\n", Status
);
3008 FatLockVolumeInternal (
3009 IN PIRP_CONTEXT IrpContext
,
3011 IN PFILE_OBJECT FileObject OPTIONAL
3016 Routine Description:
3018 This routine performs the actual lock volume operation. It will be called
3019 by anyone wishing to try to protect the volume for a long duration. PNP
3020 operations are such a user.
3022 The volume must be held exclusive by the caller.
3026 Vcb - The volume being locked.
3028 FileObject - File corresponding to the handle locking the volume. If this
3029 is not specified, a system lock is assumed.
3033 NTSTATUS - The return status for the operation
3038 NTSTATUS Status
= STATUS_SUCCESS
;
3040 ULONG RemainingUserReferences
= (FileObject
? 1: 0);
3042 ASSERT( ExIsResourceAcquiredExclusiveLite( &Vcb
->Resource
) &&
3043 !ExIsResourceAcquiredExclusiveLite( &FatData
.Resource
));
3045 // Go synchronous for the rest of the lock operation. It may be
3046 // reasonable to try to revisit this in the future, but for now
3047 // the purge below expects to be able to wait.
3049 // We know it is OK to leave the flag up given how we're used at
3053 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
3056 // If there are any open handles, this will fail.
3059 if (!FatIsHandleCountZero( IrpContext
, Vcb
)) {
3061 return STATUS_ACCESS_DENIED
;
3065 // Force Mm to get rid of its referenced file objects.
3068 FatFlushFat( IrpContext
, Vcb
);
3070 FatPurgeReferencedFileObjects( IrpContext
, Vcb
->RootDcb
, Flush
);
3072 FatCloseEaFile( IrpContext
, Vcb
, TRUE
);
3075 // Now back out of our synchronization and wait for the lazy writer
3076 // to finish off any lazy closes that could have been outstanding.
3078 // Since we flushed, we know that the lazy writer will issue all
3079 // possible lazy closes in the next tick - if we hadn't, an otherwise
3080 // unopened file with a large amount of dirty data could have hung
3081 // around for a while as the data trickled out to the disk.
3083 // This is even more important now since we send notification to
3084 // alert other folks that this style of check is about to happen so
3085 // that they can close their handles. We don't want to enter a fast
3086 // race with the lazy writer tearing down his references to the file.
3089 FatReleaseVcb( IrpContext
, Vcb
);
3091 Status
= CcWaitForCurrentLazyWriterActivity();
3093 FatAcquireExclusiveVcb( IrpContext
, Vcb
);
3095 if (!NT_SUCCESS( Status
)) {
3101 // Now rundown the delayed closes one last time. We appear to be able
3102 // to have additional collisions.
3108 // Check if the Vcb is already locked, or if the open file count
3109 // is greater than 1 (which implies that someone else also is
3110 // currently using the volume, or a file on the volume), and that the
3111 // VPB reference count only includes our residual and the handle (as
3114 // We used to only check for the vpb refcount. This is unreliable since
3115 // the vpb refcount is dropped immediately before final close, meaning
3116 // that even though we had a good refcount, the close was inflight and
3117 // subsequent operations could get confused. Especially if the PNP path
3118 // was the lock caller, we delete the VCB with an outstanding opencount!
3121 IoAcquireVpbSpinLock( &SavedIrql
);
3123 if (!FlagOn(Vcb
->Vpb
->Flags
, VPB_LOCKED
) &&
3124 (Vcb
->Vpb
->ReferenceCount
<= 2 + RemainingUserReferences
) &&
3125 (Vcb
->OpenFileCount
== (CLONG
)( FileObject
? 1: 0 ))) {
3127 SetFlag(Vcb
->Vpb
->Flags
, VPB_LOCKED
);
3128 SetFlag(Vcb
->VcbState
, VCB_STATE_FLAG_LOCKED
);
3129 Vcb
->FileObjectWithVcbLocked
= FileObject
;
3133 Status
= STATUS_ACCESS_DENIED
;
3136 IoReleaseVpbSpinLock( SavedIrql
);
3139 // If we successully locked the volume, see if it is clean now.
3142 if (NT_SUCCESS( Status
) &&
3143 FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
) &&
3144 !FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
) &&
3145 !CcIsThereDirtyData(Vcb
->Vpb
)) {
3147 FatMarkVolume( IrpContext
, Vcb
, VolumeClean
);
3148 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
);
3151 ASSERT( !NT_SUCCESS(Status
) || (Vcb
->OpenFileCount
== (CLONG
)( FileObject
? 1: 0 )));
3158 FatUnlockVolumeInternal (
3159 IN PIRP_CONTEXT IrpContext
,
3161 IN PFILE_OBJECT FileObject OPTIONAL
3166 Routine Description:
3168 This routine performs the actual unlock volume operation.
3170 The volume must be held exclusive by the caller.
3174 Vcb - The volume being locked.
3176 FileObject - File corresponding to the handle locking the volume. If this
3177 is not specified, a system lock is assumed.
3181 NTSTATUS - The return status for the operation
3183 Attempting to remove a system lock that did not exist is OK.
3189 NTSTATUS Status
= STATUS_NOT_LOCKED
;
3191 IoAcquireVpbSpinLock( &SavedIrql
);
3193 if (FlagOn(Vcb
->Vpb
->Flags
, VPB_LOCKED
) && FileObject
== Vcb
->FileObjectWithVcbLocked
) {
3196 // This one locked it, unlock the volume
3199 ClearFlag( Vcb
->Vpb
->Flags
, VPB_LOCKED
);
3200 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_LOCKED
);
3201 Vcb
->FileObjectWithVcbLocked
= NULL
;
3203 Status
= STATUS_SUCCESS
;
3206 IoReleaseVpbSpinLock( SavedIrql
);
3213 // Local Support Routine
3218 IN PIRP_CONTEXT IrpContext
,
3224 Routine Description:
3226 This routine performs the dismount volume operation. It is responsible for
3227 either completing of enqueuing the input Irp.
3231 Irp - Supplies the Irp to process
3235 NTSTATUS - The return status for the operation
3240 PIO_STACK_LOCATION IrpSp
;
3242 BOOLEAN VcbHeld
= FALSE
;
3248 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3250 DebugTrace(+1, Dbg
, "FatDismountVolume...\n", 0);
3253 // Decode the file object, the only type of opens we accept are
3254 // user volume opens on media that is not boot/paging and is not
3255 // already dismounted ... (but we need to check that stuff while
3259 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
3261 Status
= STATUS_INVALID_PARAMETER
;
3265 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
3267 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
3269 DebugTrace(-1, Dbg
, "FatDismountVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
3270 return STATUS_INVALID_PARAMETER
;
3274 // Make some unsynchronized checks to see if this operation is possible.
3275 // We will repeat the appropriate ones inside synchronization, but it is
3276 // good to avoid bogus notifications.
3279 if (FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
3281 Status
= STATUS_ACCESS_DENIED
;
3285 if (FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DISMOUNTED
)) {
3287 Status
= STATUS_VOLUME_DISMOUNTED
;
3292 // A bit of historical comment is in order.
3294 // In all versions prior to NT5, we only permitted dismount if the volume had
3295 // previously been locked. Now we must permit a forced dismount, meaning that
3296 // we grab ahold of the whole kit-n-kaboodle - regardless of activity, open
3297 // handles, etc. - to flush and invalidate the volume.
3299 // Previously, dismount assumed that lock had come along earlier and done some
3300 // of the work that we are now going to do - i.e., flush, tear down the eas. All
3301 // we had to do here is flush the device out and kill off as many of the orphan
3302 // fcbs as possible. This now changes.
3304 // In fact, everything is a forced dismount now. This changes one interesting
3305 // aspect, which is that it used to be the case that the handle used to dismount
3306 // could come back, read, and induce a verify/remount. This is just not possible
3307 // now. The point of forced dismount is that very shortly someone will come along
3308 // and be destructive to the possibility of using the media further - format, eject,
3309 // etc. By using this path, callers are expected to tolerate the consequences.
3311 // Note that the volume can still be successfully unlocked by this handle.
3315 // Send notification.
3318 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_DISMOUNT
);
3321 // Force ourselves to wait and grab everything.
3324 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
3325 (VOID
)FatAcquireExclusiveGlobal( IrpContext
);
3330 // Guess what? This can raise if a cleanup on the fileobject we
3331 // got races in ahead of us.
3334 FatAcquireExclusiveVolume( IrpContext
, Vcb
);
3337 if (FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DISMOUNTED
)) {
3339 try_return( Status
= STATUS_VOLUME_DISMOUNTED
);
3342 FatFlushAndCleanVolume( IrpContext
, Irp
, Vcb
, FlushAndInvalidate
);
3345 // We defer the physical dismount until this handle is closed, per symmetric
3346 // implemntation in the other FS. This permits a dismounter to issue IOCTL
3347 // through this handle and perform device manipulation without racing with
3348 // creates attempting to mount the volume again.
3350 // Raise a flag to tell the cleanup path to complete the dismount.
3353 SetFlag( Ccb
->Flags
, CCB_FLAG_COMPLETE_DISMOUNT
);
3356 // Indicate that the volume was dismounted so that we may return the
3357 // correct error code when operations are attempted via open handles.
3360 Vcb
->VcbCondition
= VcbBad
;
3361 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DISMOUNTED
);
3363 Status
= STATUS_SUCCESS
;
3371 FatReleaseVolume( IrpContext
, Vcb
);
3374 FatReleaseGlobal( IrpContext
);
3377 // I do not believe it is possible to raise, but for completeness
3378 // notice and send notification of failure. We absolutely
3379 // cannot have raised in CheckForDismount.
3381 // We decline to call an attempt to dismount a dismounted volume
3382 // a failure to do so.
3385 if ((!NT_SUCCESS( Status
) && Status
!= STATUS_VOLUME_DISMOUNTED
)
3386 || _SEH2_AbnormalTermination()) {
3388 FsRtlNotifyVolumeEvent( IrpSp
->FileObject
, FSRTL_VOLUME_DISMOUNT_FAILED
);
3394 FatCompleteRequest( IrpContext
, Irp
, Status
);
3395 DebugTrace(-1, Dbg
, "FatDismountVolume -> %08lx\n", Status
);
3401 // Local Support Routine
3406 IN PIRP_CONTEXT IrpContext
,
3412 Routine Description:
3414 This routine marks the volume as dirty.
3418 Irp - Supplies the Irp to process
3422 NTSTATUS - The return status for the operation
3427 PIO_STACK_LOCATION IrpSp
;
3433 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3435 DebugTrace(+1, Dbg
, "FatDirtyVolume...\n", 0);
3438 // Decode the file object, the only type of opens we accept are
3439 // user volume opens.
3442 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
3444 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
3446 DebugTrace(-1, Dbg
, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
3447 return STATUS_INVALID_PARAMETER
;
3450 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
3452 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
3454 DebugTrace(-1, Dbg
, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER
);
3455 return STATUS_INVALID_PARAMETER
;
3460 // Disable popups, we will just return any error.
3463 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
3466 // Verify the Vcb. We want to make sure we don't dirty some
3467 // random chunk of media that happens to be in the drive now.
3470 FatVerifyVcb( IrpContext
, Vcb
);
3472 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
);
3474 FatMarkVolume( IrpContext
, Vcb
, VolumeDirty
);
3476 FatCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
3478 DebugTrace(-1, Dbg
, "FatDirtyVolume -> STATUS_SUCCESS\n", 0);
3480 return STATUS_SUCCESS
;
3485 // Local Support Routine
3490 IN PIRP_CONTEXT IrpContext
,
3496 Routine Description:
3498 This routine determines if a volume is currently dirty.
3502 Irp - Supplies the Irp to process
3506 NTSTATUS - The return status for the operation
3511 PIO_STACK_LOCATION IrpSp
;
3513 TYPE_OF_OPEN TypeOfOpen
;
3521 // Get the current stack location and extract the output
3522 // buffer information.
3525 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3528 // Get a pointer to the output buffer. Look at the system buffer field in the
3529 // irp first. Then the Irp Mdl.
3532 if (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
) {
3534 VolumeState
= Irp
->AssociatedIrp
.SystemBuffer
;
3536 } else if (Irp
->MdlAddress
!= NULL
) {
3538 VolumeState
= MmGetSystemAddressForMdlSafe( Irp
->MdlAddress
, LowPagePriority
);
3540 if (VolumeState
== NULL
) {
3542 FatCompleteRequest( IrpContext
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
3543 return STATUS_INSUFFICIENT_RESOURCES
;
3548 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_USER_BUFFER
);
3549 return STATUS_INVALID_USER_BUFFER
;
3553 // Make sure the output buffer is large enough and then initialize
3554 // the answer to be that the volume isn't dirty.
3557 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
)) {
3559 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
3560 return STATUS_INVALID_PARAMETER
;
3566 // Decode the file object
3569 TypeOfOpen
= FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
);
3571 if (TypeOfOpen
!= UserVolumeOpen
) {
3573 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
3574 return STATUS_INVALID_PARAMETER
;
3577 if (Vcb
->VcbCondition
!= VcbGood
) {
3579 FatCompleteRequest( IrpContext
, Irp
, STATUS_VOLUME_DISMOUNTED
);
3580 return STATUS_VOLUME_DISMOUNTED
;
3584 // Disable PopUps, we want to return any error.
3587 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
3590 // Verify the Vcb. We want to make double sure that this volume
3591 // is around so that we know our information is good.
3594 FatVerifyVcb( IrpContext
, Vcb
);
3597 // Now set the returned information. We can avoid probing the disk since
3598 // we know our internal state is in sync.
3601 if ( FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
| VCB_STATE_FLAG_MOUNTED_DIRTY
) ) {
3603 SetFlag( *VolumeState
, VOLUME_IS_DIRTY
);
3606 Irp
->IoStatus
.Information
= sizeof( ULONG
);
3608 FatCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
3609 return STATUS_SUCCESS
;
3614 // Local Support Routine
3618 FatIsVolumeMounted (
3619 IN PIRP_CONTEXT IrpContext
,
3625 Routine Description:
3627 This routine determines if a volume is currently mounted.
3631 Irp - Supplies the Irp to process
3635 NTSTATUS - The return status for the operation
3642 PIO_STACK_LOCATION IrpSp
;
3648 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3650 Status
= STATUS_SUCCESS
;
3652 DebugTrace(+1, Dbg
, "FatIsVolumeMounted...\n", 0);
3655 // Decode the file object.
3658 (VOID
)FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
);
3660 ASSERT( Vcb
!= NULL
);
3663 // Disable PopUps, we want to return any error.
3666 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
);
3672 FatVerifyVcb( IrpContext
, Vcb
);
3674 FatCompleteRequest( IrpContext
, Irp
, Status
);
3676 DebugTrace(-1, Dbg
, "FatIsVolumeMounted -> %08lx\n", Status
);
3683 // Local Support Routine
3687 FatIsPathnameValid (
3688 IN PIRP_CONTEXT IrpContext
,
3694 Routine Description:
3696 This routine determines if a pathname is a-priori illegal by inspecting
3697 the the characters used. It is required to be correct on a FALSE return.
3699 N.B.: current implementation is intentioanlly a no-op. This may change
3700 in the future. A careful reader of the previous implementation of this
3701 FSCTL in FAT would discover that it violated the requirement stated above
3702 and could return FALSE for a valid (createable) pathname.
3706 Irp - Supplies the Irp to process
3710 NTSTATUS - The return status for the operation
3715 DebugTrace(+1, Dbg
, "FatIsPathnameValid...\n", 0);
3717 FatCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
3719 DebugTrace(-1, Dbg
, "FatIsPathnameValid -> %08lx\n", STATUS_SUCCESS
);
3721 return STATUS_SUCCESS
;
3726 // Local Support Routine
3731 IN PIRP_CONTEXT IrpContext
,
3737 Routine Description:
3739 This routine simply returns the first 0x24 bytes of sector 0.
3743 Irp - Supplies the Irp to process
3747 NTSTATUS - The return status for the operation
3752 PIO_STACK_LOCATION IrpSp
;
3756 PFSCTL_QUERY_FAT_BPB_BUFFER BpbBuffer
;
3758 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3760 DebugTrace(+1, Dbg
, "FatQueryBpb...\n", 0);
3763 // Get the Vcb. If we didn't keep the information needed for this call,
3764 // we had a reason ...
3767 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
3769 if (Vcb
->First0x24BytesOfBootSector
== NULL
) {
3771 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
3772 DebugTrace(-1, Dbg
, "FatQueryBpb -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST
);
3773 return STATUS_INVALID_DEVICE_REQUEST
;
3777 // Extract the buffer
3780 BpbBuffer
= (PFSCTL_QUERY_FAT_BPB_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
3783 // Make sure the buffer is big enough.
3786 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< 0x24) {
3788 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
3789 DebugTrace(-1, Dbg
, "FatQueryBpb -> %08lx\n", STATUS_BUFFER_TOO_SMALL
);
3790 return STATUS_BUFFER_TOO_SMALL
;
3794 // Fill in the output buffer
3797 RtlCopyMemory( BpbBuffer
->First0x24BytesOfBootSector
,
3798 Vcb
->First0x24BytesOfBootSector
,
3801 Irp
->IoStatus
.Information
= 0x24;
3803 FatCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
3804 DebugTrace(-1, Dbg
, "FatQueryBpb -> %08lx\n", STATUS_SUCCESS
);
3805 return STATUS_SUCCESS
;
3810 // Local Support Routine
3814 FatInvalidateVolumes (
3820 Routine Description:
3822 This routine searches for all the volumes mounted on the same real device
3823 of the current DASD handle, and marks them all bad. The only operation
3824 that can be done on such handles is cleanup and close.
3828 Irp - Supplies the Irp to process
3832 NTSTATUS - The return status for the operation
3838 IRP_CONTEXT IrpContext
;
3839 PIO_STACK_LOCATION IrpSp
;
3841 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
3847 PFILE_OBJECT FileToMarkBad
;
3848 PDEVICE_OBJECT DeviceToMarkBad
;
3850 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3852 DebugTrace(+1, Dbg
, "FatInvalidateVolumes...\n", 0);
3855 // Check for the correct security access.
3856 // The caller must have the SeTcbPrivilege.
3859 if (!SeSinglePrivilegeCheck(TcbPrivilege
, Irp
->RequestorMode
)) {
3861 FatCompleteRequest( FatNull
, Irp
, STATUS_PRIVILEGE_NOT_HELD
);
3863 DebugTrace(-1, Dbg
, "FatInvalidateVolumes -> %08lx\n", STATUS_PRIVILEGE_NOT_HELD
);
3864 return STATUS_PRIVILEGE_NOT_HELD
;
3868 // Try to get a pointer to the device object from the handle passed in.
3872 if (IoIs32bitProcess( Irp
)) {
3874 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(UINT32
)) {
3876 FatCompleteRequest( FatNull
, Irp
, STATUS_INVALID_PARAMETER
);
3878 DebugTrace(-1, Dbg
, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER
);
3879 return STATUS_INVALID_PARAMETER
;
3882 Handle
= (HANDLE
) LongToHandle( (*(PUINT32
)Irp
->AssociatedIrp
.SystemBuffer
) );
3885 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(HANDLE
)) {
3887 FatCompleteRequest( FatNull
, Irp
, STATUS_INVALID_PARAMETER
);
3889 DebugTrace(-1, Dbg
, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER
);
3890 return STATUS_INVALID_PARAMETER
;
3893 Handle
= *(PHANDLE
)Irp
->AssociatedIrp
.SystemBuffer
;
3899 Status
= ObReferenceObjectByHandle( Handle
,
3906 (PVOID
*)&FileToMarkBad
,
3910 if (!NT_SUCCESS(Status
)) {
3912 FatCompleteRequest( FatNull
, Irp
, Status
);
3914 DebugTrace(-1, Dbg
, "FatInvalidateVolumes -> %08lx\n", Status
);
3920 // We only needed the pointer, not a reference.
3923 ObDereferenceObject( FileToMarkBad
);
3926 // Grab the DeviceObject from the FileObject.
3929 DeviceToMarkBad
= FileToMarkBad
->DeviceObject
;
3932 RtlZeroMemory( &IrpContext
, sizeof(IRP_CONTEXT
) );
3934 SetFlag( IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
3935 IrpContext
.MajorFunction
= IrpSp
->MajorFunction
;
3936 IrpContext
.MinorFunction
= IrpSp
->MinorFunction
;
3938 FatAcquireExclusiveGlobal( &IrpContext
);
3941 // First acquire the FatData resource shared, then walk through all the
3942 // mounted VCBs looking for candidates to mark BAD.
3944 // On volumes we mark bad, check for dismount possibility (which is
3945 // why we have to get the next link early).
3948 Links
= FatData
.VcbQueue
.Flink
;
3950 while (Links
!= &FatData
.VcbQueue
) {
3954 ExistingVcb
= CONTAINING_RECORD(Links
, VCB
, VcbLinks
);
3956 Links
= Links
->Flink
;
3959 // If we get a match, mark the volume Bad, and also check to
3960 // see if the volume should go away.
3963 if (ExistingVcb
->Vpb
->RealDevice
== DeviceToMarkBad
) {
3970 // Here we acquire the Vcb exclusive and try to purge
3971 // all the open files. The idea is to have as little as
3972 // possible stale data visible and to hasten the volume
3976 (VOID
)FatAcquireExclusiveVcb( &IrpContext
, ExistingVcb
);
3978 if (ExistingVcb
->Vpb
== DeviceToMarkBad
->Vpb
) {
3982 IoAcquireVpbSpinLock( &OldIrql
);
3984 if (FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_MOUNTED
)) {
3988 NewVpb
= ExistingVcb
->SwapVpb
;
3989 ExistingVcb
->SwapVpb
= NULL
;
3990 SetFlag( ExistingVcb
->VcbState
, VCB_STATE_FLAG_VPB_MUST_BE_FREED
);
3992 RtlZeroMemory( NewVpb
, sizeof( VPB
) );
3993 NewVpb
->Type
= IO_TYPE_VPB
;
3994 NewVpb
->Size
= sizeof( VPB
);
3995 NewVpb
->RealDevice
= DeviceToMarkBad
;
3996 NewVpb
->Flags
= FlagOn( DeviceToMarkBad
->Vpb
->Flags
, VPB_REMOVE_PENDING
);
3998 DeviceToMarkBad
->Vpb
= NewVpb
;
4001 ASSERT( DeviceToMarkBad
->Vpb
->DeviceObject
== NULL
);
4003 IoReleaseVpbSpinLock( OldIrql
);
4006 FatSetVcbCondition( ExistingVcb
, VcbBad
);
4009 // Process the root directory, if it is present.
4012 if (ExistingVcb
->RootDcb
!= NULL
) {
4014 FatMarkFcbCondition( &IrpContext
, ExistingVcb
->RootDcb
, FcbBad
, TRUE
);
4017 // Purging the file objects on this volume could result in the memory manager
4018 // dereferencing it's file pointer which could be the last reference and
4019 // trigger object deletion and VCB deletion. Protect against that here by
4020 // temporarily biasing the file count, and later checking for dismount.
4023 ExistingVcb
->OpenFileCount
+= 1;
4025 FatPurgeReferencedFileObjects( &IrpContext
,
4026 ExistingVcb
->RootDcb
,
4029 ExistingVcb
->OpenFileCount
-= 1;
4031 VcbDeleted
= FatCheckForDismount( &IrpContext
, ExistingVcb
, FALSE
);
4035 // Drop the resource.
4038 if (VcbDeleted
!= TRUE
) {
4039 FatReleaseVcb( &IrpContext
, ExistingVcb
);
4044 FatReleaseGlobal( &IrpContext
);
4046 FatCompleteRequest( FatNull
, Irp
, STATUS_SUCCESS
);
4048 DebugTrace(-1, Dbg
, "FatInvalidateVolumes -> STATUS_SUCCESS\n", 0);
4050 return STATUS_SUCCESS
;
4055 // Local Support routine
4059 FatPerformVerifyDiskRead (
4060 IN PIRP_CONTEXT IrpContext
,
4064 IN ULONG NumberOfBytesToRead
,
4065 IN BOOLEAN ReturnOnError
4070 Routine Description:
4072 This routine is used to read in a range of bytes from the disk. It
4073 bypasses all of the caching and regular I/O logic, and builds and issues
4074 the requests itself. It does this operation overriding the verify
4075 volume flag in the device object.
4079 Vcb - Supplies the target device object for this operation.
4081 Buffer - Supplies the buffer that will recieve the results of this operation
4083 Lbo - Supplies the byte offset of where to start reading
4085 NumberOfBytesToRead - Supplies the number of bytes to read, this must
4086 be in multiple of bytes units acceptable to the disk driver.
4088 ReturnOnError - Indicates that we should return on an error, instead
4093 BOOLEAN - TRUE if the operation succeded, FALSE otherwise.
4100 LARGE_INTEGER ByteOffset
;
4102 IO_STATUS_BLOCK Iosb
;
4104 DebugTrace(0, Dbg
, "FatPerformVerifyDiskRead, Lbo = %08lx\n", Lbo
);
4107 // Initialize the event we're going to use
4110 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
4113 // Build the irp for the operation and also set the overrride flag
4116 ByteOffset
.QuadPart
= Lbo
;
4118 Irp
= IoBuildSynchronousFsdRequest( IRP_MJ_READ
,
4119 Vcb
->TargetDeviceObject
,
4121 NumberOfBytesToRead
,
4126 if ( Irp
== NULL
) {
4128 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
4131 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
4134 // Call the device to do the read and wait for it to finish.
4137 Status
= IoCallDriver( Vcb
->TargetDeviceObject
, Irp
);
4139 if (Status
== STATUS_PENDING
) {
4141 (VOID
)KeWaitForSingleObject( &Event
, Executive
, KernelMode
, FALSE
, (PLARGE_INTEGER
)NULL
);
4143 Status
= Iosb
.Status
;
4146 ASSERT( Status
!= STATUS_VERIFY_REQUIRED
);
4149 // Special case this error code because this probably means we used
4150 // the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
4153 if (Status
== STATUS_INVALID_PARAMETER
) {
4159 // If it doesn't succeed then either return or raise the error.
4162 if (!NT_SUCCESS(Status
)) {
4164 if (ReturnOnError
) {
4170 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
4175 // And return to our caller
4183 // Local Support Routine
4187 FatQueryRetrievalPointers (
4188 IN PIRP_CONTEXT IrpContext
,
4194 Routine Description:
4196 This routine performs the query retrieval pointers operation.
4197 It returns the retrieval pointers for the specified input
4198 file from the start of the file to the request map size specified
4199 in the input buffer.
4203 Irp - Supplies the Irp to process
4207 NTSTATUS - The return status for the operation
4214 PIO_STACK_LOCATION IrpSp
;
4220 PLARGE_INTEGER RequestedMapSize
;
4221 PLARGE_INTEGER
*MappingPairs
;
4231 // Get the current stack location
4234 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
4237 // Decode the file object and ensure that it is the paging file
4239 // Only Kernel mode clients may query retrieval pointer information about
4240 // a file. Ensure that this is the case for this caller.
4243 (VOID
)FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
);
4245 if (Irp
->RequestorMode
!= KernelMode
||
4247 !FlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ) {
4249 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
4250 return STATUS_INVALID_PARAMETER
;
4254 // Extract the input and output buffer information. The input contains
4255 // the requested size of the mappings in terms of VBO. The output
4256 // parameter will receive a pointer to nonpaged pool where the mapping
4257 // pairs are stored.
4260 ASSERT( IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
== sizeof(LARGE_INTEGER
) );
4261 ASSERT( IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
== sizeof(PVOID
) );
4263 RequestedMapSize
= IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
;
4264 MappingPairs
= Irp
->UserBuffer
;
4267 // Acquire exclusive access to the Fcb
4270 if (!FatAcquireExclusiveFcb( IrpContext
, Fcb
)) {
4272 return FatFsdPostRequest( IrpContext
, Irp
);
4278 // Verify the Fcb is still OK
4281 FatVerifyFcb( IrpContext
, Fcb
);
4284 // Check if the mapping the caller requested is too large
4287 if ((*RequestedMapSize
).QuadPart
> Fcb
->Header
.FileSize
.QuadPart
) {
4289 try_return( Status
= STATUS_INVALID_PARAMETER
);
4293 // Now get the index for the mcb entry that will contain the
4294 // callers request and allocate enough pool to hold the
4295 // output mapping pairs
4298 (VOID
)FatLookupMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
, RequestedMapSize
->LowPart
- 1, &Lbo
, NULL
, &Index
);
4300 *MappingPairs
= FsRtlAllocatePoolWithTag( NonPagedPool
,
4301 (Index
+ 2) * (2 * sizeof(LARGE_INTEGER
)),
4302 TAG_OUTPUT_MAPPINGPAIRS
);
4305 // Now copy over the mapping pairs from the mcb
4306 // to the output buffer. We store in [sector count, lbo]
4307 // mapping pairs and end with a zero sector count.
4310 MapSize
= RequestedMapSize
->LowPart
;
4312 for (i
= 0; i
<= Index
; i
+= 1) {
4315 (VOID
)FatGetNextMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
, i
, &Vbo
, &Lbo
, &SectorCount
);
4317 (VOID
)FatGetNextMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
, i
, (PVBO
)&Vbo
, &Lbo
, &SectorCount
);
4320 if (SectorCount
> MapSize
) {
4321 SectorCount
= MapSize
;
4324 (*MappingPairs
)[ i
*2 + 0 ].QuadPart
= SectorCount
;
4325 (*MappingPairs
)[ i
*2 + 1 ].QuadPart
= Lbo
;
4327 MapSize
-= SectorCount
;
4330 (*MappingPairs
)[ i
*2 + 0 ].QuadPart
= 0;
4332 Status
= STATUS_SUCCESS
;
4337 DebugUnwind( FatQueryRetrievalPointers
);
4340 // Release all of our resources
4343 FatReleaseFcb( IrpContext
, Fcb
);
4346 // If this is an abnormal termination then undo our work, otherwise
4350 if (!_SEH2_AbnormalTermination()) {
4352 FatCompleteRequest( IrpContext
, Irp
, Status
);
4361 // Local Support Routine
4366 IN PIRP_CONTEXT IrpContext
,
4372 Routine Description:
4374 This routine returns the filesystem performance counters from the
4379 Irp - Supplies the Irp to process
4383 NTSTATUS - The return status for the operation
4388 PIO_STACK_LOCATION IrpSp
;
4392 PFILE_SYSTEM_STATISTICS Buffer
;
4397 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
4399 DebugTrace(+1, Dbg
, "FatGetStatistics...\n", 0);
4402 // Extract the buffer
4405 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4406 BufferLength
= IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
;
4409 // Get a pointer to the output buffer.
4412 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4415 // Make sure the buffer is big enough for at least the common part.
4418 if (BufferLength
< sizeof(FILESYSTEM_STATISTICS
)) {
4420 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
4422 DebugTrace(-1, Dbg
, "FatGetStatistics -> %08lx\n", STATUS_BUFFER_TOO_SMALL
);
4424 return STATUS_BUFFER_TOO_SMALL
;
4428 // Now see how many bytes we can copy.
4431 StatsSize
= sizeof(FILE_SYSTEM_STATISTICS
) * KeNumberProcessors
;
4433 if (BufferLength
< StatsSize
) {
4435 BytesToCopy
= BufferLength
;
4436 Status
= STATUS_BUFFER_OVERFLOW
;
4440 BytesToCopy
= StatsSize
;
4441 Status
= STATUS_SUCCESS
;
4448 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
4451 // Fill in the output buffer
4454 RtlCopyMemory( Buffer
, Vcb
->Statistics
, BytesToCopy
);
4456 Irp
->IoStatus
.Information
= BytesToCopy
;
4458 FatCompleteRequest( IrpContext
, Irp
, Status
);
4460 DebugTrace(-1, Dbg
, "FatGetStatistics -> %08lx\n", Status
);
4466 // Local Support Routine
4471 IN PIRP_CONTEXT IrpContext
,
4477 Routine Description:
4479 This routine returns the volume allocation bitmap.
4481 Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
4482 through the input buffer.
4483 Output = the VOLUME_BITMAP_BUFFER data structure is returned through
4486 We return as much as the user buffer allows starting the specified input
4487 LCN (trucated to a byte). If there is no input buffer, we start at zero.
4491 Irp - Supplies the Irp being processed.
4495 NTSTATUS - The return status for the operation.
4500 PIO_STACK_LOCATION IrpSp
;
4507 ULONG TotalClusters
;
4508 ULONG DesiredClusters
;
4509 ULONG StartingCluster
;
4510 ULONG InputBufferLength
;
4511 ULONG OutputBufferLength
;
4512 LARGE_INTEGER StartingLcn
;
4513 PVOLUME_BITMAP_BUFFER OutputBuffer
;
4516 // Get the current Irp stack location and save some references.
4519 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
4521 DebugTrace(+1, Dbg
, "FatGetVolumeBitmap, FsControlCode = %08lx\n",
4522 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
);
4525 // Extract and decode the file object and check for type of open.
4528 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
4530 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
4531 return STATUS_INVALID_PARAMETER
;
4534 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
4536 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
4538 DebugTrace(-1, Dbg
, "FatGetVolumeBitmap -> %08lx\n", STATUS_INVALID_PARAMETER
);
4539 return STATUS_INVALID_PARAMETER
;
4542 InputBufferLength
= IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
;
4543 OutputBufferLength
= IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
;
4545 OutputBuffer
= (PVOLUME_BITMAP_BUFFER
)FatMapUserBuffer( IrpContext
, Irp
);
4548 // Check for a minimum length on the input and output buffers.
4551 if ((InputBufferLength
< sizeof(STARTING_LCN_INPUT_BUFFER
)) ||
4552 (OutputBufferLength
< sizeof(VOLUME_BITMAP_BUFFER
))) {
4554 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
4555 return STATUS_BUFFER_TOO_SMALL
;
4559 // Check if a starting cluster was specified.
4562 TotalClusters
= Vcb
->AllocationSupport
.NumberOfClusters
;
4565 // Check for valid buffers
4570 if (Irp
->RequestorMode
!= KernelMode
) {
4572 ProbeForRead( IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
,
4576 ProbeForWrite( OutputBuffer
, OutputBufferLength
, sizeof(UCHAR
) );
4579 StartingLcn
= ((PSTARTING_LCN_INPUT_BUFFER
)IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
)->StartingLcn
;
4581 } _SEH2_EXCEPT( Irp
->RequestorMode
!= KernelMode
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
4583 Status
= _SEH2_GetExceptionCode();
4585 FatRaiseStatus( IrpContext
,
4586 FsRtlIsNtstatusExpected(Status
) ?
4587 Status
: STATUS_INVALID_USER_BUFFER
);
4590 if (StartingLcn
.HighPart
|| StartingLcn
.LowPart
>= TotalClusters
) {
4592 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
4593 return STATUS_INVALID_PARAMETER
;
4597 StartingCluster
= StartingLcn
.LowPart
& ~7;
4601 // Acquire exclusive access to the Vcb and enqueue the Irp if we
4602 // didn't get access.
4605 if (!FatAcquireExclusiveVcb( IrpContext
, Vcb
)) {
4607 DebugTrace( 0, Dbg
, "Cannot acquire Vcb\n", 0);
4609 ASSERT( Irp
->RequestorMode
== KernelMode
);
4611 Status
= FatFsdPostRequest( IrpContext
, Irp
);
4613 DebugTrace(-1, Dbg
, "FatGetVolumeBitmap -> %08lx\n", Status
);
4618 // Only return what will fit in the user buffer.
4621 OutputBufferLength
-= FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
);
4622 DesiredClusters
= TotalClusters
- StartingCluster
;
4624 if (OutputBufferLength
< (DesiredClusters
+ 7) / 8) {
4626 BytesToCopy
= OutputBufferLength
;
4627 Status
= STATUS_BUFFER_OVERFLOW
;
4631 BytesToCopy
= (DesiredClusters
+ 7) / 8;
4632 Status
= STATUS_SUCCESS
;
4636 // Use try/finally for cleanup.
4644 // Verify the Vcb is still OK
4647 FatQuickVerifyVcb( IrpContext
, Vcb
);
4650 // Fill in the fixed part of the output buffer
4653 OutputBuffer
->StartingLcn
.QuadPart
= StartingCluster
;
4654 OutputBuffer
->BitmapSize
.QuadPart
= DesiredClusters
;
4656 if (Vcb
->NumberOfWindows
== 1) {
4659 // Just copy the volume bitmap into the user buffer.
4662 ASSERT( Vcb
->FreeClusterBitMap
.Buffer
!= NULL
);
4664 RtlCopyMemory( &OutputBuffer
->Buffer
[0],
4665 (PUCHAR
)Vcb
->FreeClusterBitMap
.Buffer
+ StartingCluster
/8,
4670 // Call out to analyze the FAT. We must bias by two to account for
4671 // the zero base of this API and FAT's physical reality of starting
4672 // the file heap at cluster 2.
4674 // Note that the end index is inclusive - we need to subtract one to
4677 // I.e.: StartingCluster 0 for one byte of bitmap means a start cluster
4678 // of 2 and end cluster of 9, a run of eight clusters.
4681 FatExamineFatEntries( IrpContext
,
4683 StartingCluster
+ 2,
4684 StartingCluster
+ BytesToCopy
* 8 + 2 - 1,
4687 (PULONG
)&OutputBuffer
->Buffer
[0] );
4690 } _SEH2_EXCEPT( Irp
->RequestorMode
!= KernelMode
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
4692 Status
= _SEH2_GetExceptionCode();
4694 FatRaiseStatus( IrpContext
,
4695 FsRtlIsNtstatusExpected(Status
) ?
4696 Status
: STATUS_INVALID_USER_BUFFER
);
4701 FatReleaseVcb( IrpContext
, Vcb
);
4704 Irp
->IoStatus
.Information
= FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
) +
4707 FatCompleteRequest( IrpContext
, Irp
, Status
);
4709 DebugTrace(-1, Dbg
, "FatGetVolumeBitmap -> VOID\n", 0);
4716 // Local Support Routine
4720 FatGetRetrievalPointers (
4721 IN PIRP_CONTEXT IrpContext
,
4727 Routine Description:
4729 This routine scans the MCB and builds an extent list. The first run in
4730 the output extent list will start at the begining of the contiguous
4731 run specified by the input parameter.
4733 Input = STARTING_VCN_INPUT_BUFFER;
4734 Output = RETRIEVAL_POINTERS_BUFFER.
4738 Irp - Supplies the Irp being processed.
4742 NTSTATUS - The return status for the operation.
4747 PIO_STACK_LOCATION IrpSp
;
4752 TYPE_OF_OPEN TypeOfOpen
;
4756 ULONG AllocationSize
;
4761 LARGE_INTEGER StartingVcn
;
4763 ULONG InputBufferLength
;
4764 ULONG OutputBufferLength
;
4766 PRETRIEVAL_POINTERS_BUFFER OutputBuffer
;
4771 // Get the current Irp stack location and save some references.
4774 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
4776 DebugTrace(+1, Dbg
, "FatGetRetrievalPointers, FsControlCode = %08lx\n",
4777 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
);
4780 // Extract and decode the file object and check for type of open.
4783 TypeOfOpen
= FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &FcbOrDcb
, &Ccb
);
4785 if ((TypeOfOpen
!= UserFileOpen
) && (TypeOfOpen
!= UserDirectoryOpen
)) {
4787 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
4788 return STATUS_INVALID_PARAMETER
;
4792 // Get the input and output buffer lengths and pointers.
4793 // Initialize some variables.
4796 InputBufferLength
= IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
;
4797 OutputBufferLength
= IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
;
4799 OutputBuffer
= (PRETRIEVAL_POINTERS_BUFFER
)FatMapUserBuffer( IrpContext
, Irp
);
4802 // Check for a minimum length on the input and ouput buffers.
4805 if ((InputBufferLength
< sizeof(STARTING_VCN_INPUT_BUFFER
)) ||
4806 (OutputBufferLength
< sizeof(RETRIEVAL_POINTERS_BUFFER
))) {
4808 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
4809 return STATUS_BUFFER_TOO_SMALL
;
4813 // Acquire the Fcb and enqueue the Irp if we didn't get access. Go for
4814 // shared on read-only media so we can allow prototype XIP to get
4815 // recursive, as well as recognizing this is safe anyway.
4818 if (FlagOn( FcbOrDcb
->Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
)) {
4820 FcbLocked
= FatAcquireSharedFcb( IrpContext
, FcbOrDcb
);
4824 FcbLocked
= FatAcquireExclusiveFcb( IrpContext
, FcbOrDcb
);
4829 DebugTrace( 0, Dbg
, "Cannot acquire Vcb\n", 0);
4831 ASSERT( Irp
->RequestorMode
== KernelMode
);
4833 Status
= FatFsdPostRequest( IrpContext
, Irp
);
4835 DebugTrace(-1, Dbg
, "FatGetRetrievalPointers -> %08lx\n", Status
);
4842 // Verify the Fcb is still OK
4845 FatVerifyFcb( IrpContext
, FcbOrDcb
);
4848 // If we haven't yet set the correct AllocationSize, do so.
4851 if (FcbOrDcb
->Header
.AllocationSize
.QuadPart
== FCB_LOOKUP_ALLOCATIONSIZE_HINT
) {
4853 FatLookupFileAllocationSize( IrpContext
, FcbOrDcb
);
4856 // If this is a non-root directory, we have a bit more to
4857 // do since it has not gone through FatOpenDirectoryFile().
4860 if (NodeType(FcbOrDcb
) == FAT_NTC_DCB
||
4861 (NodeType(FcbOrDcb
) == FAT_NTC_ROOT_DCB
&& FatIsFat32(Vcb
))) {
4863 FcbOrDcb
->Header
.FileSize
.LowPart
=
4864 FcbOrDcb
->Header
.AllocationSize
.LowPart
;
4869 // Check if a starting cluster was specified.
4872 ClusterShift
= Vcb
->AllocationSupport
.LogOfBytesPerCluster
;
4873 AllocationSize
= FcbOrDcb
->Header
.AllocationSize
.LowPart
;
4877 if (Irp
->RequestorMode
!= KernelMode
) {
4879 ProbeForRead( IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
,
4883 ProbeForWrite( OutputBuffer
, OutputBufferLength
, sizeof(UCHAR
) );
4886 StartingVcn
= ((PSTARTING_VCN_INPUT_BUFFER
)IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
)->StartingVcn
;
4888 } _SEH2_EXCEPT( Irp
->RequestorMode
!= KernelMode
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
4890 Status
= _SEH2_GetExceptionCode();
4892 FatRaiseStatus( IrpContext
,
4893 FsRtlIsNtstatusExpected(Status
) ?
4894 Status
: STATUS_INVALID_USER_BUFFER
);
4897 if (StartingVcn
.HighPart
||
4898 StartingVcn
.LowPart
>= (AllocationSize
>> ClusterShift
)) {
4900 try_return( Status
= STATUS_END_OF_FILE
);
4905 // If we don't find the run, something is very wrong.
4910 if (!FatLookupMcbEntry( FcbOrDcb
->Vcb
, &FcbOrDcb
->Mcb
,
4911 StartingVcn
.LowPart
<< ClusterShift
,
4916 FatBugCheck( (ULONG_PTR
)FcbOrDcb
, (ULONG_PTR
)&FcbOrDcb
->Mcb
, StartingVcn
.LowPart
);
4921 // Now go fill in the ouput buffer with run information
4924 RunCount
= FsRtlNumberOfRunsInLargeMcb( &FcbOrDcb
->Mcb
);
4926 for (Index
= 0, Run
= StartingRun
; Run
< RunCount
; Index
++, Run
++) {
4933 // Check for an exhausted output buffer.
4936 if ((ULONG
)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER
, Extents
[Index
+1]) > OutputBufferLength
) {
4940 // We've run out of space, so we won't be storing as many runs to the
4941 // user's buffer as we had originally planned. We need to return the
4942 // number of runs that we did have room for.
4947 OutputBuffer
->ExtentCount
= Index
;
4949 } _SEH2_EXCEPT( Irp
->RequestorMode
!= KernelMode
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
4951 Status
= _SEH2_GetExceptionCode();
4953 FatRaiseStatus( IrpContext
,
4954 FsRtlIsNtstatusExpected(Status
) ?
4955 Status
: STATUS_INVALID_USER_BUFFER
);
4958 Irp
->IoStatus
.Information
= FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER
, Extents
[Index
]);
4959 try_return( Status
= STATUS_BUFFER_OVERFLOW
);
4963 // Get the extent. If it's not there or malformed, something is very wrong.
4967 if (!FatGetNextMcbEntry(Vcb
, &FcbOrDcb
->Mcb
, Run
, &Vcn
, &Lbo
, &ByteLength
)) {
4969 if (!FatGetNextMcbEntry(Vcb
, &FcbOrDcb
->Mcb
, Run
, (PVBO
)&Vcn
, &Lbo
, &ByteLength
)) {
4971 FatBugCheck( (ULONG_PTR
)FcbOrDcb
, (ULONG_PTR
)&FcbOrDcb
->Mcb
, Run
);
4975 // Fill in the next array element.
4980 OutputBuffer
->Extents
[Index
].NextVcn
.QuadPart
= (Vcn
+ ByteLength
) >> ClusterShift
;
4981 OutputBuffer
->Extents
[Index
].Lcn
.QuadPart
= FatGetIndexFromLbo( Vcb
, Lbo
) - 2;
4984 // If this is the first run, fill in the starting Vcn
4988 OutputBuffer
->ExtentCount
= RunCount
- StartingRun
;
4989 OutputBuffer
->StartingVcn
.QuadPart
= Vcn
>> ClusterShift
;
4992 } _SEH2_EXCEPT( Irp
->RequestorMode
!= KernelMode
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
4994 Status
= _SEH2_GetExceptionCode();
4996 FatRaiseStatus( IrpContext
,
4997 FsRtlIsNtstatusExpected(Status
) ?
4998 Status
: STATUS_INVALID_USER_BUFFER
);
5003 // We successfully retrieved extent info to the end of the allocation.
5006 Irp
->IoStatus
.Information
= FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER
, Extents
[Index
]);
5007 Status
= STATUS_SUCCESS
;
5013 DebugUnwind( FatGetRetrievalPointers
);
5016 // Release resources
5019 FatReleaseFcb( IrpContext
, FcbOrDcb
);
5022 // If nothing raised then complete the irp.
5025 if (!_SEH2_AbnormalTermination()) {
5027 FatCompleteRequest( IrpContext
, Irp
, Status
);
5030 DebugTrace(-1, Dbg
, "FatGetRetrievalPointers -> VOID\n", 0);
5038 // Local Support Routine
5043 IN PIRP_CONTEXT IrpContext
,
5049 Routine Description:
5051 Routine moves a file to the requested Starting Lcn from Starting Vcn for the length
5052 of cluster count. These values are passed in through the the input buffer as a
5053 MOVE_DATA structure.
5055 The call must be made with a DASD handle. The file to move is passed in as a
5060 Irp - Supplies the Irp being processed.
5064 NTSTATUS - The return status for the operation.
5070 PIO_STACK_LOCATION IrpSp
;
5072 PFILE_OBJECT FileObject
;
5073 TYPE_OF_OPEN TypeOfOpen
;
5078 ULONG InputBufferLength
;
5079 PMOVE_FILE_DATA InputBuffer
;
5087 ULONG TargetCluster
;
5088 LARGE_INTEGER LargeSourceLbo
;
5089 LARGE_INTEGER LargeTargetLbo
;
5093 ULONG BytesToReallocate
;
5095 ULONG TargetAllocation
;
5098 ULONG FirstSpliceSourceCluster
;
5099 ULONG FirstSpliceTargetCluster
;
5100 ULONG SecondSpliceSourceCluster
;
5101 ULONG SecondSpliceTargetCluster
;
5103 LARGE_MCB SourceMcb
;
5104 LARGE_MCB TargetMcb
;
5111 BOOLEAN SourceMcbInitialized
= FALSE
;
5112 BOOLEAN TargetMcbInitialized
= FALSE
;
5114 BOOLEAN FcbAcquired
= FALSE
;
5115 BOOLEAN EventArmed
= FALSE
;
5116 BOOLEAN DiskSpaceAllocated
= FALSE
;
5119 PBCB DirentBcb
= NULL
;
5122 MOVE_FILE_DATA LocalMoveFileData
;
5123 PMOVE_FILE_DATA32 MoveFileData32
;
5126 ULONG LocalAbnormalTermination
= 0;
5129 // Get the current Irp stack location and save some references.
5132 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
5134 DebugTrace(+1, Dbg
, "FatMoveFile, FsControlCode = %08lx\n",
5135 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
);
5138 // Force WAIT to true. We have a handle in the input buffer which can only
5139 // be referenced within the originating process.
5142 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
5145 // Extract and decode the file object and check for type of open.
5148 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &FcbOrDcb
, &Ccb
) != UserVolumeOpen
) {
5150 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
5152 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER
);
5153 return STATUS_INVALID_PARAMETER
;
5156 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
5158 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
5160 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER
);
5161 return STATUS_INVALID_PARAMETER
;
5164 InputBufferLength
= IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
;
5165 InputBuffer
= (PMOVE_FILE_DATA
)Irp
->AssociatedIrp
.SystemBuffer
;
5168 // Do a quick check on the input buffer.
5172 if (IoIs32bitProcess( Irp
)) {
5174 if (InputBuffer
== NULL
|| InputBufferLength
< sizeof(MOVE_FILE_DATA32
)) {
5176 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
5177 return STATUS_BUFFER_TOO_SMALL
;
5180 MoveFileData32
= (PMOVE_FILE_DATA32
) InputBuffer
;
5182 LocalMoveFileData
.FileHandle
= (HANDLE
) LongToHandle( MoveFileData32
->FileHandle
);
5183 LocalMoveFileData
.StartingVcn
= MoveFileData32
->StartingVcn
;
5184 LocalMoveFileData
.StartingLcn
= MoveFileData32
->StartingLcn
;
5185 LocalMoveFileData
.ClusterCount
= MoveFileData32
->ClusterCount
;
5187 InputBuffer
= &LocalMoveFileData
;
5191 if (InputBuffer
== NULL
|| InputBufferLength
< sizeof(MOVE_FILE_DATA
)) {
5193 FatCompleteRequest( IrpContext
, Irp
, STATUS_BUFFER_TOO_SMALL
);
5194 return STATUS_BUFFER_TOO_SMALL
;
5200 MaxClusters
= Vcb
->AllocationSupport
.NumberOfClusters
;
5201 TargetCluster
= InputBuffer
->StartingLcn
.LowPart
+ 2;
5203 if (InputBuffer
->StartingVcn
.HighPart
||
5204 InputBuffer
->StartingLcn
.HighPart
||
5205 (TargetCluster
< 2) ||
5206 (TargetCluster
+ InputBuffer
->ClusterCount
< TargetCluster
) ||
5207 (TargetCluster
+ InputBuffer
->ClusterCount
> MaxClusters
+ 2) ||
5208 (InputBuffer
->StartingVcn
.LowPart
>= MaxClusters
)) {
5210 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
5212 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER
);
5213 return STATUS_INVALID_PARAMETER
;
5217 // Try to get a pointer to the file object from the handle passed in.
5220 Status
= ObReferenceObjectByHandle( InputBuffer
->FileHandle
,
5227 (PVOID
*)&FileObject
,
5231 if (!NT_SUCCESS(Status
)) {
5233 FatCompleteRequest( IrpContext
, Irp
, Status
);
5235 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", Status
);
5240 // There are three basic ways this could be an invalid attempt, so
5243 // - check that this file object is opened on the same volume as the
5244 // DASD handle used to call this routine.
5246 // - extract and decode the file object and check for type of open.
5248 // - if this is a directory, verify that it's not the root and that
5249 // we are not trying to move the first cluster. We cannot move the
5250 // first cluster because sub-directories have this cluster number
5251 // in them and there is no safe way to simultaneously update them
5254 // We'll allow movefile on the root dir if its fat32, since the root dir
5255 // is a real chained file there.
5258 if (FileObject
->Vpb
!= Vcb
->Vpb
) {
5260 ObDereferenceObject( FileObject
);
5261 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
5263 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER
);
5264 return STATUS_INVALID_PARAMETER
;
5267 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &FcbOrDcb
, &Ccb
);
5269 if ((TypeOfOpen
!= UserFileOpen
&&
5270 TypeOfOpen
!= UserDirectoryOpen
) ||
5272 ((TypeOfOpen
== UserDirectoryOpen
) &&
5273 ((NodeType(FcbOrDcb
) == FAT_NTC_ROOT_DCB
&& !FatIsFat32(Vcb
)) ||
5274 (InputBuffer
->StartingVcn
.QuadPart
== 0)))) {
5276 ObDereferenceObject( FileObject
);
5277 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
5279 DebugTrace(-1, Dbg
, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER
);
5280 return STATUS_INVALID_PARAMETER
;
5284 // Indicate we're getting to parents of this fcb by their child, and that
5285 // this is a sufficient assertion of our ability to by synchronized
5286 // with respect to the parent directory going away.
5288 // The defrag path is an example of one which arrives at an Fcb by
5289 // a means which would be unreasonable to duplicate in the assertion
5290 // code. See FatOpenDirectoryFile.
5293 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_PARENT_BY_CHILD
);
5295 ClusterShift
= Vcb
->AllocationSupport
.LogOfBytesPerCluster
;
5300 // Initialize our state variables and the event.
5303 FileOffset
= InputBuffer
->StartingVcn
.LowPart
<< ClusterShift
;
5305 ByteCount
= InputBuffer
->ClusterCount
<< ClusterShift
;
5307 TargetLbo
= FatGetLboFromIndex( Vcb
, TargetCluster
);
5308 LargeTargetLbo
.QuadPart
= TargetLbo
;
5313 // Do a quick check on parameters here
5316 if (FileOffset
+ ByteCount
< FileOffset
) {
5318 try_return( Status
= STATUS_INVALID_PARAMETER
);
5321 KeInitializeEvent( &StackEvent
, NotificationEvent
, FALSE
);
5324 // Initialize two MCBs we will be using
5327 FsRtlInitializeLargeMcb( &SourceMcb
, PagedPool
);
5328 SourceMcbInitialized
= TRUE
;
5330 FsRtlInitializeLargeMcb( &TargetMcb
, PagedPool
);
5331 TargetMcbInitialized
= TRUE
;
5334 // Ok, now if this is a directory open we need to switch to the internal
5335 // stream fileobject since it is set up for caching. The top-level
5336 // fileobject has no section object pointers in order prevent folks from
5340 if (TypeOfOpen
== UserDirectoryOpen
) {
5342 PFILE_OBJECT DirStreamFileObject
;
5345 // Open the stream fileobject if neccesary. We must acquire the Fcb
5346 // now to synchronize with other operations (such as dismount ripping
5347 // apart the allocator).
5350 (VOID
)FatAcquireExclusiveFcb( IrpContext
, FcbOrDcb
);
5353 FatVerifyFcb( IrpContext
, FcbOrDcb
);
5355 FatOpenDirectoryFile( IrpContext
, FcbOrDcb
);
5356 DirStreamFileObject
= FcbOrDcb
->Specific
.Dcb
.DirectoryFile
;
5359 // Transfer our reference to the internal stream and proceed. Note that
5360 // if we dereferenced first, the user could sneak a teardown through since
5361 // we'd have no references.
5364 ObReferenceObject( DirStreamFileObject
);
5365 ObDereferenceObject( FileObject
);
5366 FileObject
= DirStreamFileObject
;
5370 // Determine the size of the buffer we will use to move data.
5373 BufferSize
= FAT_DEFAULT_DEFRAG_CHUNK_IN_BYTES
;
5375 if (BufferSize
< (ULONG
)(1 << ClusterShift
)) {
5377 BufferSize
= (1 << ClusterShift
);
5384 ULONG TempByteCount
;
5387 // We must throttle our writes.
5390 CcCanIWrite( FileObject
,
5396 // Aqcuire file resource exclusive to freeze FileSize and block
5397 // user non-cached I/O. Verify the integrity of the fcb - the
5398 // media may have changed (or been dismounted) on us.
5401 if (FcbAcquired
== FALSE
) {
5403 (VOID
)FatAcquireExclusiveFcb( IrpContext
, FcbOrDcb
);
5406 FatVerifyFcb( IrpContext
, FcbOrDcb
);
5410 // Allocate our buffer, if we need to.
5413 if (Buffer
== NULL
) {
5415 Buffer
= FsRtlAllocatePoolWithTag( NonPagedPool
,
5417 TAG_DEFRAG_BUFFER
);
5421 // Analyzes the range of file allocation we are moving
5422 // and determines the actual amount of allocation to be
5423 // moved and how much needs to be written. In addition
5424 // it guarantees that the Mcb in the file is large enough
5425 // so that later MCB operations cannot fail.
5428 FatComputeMoveFileParameter( IrpContext
,
5438 // If ByteCount comes back zero, break here.
5441 if (ByteCount
== 0) {
5446 // At this point (before actually doing anything with the disk
5447 // meta data), calculate the FAT splice clusters and build an
5448 // MCB describing the space to be deallocated.
5451 FatComputeMoveFileSplicePoints( IrpContext
,
5456 &FirstSpliceSourceCluster
,
5457 &FirstSpliceTargetCluster
,
5458 &SecondSpliceSourceCluster
,
5459 &SecondSpliceTargetCluster
,
5463 // Now attempt to allocate the new disk storage using the
5464 // Target Lcn as a hint.
5467 TempByteCount
= BytesToReallocate
;
5468 FatAllocateDiskSpace( IrpContext
,
5475 DiskSpaceAllocated
= TRUE
;
5478 // If we didn't get EXACTLY what we wanted, return immediately.
5481 if ((FsRtlNumberOfRunsInLargeMcb( &TargetMcb
) != 1) ||
5482 !FatGetNextMcbEntry( Vcb
, &TargetMcb
, 0, &TempVbo
, &TempLbo
, &TempByteCount
) ||
5483 (FatGetIndexFromLbo( Vcb
, TempLbo
) != TargetCluster
) ||
5484 (TempByteCount
!= BytesToReallocate
)) {
5487 // It would be nice if we could be more specific, but such is life.
5489 try_return( Status
= STATUS_INVALID_PARAMETER
);
5494 // We are going to attempt a move, note it.
5497 if (FatMoveFileDebug
) {
5498 DbgPrint("%lx: Vcn 0x%lx, Lcn 0x%lx, Count 0x%lx.\n",
5499 PsGetCurrentThread(),
5500 FileOffset
>> ClusterShift
,
5502 BytesToReallocate
>> ClusterShift
);
5507 // Now attempt to commit the new allocation to disk. If this
5508 // raises, the allocation will be deallocated.
5511 FatFlushFatEntries( IrpContext
,
5514 BytesToReallocate
>> ClusterShift
);
5517 // Aqcuire both resources exclusive now, guaranteeing that NOBODY
5518 // is in either the read or write paths.
5521 ExAcquireResourceExclusiveLite( FcbOrDcb
->Header
.PagingIoResource
, TRUE
);
5524 // This is the first part of some tricky synchronization.
5526 // Set the Event pointer in the FCB. Any paging I/O will block on
5527 // this event (if set in FCB) after acquiring the PagingIo resource.
5529 // This is how I keep ALL I/O out of this path without holding the
5530 // PagingIo resource exclusive for an extended time.
5533 FcbOrDcb
->MoveFileEvent
= &StackEvent
;
5536 ExReleaseResourceLite( FcbOrDcb
->Header
.PagingIoResource
);
5539 // Now write out the data, but only if we have to. We don't have
5540 // to copy any file data if the range being reallocated is wholly
5541 // beyond valid data length.
5548 IO_STATUS_BLOCK Iosb
;
5550 KeInitializeEvent( &IoEvent
,
5554 ASSERT( LargeTargetLbo
.QuadPart
>= Vcb
->AllocationSupport
.FileAreaLbo
);
5557 // Read in the data that is being moved.
5560 IoIrp
= IoBuildSynchronousFsdRequest( IRP_MJ_READ
,
5561 Vcb
->TargetDeviceObject
,
5568 if (IoIrp
== NULL
) {
5570 FatRaiseStatus( IrpContext
,
5571 STATUS_INSUFFICIENT_RESOURCES
);
5574 Status
= IoCallDriver( Vcb
->TargetDeviceObject
,
5577 if (Status
== STATUS_PENDING
) {
5579 (VOID
)KeWaitForSingleObject( &IoEvent
,
5583 (PLARGE_INTEGER
)NULL
);
5585 Status
= Iosb
.Status
;
5588 if (!NT_SUCCESS( Status
)) {
5590 FatNormalizeAndRaiseStatus( IrpContext
,
5595 // Write the data to its new location.
5598 KeInitializeEvent( &IoEvent
, NotificationEvent
, FALSE
);
5600 IoIrp
= IoBuildSynchronousFsdRequest( IRP_MJ_WRITE
,
5601 Vcb
->TargetDeviceObject
,
5609 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
5613 // Set a flag indicating that we want to write through any
5614 // cache on the controller. This eliminates the need for
5615 // an explicit flush-device after the write.
5618 SetFlag( IoGetNextIrpStackLocation(IoIrp
)->Flags
, SL_WRITE_THROUGH
);
5620 Status
= IoCallDriver( Vcb
->TargetDeviceObject
, IoIrp
);
5622 if (Status
== STATUS_PENDING
) {
5623 (VOID
)KeWaitForSingleObject( &IoEvent
, Executive
, KernelMode
, FALSE
, (PLARGE_INTEGER
)NULL
);
5624 Status
= Iosb
.Status
;
5627 if (!NT_SUCCESS(Status
)) {
5628 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
5633 // Now that the file data has been moved successfully, we'll go
5634 // to fix up the links in the FAT table and perhaps change the
5635 // entry in the parent directory.
5637 // First we'll do the second splice and commit it. At that point,
5638 // while the volume is in an inconsistent state, the file is
5642 FatSetFatEntry( IrpContext
,
5644 SecondSpliceSourceCluster
,
5645 (FAT_ENTRY
)SecondSpliceTargetCluster
);
5647 FatFlushFatEntries( IrpContext
, Vcb
, SecondSpliceSourceCluster
, 1 );
5650 // Now do the first splice OR update the dirent in the parent
5651 // and flush the respective object. After this flush the file
5652 // now points to the new allocation.
5655 if (FirstSpliceSourceCluster
== 0) {
5657 ASSERT( NodeType(FcbOrDcb
) == FAT_NTC_FCB
);
5660 // We are moving the first cluster of the file, so we need
5661 // to update our parent directory.
5664 FatGetDirentFromFcbOrDcb( IrpContext
, FcbOrDcb
, &Dirent
, &DirentBcb
);
5665 Dirent
->FirstClusterOfFile
= (USHORT
)FirstSpliceTargetCluster
;
5667 if (FatIsFat32(Vcb
)) {
5669 Dirent
->FirstClusterOfFileHi
=
5670 (USHORT
)(FirstSpliceTargetCluster
>> 16);
5674 FatSetDirtyBcb( IrpContext
, DirentBcb
, Vcb
, TRUE
);
5676 FatUnpinBcb( IrpContext
, DirentBcb
);
5679 FatFlushDirentForFile( IrpContext
, FcbOrDcb
);
5681 FcbOrDcb
->FirstClusterOfFile
= FirstSpliceTargetCluster
;
5685 FatSetFatEntry( IrpContext
,
5687 FirstSpliceSourceCluster
,
5688 (FAT_ENTRY
)FirstSpliceTargetCluster
);
5690 FatFlushFatEntries( IrpContext
, Vcb
, FirstSpliceSourceCluster
, 1 );
5694 // This was successfully committed. We no longer want to free
5695 // this allocation on error.
5698 DiskSpaceAllocated
= FALSE
;
5701 // Now we just have to free the orphaned space. We don't have
5702 // to commit this right now as the integrity of the file doesn't
5706 FatDeallocateDiskSpace( IrpContext
, Vcb
, &SourceMcb
);
5708 FatUnpinRepinnedBcbs( IrpContext
);
5710 Status
= FatHijackIrpAndFlushDevice( IrpContext
,
5712 Vcb
->TargetDeviceObject
);
5714 if (!NT_SUCCESS(Status
)) {
5715 FatNormalizeAndRaiseStatus( IrpContext
, Status
);
5719 // Finally we must replace the old MCB extent information with
5720 // the new. If this fails from pool allocation, we fix it in
5721 // the finally clause by resetting the file's Mcb.
5724 FatRemoveMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
5726 BytesToReallocate
);
5728 FatAddMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
5731 BytesToReallocate
);
5734 // Now this is the second part of the tricky synchronization.
5736 // We drop the paging I/O here and signal the notification
5737 // event which allows all waiters (present or future) to proceed.
5738 // Then we block again on the PagingIo exclusive. When
5739 // we have it, we again know that there can be nobody in the
5740 // read/write path and thus nobody touching the event, so we
5741 // NULL the pointer to it and then drop the PagingIo resource.
5743 // This combined with our synchronization before the write above
5744 // guarantees that while we were moving the allocation, there
5745 // was no other I/O to this file and because we do not hold
5746 // the paging resource across a flush, we are not exposed to
5750 KeSetEvent( &StackEvent
, 0, FALSE
);
5752 ExAcquireResourceExclusiveLite( FcbOrDcb
->Header
.PagingIoResource
, TRUE
);
5754 FcbOrDcb
->MoveFileEvent
= NULL
;
5757 ExReleaseResourceLite( FcbOrDcb
->Header
.PagingIoResource
);
5760 // Release the resources and let anyone else access the file before
5764 FatReleaseFcb( IrpContext
, FcbOrDcb
);
5765 FcbAcquired
= FALSE
;
5768 // Advance the state variables.
5771 TargetCluster
+= BytesToReallocate
>> ClusterShift
;
5773 FileOffset
+= BytesToReallocate
;
5774 TargetLbo
+= BytesToReallocate
;
5775 ByteCount
-= BytesToReallocate
;
5777 LargeTargetLbo
.QuadPart
+= BytesToReallocate
;
5780 // Clear the two Mcbs
5783 FatRemoveMcbEntry( Vcb
, &SourceMcb
, 0, 0xFFFFFFFF );
5784 FatRemoveMcbEntry( Vcb
, &TargetMcb
, 0, 0xFFFFFFFF );
5787 // Make the event blockable again.
5790 KeClearEvent( &StackEvent
);
5793 Status
= STATUS_SUCCESS
;
5799 DebugUnwind( FatMoveFile
);
5801 LocalAbnormalTermination
|= _SEH2_AbnormalTermination();
5803 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_PARENT_BY_CHILD
);
5806 // Free the data buffer, if it was allocated.
5809 if (Buffer
!= NULL
) {
5811 ExFreePool( Buffer
);
5815 // Use a nested try-finally for cleanup if our unpinrepinned
5816 // encounters write-through errors. This may even be a re-raise.
5822 // If we have some new allocation hanging around, remove it. The
5823 // pages needed to do this are guaranteed to be resident because
5824 // we have already repinned them.
5827 if (DiskSpaceAllocated
) {
5828 FatDeallocateDiskSpace( IrpContext
, Vcb
, &TargetMcb
);
5829 FatUnpinRepinnedBcbs( IrpContext
);
5834 LocalAbnormalTermination
|= _SEH2_AbnormalTermination();
5837 // Check on the directory Bcb
5840 if (DirentBcb
!= NULL
) {
5841 FatUnpinBcb( IrpContext
, DirentBcb
);
5845 // Uninitialize our MCBs
5848 if (SourceMcbInitialized
) {
5849 FsRtlUninitializeLargeMcb( &SourceMcb
);
5852 if (TargetMcbInitialized
) {
5853 FsRtlUninitializeLargeMcb( &TargetMcb
);
5857 // If this is an abnormal termination then presumably something
5858 // bad happened. Set the Allocation size to unknown and clear
5859 // the Mcb, but only if we still own the Fcb.
5861 // It is important to make sure we use a 64bit form of -1. This is
5862 // what will convince the fastIO path that it cannot extend the file
5863 // in the cache until we have picked up the mapping pairs again.
5865 // Also, we have to do this while owning PagingIo or we can tear the
5866 // Mcb down in the midst of the noncached IO path looking up extents
5867 // (after we drop it and let them all in).
5870 if (LocalAbnormalTermination
&& FcbAcquired
) {
5872 if (FcbOrDcb
->FirstClusterOfFile
== 0) {
5874 FcbOrDcb
->Header
.AllocationSize
.QuadPart
= 0;
5877 FcbOrDcb
->Header
.AllocationSize
.QuadPart
= FCB_LOOKUP_ALLOCATIONSIZE_HINT
;
5880 FatRemoveMcbEntry( Vcb
, &FcbOrDcb
->Mcb
, 0, 0xFFFFFFFF );
5884 // If we broke out of the loop with the Event armed, defuse it
5885 // in the same way we do it after a write.
5889 KeSetEvent( &StackEvent
, 0, FALSE
);
5890 ExAcquireResourceExclusiveLite( FcbOrDcb
->Header
.PagingIoResource
, TRUE
);
5891 FcbOrDcb
->MoveFileEvent
= NULL
;
5892 ExReleaseResourceLite( FcbOrDcb
->Header
.PagingIoResource
);
5896 // Finally release the main file resource.
5900 FatReleaseFcb( IrpContext
, FcbOrDcb
);
5904 // Now dereference the fileobject. If the user was a wacko they could have
5905 // tried to nail us by closing the handle right after they threw this move
5906 // down, so we had to keep the fileobject referenced across the entire
5910 ObDereferenceObject( FileObject
);
5916 // Complete the irp if we terminated normally.
5919 FatCompleteRequest( IrpContext
, Irp
, Status
);
5926 // Local Support Routine
5930 FatComputeMoveFileParameter (
5931 IN PIRP_CONTEXT IrpContext
,
5933 IN ULONG BufferSize
,
5934 IN ULONG FileOffset
,
5935 IN OUT PULONG ByteCount
,
5936 OUT PULONG BytesToReallocate
,
5937 OUT PULONG BytesToWrite
,
5938 OUT PLARGE_INTEGER SourceLbo
5943 Routine Description:
5945 This is a helper routine for FatMoveFile that analyses the range of
5946 file allocation we are moving and determines the actual amount
5947 of allocation to be moved and how much needs to be written.
5951 FcbOrDcb - Supplies the file and its various sizes.
5953 BufferSize - Supplies the size of the buffer we are using to store the data
5956 FileOffset - Supplies the beginning Vbo of the reallocation zone.
5958 ByteCount - Supplies the request length to reallocate. This will
5959 be bounded by allocation size on return.
5961 BytesToReallocate - Receives ByteCount bounded by the file allocation size
5964 BytesToWrite - Receives BytesToReallocate bounded by ValidDataLength.
5966 SourceLbo - Receives the logical byte offset of the source data on the volume.
5977 ULONG AllocationSize
;
5978 ULONG ValidDataLength
;
5979 ULONG ClusterAlignedVDL
;
5983 BOOLEAN RunAllocated
;
5984 BOOLEAN RunEndOnMax
;
5988 // If we haven't yet set the correct AllocationSize, do so.
5991 if (FcbOrDcb
->Header
.AllocationSize
.QuadPart
== FCB_LOOKUP_ALLOCATIONSIZE_HINT
) {
5993 FatLookupFileAllocationSize( IrpContext
, FcbOrDcb
);
5996 // If this is a non-root directory, we have a bit more to
5997 // do since it has not gone through FatOpenDirectoryFile().
6000 if (NodeType(FcbOrDcb
) == FAT_NTC_DCB
||
6001 (NodeType(FcbOrDcb
) == FAT_NTC_ROOT_DCB
&& FatIsFat32(FcbOrDcb
->Vcb
))) {
6003 FcbOrDcb
->Header
.FileSize
.LowPart
=
6004 FcbOrDcb
->Header
.AllocationSize
.LowPart
;
6009 // Get the number of bytes left to write and ensure that it does
6010 // not extend beyond allocation size. We return here if FileOffset
6011 // is beyond AllocationSize which can happn on a truncation.
6014 AllocationSize
= FcbOrDcb
->Header
.AllocationSize
.LowPart
;
6015 ValidDataLength
= FcbOrDcb
->Header
.ValidDataLength
.LowPart
;
6017 if (FileOffset
+ *ByteCount
> AllocationSize
) {
6019 if (FileOffset
>= AllocationSize
) {
6021 *BytesToReallocate
= 0;
6027 *ByteCount
= AllocationSize
- FileOffset
;
6031 // If there is more than our max, then reduce the byte count for this
6032 // pass to our maximum. We must also align the file offset to a
6033 // buffer size byte boundary.
6036 if ((FileOffset
& (BufferSize
- 1)) + *ByteCount
> BufferSize
) {
6038 *BytesToReallocate
= BufferSize
- (FileOffset
& (BufferSize
- 1));
6042 *BytesToReallocate
= *ByteCount
;
6046 // Find where this data exists on the volume.
6049 FatLookupFileAllocation( IrpContext
,
6058 ASSERT( RunAllocated
);
6061 // Limit this run to the contiguous length.
6064 if (RunByteCount
< *BytesToReallocate
) {
6066 *BytesToReallocate
= RunByteCount
;
6070 // Set the starting offset of the source.
6073 SourceLbo
->QuadPart
= RunLbo
;
6076 // We may be able to skip some (or all) of the write
6077 // if allocation size is significantly greater than valid data length.
6080 ClusterSize
= 1 << FcbOrDcb
->Vcb
->AllocationSupport
.LogOfBytesPerCluster
;
6082 ASSERT( ClusterSize
<= BufferSize
);
6084 ClusterAlignedVDL
= (ValidDataLength
+ (ClusterSize
- 1)) & ~(ClusterSize
- 1);
6086 if ((NodeType(FcbOrDcb
) == FAT_NTC_FCB
) &&
6087 (FileOffset
+ *BytesToReallocate
> ClusterAlignedVDL
)) {
6089 if (FileOffset
> ClusterAlignedVDL
) {
6095 *BytesToWrite
= ClusterAlignedVDL
- FileOffset
;
6100 *BytesToWrite
= *BytesToReallocate
;
6106 // Local Support Routine
6110 FatComputeMoveFileSplicePoints (
6111 IN PIRP_CONTEXT IrpContext
,
6113 IN ULONG FileOffset
,
6114 IN ULONG TargetCluster
,
6115 IN ULONG BytesToReallocate
,
6116 OUT PULONG FirstSpliceSourceCluster
,
6117 OUT PULONG FirstSpliceTargetCluster
,
6118 OUT PULONG SecondSpliceSourceCluster
,
6119 OUT PULONG SecondSpliceTargetCluster
,
6120 IN OUT PLARGE_MCB SourceMcb
6125 Routine Description:
6127 This is a helper routine for FatMoveFile that analyzes the range of
6128 file allocation we are moving and generates the splice points in the
6133 FcbOrDcb - Supplies the file and thus Mcb.
6135 FileOffset - Supplies the beginning Vbo of the reallocation zone.
6137 TargetCluster - Supplies the beginning cluster of the reallocation target.
6139 BytesToReallocate - Suppies the length of the reallocation zone.
6141 FirstSpliceSourceCluster - Receives the last cluster in previous allocation
6142 or zero if we are reallocating from VBO 0.
6144 FirstSpliceTargetCluster - Receives the target cluster (i.e. new allocation)
6146 SecondSpliceSourceCluster - Receives the final target cluster.
6148 SecondSpliceTargetCluster - Receives the first cluster of the remaining
6149 source allocation or FAT_CLUSTER_LAST if the reallocation zone
6150 extends to the end of the file.
6152 SourceMcb - This supplies an MCB that will be filled in with run
6153 information describing the file allocation being replaced. The Mcb
6154 must be initialized by the caller.
6166 ULONG SourceBytesInRun
;
6167 ULONG SourceBytesRemaining
;
6170 ULONG SourceMcbBytesInRun
;
6174 Vcb
= FcbOrDcb
->Vcb
;
6177 // Get information on the final cluster in the previous allocation and
6178 // prepare to enumerate it in the follow loop.
6181 if (FileOffset
== 0) {
6184 *FirstSpliceSourceCluster
= 0;
6185 FatGetNextMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
6189 &SourceBytesInRun
);
6193 FatLookupMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
6199 *FirstSpliceSourceCluster
= FatGetIndexFromLbo( Vcb
, SourceLbo
);
6201 if (SourceBytesInRun
== 1) {
6204 FatGetNextMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
6212 SourceVbo
= FileOffset
;
6214 SourceBytesInRun
-= 1;
6219 // At this point the variables:
6221 // - SourceIndex - SourceLbo - SourceBytesInRun -
6223 // all correctly decribe the allocation to be removed. In the loop
6224 // below we will start here and continue enumerating the Mcb runs
6225 // until we are finished with the allocation to be relocated.
6228 *FirstSpliceTargetCluster
= TargetCluster
;
6230 *SecondSpliceSourceCluster
=
6231 *FirstSpliceTargetCluster
+
6232 (BytesToReallocate
>> Vcb
->AllocationSupport
.LogOfBytesPerCluster
) - 1;
6234 for (SourceBytesRemaining
= BytesToReallocate
, SourceMcbVbo
= 0;
6236 SourceBytesRemaining
> 0;
6239 SourceBytesRemaining
-= SourceMcbBytesInRun
,
6240 SourceMcbVbo
+= SourceMcbBytesInRun
) {
6242 if (SourceMcbVbo
!= 0) {
6243 FatGetNextMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
6247 &SourceBytesInRun
);
6250 ASSERT( SourceVbo
== SourceMcbVbo
+ FileOffset
);
6252 SourceMcbBytesInRun
=
6253 SourceBytesInRun
< SourceBytesRemaining
?
6254 SourceBytesInRun
: SourceBytesRemaining
;
6256 FatAddMcbEntry( Vcb
, SourceMcb
,
6259 SourceMcbBytesInRun
);
6263 // Now compute the cluster of the target of the second
6264 // splice. If the final run in the above loop was
6265 // more than we needed, then we can just do arithmetic,
6266 // otherwise we have to look up the next run.
6269 if (SourceMcbBytesInRun
< SourceBytesInRun
) {
6271 *SecondSpliceTargetCluster
=
6272 FatGetIndexFromLbo( Vcb
, SourceLbo
+ SourceMcbBytesInRun
);
6276 if (FatGetNextMcbEntry( Vcb
, &FcbOrDcb
->Mcb
,
6280 &SourceBytesInRun
)) {
6282 *SecondSpliceTargetCluster
= FatGetIndexFromLbo( Vcb
, SourceLbo
);
6286 *SecondSpliceTargetCluster
= FAT_CLUSTER_LAST
;
6293 FatAllowExtendedDasdIo(
6294 IN PIRP_CONTEXT IrpContext
,
6299 Routine Description:
6301 This routine marks the CCB to indicate that the handle
6302 may be used to read past the end of the volume file. The
6303 handle must be a dasd handle.
6307 Irp - Supplies the Irp being processed.
6311 NTSTATUS - The return status for the operation.
6315 PIO_STACK_LOCATION IrpSp
;
6321 // Get the current Irp stack location and save some references.
6324 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
6327 // Extract and decode the file object and check for type of open.
6330 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
6332 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
6333 return STATUS_INVALID_PARAMETER
;
6336 if ((Ccb
== NULL
) || !FlagOn( Ccb
->Flags
, CCB_FLAG_MANAGE_VOLUME_ACCESS
)) {
6338 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
6340 DebugTrace(-1, Dbg
, "FatAllowExtendedDasdIo -> %08lx\n", STATUS_INVALID_PARAMETER
);
6341 return STATUS_INVALID_PARAMETER
;
6344 SetFlag( Ccb
->Flags
, CCB_FLAG_ALLOW_EXTENDED_DASD_IO
);
6346 FatCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
6347 return STATUS_SUCCESS
;
6353 FatFlushAndCleanVolume(
6354 IN PIRP_CONTEXT IrpContext
,
6357 IN FAT_FLUSH_TYPE FlushType
6361 Routine Description:
6363 This routine flushes and otherwise preparse a volume to be eligible
6364 for deletion. The dismount and PNP paths share the need for this
6367 The Vcb will always be valid on return from this function. It is the
6368 caller's responsibility to attempt the dismount/deletion, and to setup
6369 allocation support again if the volume will be brought back from the
6374 Irp - Irp for the overlying request
6376 Vcb - the volume being operated on
6378 FlushType - specifies the kind of flushing desired
6382 NTSTATUS - The return status for the operation.
6387 // The volume must be held exclusive.
6390 ASSERT( FatVcbAcquiredExclusive( IrpContext
, Vcb
));
6393 // There is no fail, flush everything. If invalidating, it is important
6394 // that we invalidate as we flush (eventually, w/ paging io held) so that we
6395 // error out the maximum number of late writes.
6398 if (FlushType
!= NoFlush
) {
6400 (VOID
) FatFlushVolume( IrpContext
, Vcb
, FlushType
);
6403 FatCloseEaFile( IrpContext
, Vcb
, FALSE
);
6406 // Now, tell the device to flush its buffers.
6409 if (FlushType
!= NoFlush
) {
6411 (VOID
)FatHijackIrpAndFlushDevice( IrpContext
, Irp
, Vcb
->TargetDeviceObject
);
6415 // Now purge everything in sight. We're trying to provoke as many closes as
6416 // soon as possible, this volume may be on its way out.
6419 if (FlushType
!= FlushWithoutPurge
) {
6421 (VOID
) FatPurgeReferencedFileObjects( IrpContext
, Vcb
->RootDcb
, NoFlush
);
6425 // If the volume was dirty and we were allowed to flush, do the processing that
6426 // the delayed callback would have done.
6429 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
)) {
6432 // Cancel any pending clean volumes.
6435 (VOID
)KeCancelTimer( &Vcb
->CleanVolumeTimer
);
6436 (VOID
)KeRemoveQueueDpc( &Vcb
->CleanVolumeDpc
);
6439 if (FlushType
!= NoFlush
) {
6442 // The volume is now clean, note it.
6445 if (!FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
)) {
6447 FatMarkVolume( IrpContext
, Vcb
, VolumeClean
);
6448 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
);
6452 // Unlock the volume if it is removable.
6455 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
) &&
6456 !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
6458 FatToggleMediaEjectDisable( IrpContext
, Vcb
, FALSE
);
6466 FatSearchBufferForLabel(
6467 IN PIRP_CONTEXT IrpContext
,
6471 OUT PBOOLEAN LabelFound
6475 Routine Description:
6477 Search a buffer (taken from the root directory) for a volume label
6478 matching the label in the
6482 IrpContext - Supplies our irp context
6483 Vpb - Vpb supplying the volume label
6484 Buffer - Supplies the buffer we'll search
6485 Size - The size of the buffer in bytes.
6486 LabelFound - Returns whether a label was found.
6490 There are four interesting cases:
6492 1) Some random error occurred - that error returned as status, LabelFound
6495 2) No label was found - STATUS_SUCCESS returned, LabelFound is FALSE.
6497 3) A matching label was found - STATUS_SUCCESS returned, LabelFound is TRUE.
6499 4) A non-matching label found - STATUS_WRONG_VOLUME returned, LabelFound
6506 WCHAR UnicodeBuffer
[11];
6509 PDIRENT TerminationDirent
;
6510 ULONG VolumeLabelLength
;
6511 OEM_STRING OemString
;
6512 UNICODE_STRING UnicodeString
;
6516 TerminationDirent
= Dirent
+ Size
/ sizeof(DIRENT
);
6518 while ( Dirent
< TerminationDirent
) {
6520 if ( Dirent
->FileName
[0] == FAT_DIRENT_NEVER_USED
) {
6522 Dirent
= TerminationDirent
;
6527 // If the entry is the non-deleted volume label break from the loop.
6529 // Note that all out parameters are already correctly set.
6532 if (((Dirent
->Attributes
& ~FAT_DIRENT_ATTR_ARCHIVE
) ==
6533 FAT_DIRENT_ATTR_VOLUME_ID
) &&
6534 (Dirent
->FileName
[0] != FAT_DIRENT_DELETED
)) {
6542 if (Dirent
>= TerminationDirent
) {
6545 // We've run out of buffer.
6548 *LabelFound
= FALSE
;
6549 return STATUS_SUCCESS
;
6554 // Compute the length of the volume name
6558 OemString
.Buffer
= &Dirent
->FileName
[0];
6560 OemString
.Buffer
= (PCHAR
)&Dirent
->FileName
[0];
6562 OemString
.MaximumLength
= 11;
6564 for ( OemString
.Length
= 11;
6565 OemString
.Length
> 0;
6566 OemString
.Length
-= 1) {
6568 if ( (Dirent
->FileName
[OemString
.Length
-1] != 0x00) &&
6569 (Dirent
->FileName
[OemString
.Length
-1] != 0x20) ) { break; }
6572 UnicodeString
.MaximumLength
= MAXIMUM_VOLUME_LABEL_LENGTH
;
6573 UnicodeString
.Buffer
= &UnicodeBuffer
[0];
6575 Status
= RtlOemStringToCountedUnicodeString( &UnicodeString
,
6579 if ( !NT_SUCCESS( Status
) ) {
6584 VolumeLabelLength
= UnicodeString
.Length
;
6586 if ( (VolumeLabelLength
!= (ULONG
)Vpb
->VolumeLabelLength
) ||
6587 (!RtlEqualMemory(&UnicodeBuffer
[0],
6588 &Vpb
->VolumeLabel
[0],
6589 VolumeLabelLength
)) ) {
6591 return STATUS_WRONG_VOLUME
;
6595 // We found a matching label.
6599 return STATUS_SUCCESS
;
6604 FatVerifyLookupFatEntry (
6605 IN PIRP_CONTEXT IrpContext
,
6608 IN OUT PULONG FatEntry
6611 ULONG PageEntryOffset
;
6612 ULONG OffsetIntoVolumeFile
;
6615 ASSERT(Vcb
->AllocationSupport
.FatIndexBitSize
== 32);
6617 FatVerifyIndexIsValid( IrpContext
, Vcb
, FatIndex
);
6619 Buffer
= FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned
,
6621 TAG_ENTRY_LOOKUP_BUFFER
);
6623 OffsetIntoVolumeFile
= FatReservedBytes(&Vcb
->Bpb
) + FatIndex
* sizeof(ULONG
);
6624 PageEntryOffset
= (OffsetIntoVolumeFile
% PAGE_SIZE
) / sizeof(ULONG
);
6628 FatPerformVerifyDiskRead( IrpContext
,
6631 OffsetIntoVolumeFile
& ~(PAGE_SIZE
- 1),
6635 *FatEntry
= ((PULONG
)(Buffer
))[PageEntryOffset
];
6639 ExFreePool( Buffer
);
6644 // Local support routine
6648 FatScanForDismountedVcb (
6649 IN PIRP_CONTEXT IrpContext
6654 Routine Description:
6656 This routine walks through the list of Vcb's looking for any which may
6657 now be deleted. They may have been left on the list because there were
6658 outstanding references.
6676 // Walk through all of the Vcb's attached to the global data.
6679 FatAcquireExclusiveGlobal( IrpContext
);
6681 Links
= FatData
.VcbQueue
.Flink
;
6683 while (Links
!= &FatData
.VcbQueue
) {
6685 Vcb
= CONTAINING_RECORD( Links
, VCB
, VcbLinks
);
6688 // Move to the next link now since the current Vcb may be deleted.
6691 Links
= Links
->Flink
;
6694 // Try to acquire the VCB for exclusive access. If we cannot, just skip
6698 if (!ExAcquireResourceExclusiveLite( &(Vcb
->Resource
), FALSE
)) {
6704 // Check if this Vcb can go away.
6707 VcbDeleted
= FatCheckForDismount ( IrpContext
,
6712 // If the VCB was not deleted, release it.
6717 ExReleaseResourceLite( &(Vcb
->Resource
) );
6721 FatReleaseGlobal( IrpContext
);