3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/fs/vfat/fsctl.c
23 * PURPOSE: VFAT Filesystem
26 /* INCLUDES *****************************************************************/
33 extern VFAT_DISPATCH FatXDispatch
;
34 extern VFAT_DISPATCH FatDispatch
;
36 /* FUNCTIONS ****************************************************************/
38 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
39 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
44 PDEVICE_OBJECT DeviceToMount
,
45 PBOOLEAN RecognizedFS
,
50 PARTITION_INFORMATION PartitionInfo
;
51 DISK_GEOMETRY DiskGeometry
;
56 struct _BootSector
* Boot
;
57 struct _BootSectorFatX
* BootFatX
;
58 BOOLEAN PartitionInfoIsValid
= FALSE
;
60 DPRINT("VfatHasFileSystem\n");
62 *RecognizedFS
= FALSE
;
64 Size
= sizeof(DISK_GEOMETRY
);
65 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
66 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
72 if (!NT_SUCCESS(Status
))
74 DPRINT("VfatBlockDeviceIoControl failed (%x)\n", Status
);
78 FatInfo
.FixedMedia
= DiskGeometry
.MediaType
== FixedMedia
? TRUE
: FALSE
;
79 if (DiskGeometry
.MediaType
== FixedMedia
|| DiskGeometry
.MediaType
== RemovableMedia
)
81 // We have found a hard disk
82 Size
= sizeof(PARTITION_INFORMATION
);
83 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
84 IOCTL_DISK_GET_PARTITION_INFO
,
90 if (!NT_SUCCESS(Status
))
92 DPRINT("VfatBlockDeviceIoControl failed (%x)\n", Status
);
96 DPRINT("Partition Information:\n");
97 DPRINT("StartingOffset %I64x\n", PartitionInfo
.StartingOffset
.QuadPart
/ 512);
98 DPRINT("PartitionLength %I64x\n", PartitionInfo
.PartitionLength
.QuadPart
/ 512);
99 DPRINT("HiddenSectors %u\n", PartitionInfo
.HiddenSectors
);
100 DPRINT("PartitionNumber %u\n", PartitionInfo
.PartitionNumber
);
101 DPRINT("PartitionType %u\n", PartitionInfo
.PartitionType
);
102 DPRINT("BootIndicator %u\n", PartitionInfo
.BootIndicator
);
103 DPRINT("RecognizedPartition %u\n", PartitionInfo
.RecognizedPartition
);
104 DPRINT("RewritePartition %u\n", PartitionInfo
.RewritePartition
);
105 if (PartitionInfo
.PartitionType
)
107 if (PartitionInfo
.PartitionType
== PARTITION_FAT_12
||
108 PartitionInfo
.PartitionType
== PARTITION_FAT_16
||
109 PartitionInfo
.PartitionType
== PARTITION_HUGE
||
110 PartitionInfo
.PartitionType
== PARTITION_FAT32
||
111 PartitionInfo
.PartitionType
== PARTITION_FAT32_XINT13
||
112 PartitionInfo
.PartitionType
== PARTITION_XINT13
)
114 PartitionInfoIsValid
= TRUE
;
115 *RecognizedFS
= TRUE
;
118 else if (DiskGeometry
.MediaType
== RemovableMedia
&&
119 PartitionInfo
.PartitionNumber
> 0 &&
120 PartitionInfo
.StartingOffset
.QuadPart
== 0 &&
121 PartitionInfo
.PartitionLength
.QuadPart
> 0)
123 /* This is possible a removable media formated as super floppy */
124 PartitionInfoIsValid
= TRUE
;
125 *RecognizedFS
= TRUE
;
130 *RecognizedFS
= TRUE
;
135 Boot
= ExAllocatePoolWithTag(NonPagedPool
, DiskGeometry
.BytesPerSector
, TAG_BUFFER
);
138 return STATUS_INSUFFICIENT_RESOURCES
;
143 /* Try to recognize FAT12/FAT16/FAT32 partitions */
144 Status
= VfatReadDisk(DeviceToMount
, &Offset
, DiskGeometry
.BytesPerSector
, (PUCHAR
) Boot
, Override
);
145 if (NT_SUCCESS(Status
))
147 if (Boot
->Signatur1
!= 0xaa55)
149 *RecognizedFS
= FALSE
;
153 Boot
->BytesPerSector
!= 512 &&
154 Boot
->BytesPerSector
!= 1024 &&
155 Boot
->BytesPerSector
!= 2048 &&
156 Boot
->BytesPerSector
!= 4096)
158 DPRINT1("BytesPerSector %u\n", Boot
->BytesPerSector
);
159 *RecognizedFS
= FALSE
;
163 Boot
->FATCount
!= 1 &&
166 DPRINT1("FATCount %u\n", Boot
->FATCount
);
167 *RecognizedFS
= FALSE
;
171 Boot
->Media
!= 0xf0 &&
172 Boot
->Media
!= 0xf8 &&
173 Boot
->Media
!= 0xf9 &&
174 Boot
->Media
!= 0xfa &&
175 Boot
->Media
!= 0xfb &&
176 Boot
->Media
!= 0xfc &&
177 Boot
->Media
!= 0xfd &&
178 Boot
->Media
!= 0xfe &&
181 DPRINT1("Media %02x\n", Boot
->Media
);
182 *RecognizedFS
= FALSE
;
186 Boot
->SectorsPerCluster
!= 1 &&
187 Boot
->SectorsPerCluster
!= 2 &&
188 Boot
->SectorsPerCluster
!= 4 &&
189 Boot
->SectorsPerCluster
!= 8 &&
190 Boot
->SectorsPerCluster
!= 16 &&
191 Boot
->SectorsPerCluster
!= 32 &&
192 Boot
->SectorsPerCluster
!= 64 &&
193 Boot
->SectorsPerCluster
!= 128)
195 DPRINT1("SectorsPerCluster %02x\n", Boot
->SectorsPerCluster
);
196 *RecognizedFS
= FALSE
;
200 Boot
->BytesPerSector
* Boot
->SectorsPerCluster
> 64 * 1024)
202 DPRINT1("ClusterSize %d\n", Boot
->BytesPerSector
* Boot
->SectorsPerCluster
);
203 *RecognizedFS
= FALSE
;
208 FatInfo
.VolumeID
= Boot
->VolumeID
;
209 FatInfo
.FATStart
= Boot
->ReservedSectors
;
210 FatInfo
.FATCount
= Boot
->FATCount
;
211 FatInfo
.FATSectors
= Boot
->FATSectors
? Boot
->FATSectors
: ((struct _BootSector32
*) Boot
)->FATSectors32
;
212 FatInfo
.BytesPerSector
= Boot
->BytesPerSector
;
213 FatInfo
.SectorsPerCluster
= Boot
->SectorsPerCluster
;
214 FatInfo
.BytesPerCluster
= FatInfo
.BytesPerSector
* FatInfo
.SectorsPerCluster
;
215 FatInfo
.rootDirectorySectors
= ((Boot
->RootEntries
* 32) + Boot
->BytesPerSector
- 1) / Boot
->BytesPerSector
;
216 FatInfo
.rootStart
= FatInfo
.FATStart
+ FatInfo
.FATCount
* FatInfo
.FATSectors
;
217 FatInfo
.dataStart
= FatInfo
.rootStart
+ FatInfo
.rootDirectorySectors
;
218 FatInfo
.Sectors
= Sectors
= Boot
->Sectors
? Boot
->Sectors
: Boot
->SectorsHuge
;
219 Sectors
-= Boot
->ReservedSectors
+ FatInfo
.FATCount
* FatInfo
.FATSectors
+ FatInfo
.rootDirectorySectors
;
220 FatInfo
.NumberOfClusters
= Sectors
/ Boot
->SectorsPerCluster
;
221 if (FatInfo
.NumberOfClusters
< 4085)
224 FatInfo
.FatType
= FAT12
;
225 FatInfo
.RootCluster
= (FatInfo
.rootStart
- 1) / FatInfo
.SectorsPerCluster
;
226 RtlCopyMemory(&FatInfo
.VolumeLabel
, &Boot
->VolumeLabel
, sizeof(FatInfo
.VolumeLabel
));
228 else if (FatInfo
.NumberOfClusters
>= 65525)
231 FatInfo
.FatType
= FAT32
;
232 FatInfo
.RootCluster
= ((struct _BootSector32
*) Boot
)->RootCluster
;
233 FatInfo
.rootStart
= FatInfo
.dataStart
+ ((FatInfo
.RootCluster
- 2) * FatInfo
.SectorsPerCluster
);
234 FatInfo
.VolumeID
= ((struct _BootSector32
*) Boot
)->VolumeID
;
235 FatInfo
.FSInfoSector
= ((struct _BootSector32
*) Boot
)->FSInfoSector
;
236 RtlCopyMemory(&FatInfo
.VolumeLabel
, &((struct _BootSector32
*)Boot
)->VolumeLabel
, sizeof(FatInfo
.VolumeLabel
));
241 FatInfo
.FatType
= FAT16
;
242 FatInfo
.RootCluster
= FatInfo
.rootStart
/ FatInfo
.SectorsPerCluster
;
243 RtlCopyMemory(&FatInfo
.VolumeLabel
, &Boot
->VolumeLabel
, sizeof(FatInfo
.VolumeLabel
));
246 if (PartitionInfoIsValid
&&
247 FatInfo
.Sectors
> PartitionInfo
.PartitionLength
.QuadPart
/ FatInfo
.BytesPerSector
)
249 *RecognizedFS
= FALSE
;
252 if (pFatInfo
&& *RecognizedFS
)
259 ExFreePoolWithTag(Boot
, TAG_BUFFER
);
262 if (!*RecognizedFS
&& PartitionInfoIsValid
)
264 BootFatX
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(struct _BootSectorFatX
), TAG_BUFFER
);
265 if (BootFatX
== NULL
)
268 return STATUS_INSUFFICIENT_RESOURCES
;
273 /* Try to recognize FATX16/FATX32 partitions (Xbox) */
274 Status
= VfatReadDisk(DeviceToMount
, &Offset
, sizeof(struct _BootSectorFatX
), (PUCHAR
) BootFatX
, Override
);
275 if (NT_SUCCESS(Status
))
277 *RecognizedFS
= TRUE
;
278 if (BootFatX
->SysType
[0] != 'F' ||
279 BootFatX
->SysType
[1] != 'A' ||
280 BootFatX
->SysType
[2] != 'T' ||
281 BootFatX
->SysType
[3] != 'X')
283 DPRINT1("SysType %02X%02X%02X%02X (%c%c%c%c)\n",
284 BootFatX
->SysType
[0], BootFatX
->SysType
[1], BootFatX
->SysType
[2], BootFatX
->SysType
[3],
285 isprint(BootFatX
->SysType
[0]) ? BootFatX
->SysType
[0] : '.',
286 isprint(BootFatX
->SysType
[1]) ? BootFatX
->SysType
[1] : '.',
287 isprint(BootFatX
->SysType
[2]) ? BootFatX
->SysType
[2] : '.',
288 isprint(BootFatX
->SysType
[3]) ? BootFatX
->SysType
[3] : '.');
290 *RecognizedFS
= FALSE
;
294 BootFatX
->SectorsPerCluster
!= 1 &&
295 BootFatX
->SectorsPerCluster
!= 2 &&
296 BootFatX
->SectorsPerCluster
!= 4 &&
297 BootFatX
->SectorsPerCluster
!= 8 &&
298 BootFatX
->SectorsPerCluster
!= 16 &&
299 BootFatX
->SectorsPerCluster
!= 32 &&
300 BootFatX
->SectorsPerCluster
!= 64 &&
301 BootFatX
->SectorsPerCluster
!= 128)
303 DPRINT1("SectorsPerCluster %lu\n", BootFatX
->SectorsPerCluster
);
309 FatInfo
.BytesPerSector
= DiskGeometry
.BytesPerSector
;
310 FatInfo
.SectorsPerCluster
= BootFatX
->SectorsPerCluster
;
311 FatInfo
.rootDirectorySectors
= BootFatX
->SectorsPerCluster
;
312 FatInfo
.BytesPerCluster
= BootFatX
->SectorsPerCluster
* DiskGeometry
.BytesPerSector
;
313 FatInfo
.Sectors
= (ULONG
)(PartitionInfo
.PartitionLength
.QuadPart
/ DiskGeometry
.BytesPerSector
);
314 if (FatInfo
.Sectors
/ FatInfo
.SectorsPerCluster
< 65525)
317 FatInfo
.FatType
= FATX16
;
322 FatInfo
.FatType
= FATX32
;
324 FatInfo
.VolumeID
= BootFatX
->VolumeID
;
325 FatInfo
.FATStart
= sizeof(struct _BootSectorFatX
) / DiskGeometry
.BytesPerSector
;
326 FatInfo
.FATCount
= BootFatX
->FATCount
;
328 ROUND_UP(FatInfo
.Sectors
/ FatInfo
.SectorsPerCluster
* (FatInfo
.FatType
== FATX16
? 2 : 4), 4096) /
329 FatInfo
.BytesPerSector
;
330 FatInfo
.rootStart
= FatInfo
.FATStart
+ FatInfo
.FATCount
* FatInfo
.FATSectors
;
331 FatInfo
.RootCluster
= (FatInfo
.rootStart
- 1) / FatInfo
.SectorsPerCluster
;
332 FatInfo
.dataStart
= FatInfo
.rootStart
+ FatInfo
.rootDirectorySectors
;
333 FatInfo
.NumberOfClusters
= (FatInfo
.Sectors
- FatInfo
.dataStart
) / FatInfo
.SectorsPerCluster
;
335 if (pFatInfo
&& *RecognizedFS
)
341 ExFreePoolWithTag(BootFatX
, TAG_BUFFER
);
344 DPRINT("VfatHasFileSystem done\n");
349 * FUNCTION: Read the volume label
350 * WARNING: Read this comment carefully before using it (and using it wrong)
351 * Device parameter is expected to be the lower DO is start isn't 0
352 * otherwise, it is expected to be the VCB is start is 0
353 * Start parameter is expected to be, in bytes, the beginning of the root start.
354 * Set it to 0 if you wish to use the associated FCB with caching.
355 * In that specific case, Device parameter is expected to be the VCB!
356 * VolumeLabel parameter is expected to be a preallocated UNICODE_STRING (ie, with buffer)
357 * Its buffer has to be able to contain MAXIMUM_VOLUME_LABEL_LENGTH bytes
365 PUNICODE_STRING VolumeLabel
)
367 PDEVICE_EXTENSION DeviceExt
;
368 PDEVICE_OBJECT DeviceObject
;
369 PVOID Context
= NULL
;
373 LARGE_INTEGER FileOffset
;
375 ULONG EntriesPerPage
;
377 BOOLEAN NoCache
= (Start
!= 0);
379 NTSTATUS Status
= STATUS_SUCCESS
;
383 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
384 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
388 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
389 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
392 FileOffset
.QuadPart
= Start
;
397 /* FIXME: Check we really have a VCB
401 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
402 pFcb
= vfatOpenRootFCB(DeviceExt
);
403 ExReleaseResourceLite(&DeviceExt
->DirResource
);
407 CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, MAP_WAIT
, &Context
, (PVOID
*)&Entry
);
409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
411 Status
= _SEH2_GetExceptionCode();
417 DeviceObject
= Device
;
419 ASSERT(DeviceObject
->Type
== 3);
421 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_DIRENT
);
424 Status
= VfatReadDisk(DeviceObject
, &FileOffset
, PAGE_SIZE
, (PUCHAR
)Buffer
, TRUE
);
425 if (!NT_SUCCESS(Status
))
427 ExFreePoolWithTag(Buffer
, TAG_DIRENT
);
436 Status
= STATUS_INSUFFICIENT_RESOURCES
;
440 if (NT_SUCCESS(Status
))
444 if (ENTRY_VOLUME(IsFatX
, Entry
))
446 /* copy volume label */
449 StringO
.Buffer
= (PCHAR
)Entry
->FatX
.Filename
;
450 StringO
.MaximumLength
= StringO
.Length
= Entry
->FatX
.FilenameLength
;
451 RtlOemStringToUnicodeString(VolumeLabel
, &StringO
, FALSE
);
455 vfat8Dot3ToString(&Entry
->Fat
, VolumeLabel
);
459 if (ENTRY_END(IsFatX
, Entry
))
464 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
465 if ((DirIndex
% EntriesPerPage
) == 0)
467 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
471 CcUnpinData(Context
);
475 CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, MAP_WAIT
, &Context
, (PVOID
*)&Entry
);
477 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
479 Status
= _SEH2_GetExceptionCode();
482 if (!NT_SUCCESS(Status
))
490 Status
= VfatReadDisk(DeviceObject
, &FileOffset
, PAGE_SIZE
, (PUCHAR
)Buffer
, TRUE
);
491 if (!NT_SUCCESS(Status
))
501 CcUnpinData(Context
);
505 ExFreePoolWithTag(Buffer
, TAG_DIRENT
);
511 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
512 vfatReleaseFCB(DeviceExt
, pFcb
);
513 ExReleaseResourceLite(&DeviceExt
->DirResource
);
516 return STATUS_SUCCESS
;
521 * FUNCTION: Mount the filesystem
526 PVFAT_IRP_CONTEXT IrpContext
)
528 PDEVICE_OBJECT DeviceObject
= NULL
;
529 PDEVICE_EXTENSION DeviceExt
= NULL
;
530 BOOLEAN RecognizedFS
;
533 PVFATFCB VolumeFcb
= NULL
;
534 PDEVICE_OBJECT DeviceToMount
;
536 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\$$Fat$$");
537 UNICODE_STRING VolumeNameU
= RTL_CONSTANT_STRING(L
"\\$$Volume$$");
538 UNICODE_STRING VolumeLabelU
;
544 DPRINT("VfatMount(IrpContext %p)\n", IrpContext
);
548 if (IrpContext
->DeviceObject
!= VfatGlobalData
->DeviceObject
)
550 Status
= STATUS_INVALID_DEVICE_REQUEST
;
554 DeviceToMount
= IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
;
555 Vpb
= IrpContext
->Stack
->Parameters
.MountVolume
.Vpb
;
557 Status
= VfatHasFileSystem(DeviceToMount
, &RecognizedFS
, &FatInfo
, FALSE
);
558 if (!NT_SUCCESS(Status
))
563 if (RecognizedFS
== FALSE
)
565 DPRINT("VFAT: Unrecognized Volume\n");
566 Status
= STATUS_UNRECOGNIZED_VOLUME
;
570 /* Use prime numbers for the table size */
571 if (FatInfo
.FatType
== FAT12
)
573 HashTableSize
= 4099; // 4096 = 4 * 1024
575 else if (FatInfo
.FatType
== FAT16
||
576 FatInfo
.FatType
== FATX16
)
578 HashTableSize
= 16411; // 16384 = 16 * 1024
582 HashTableSize
= 65537; // 65536 = 64 * 1024;
584 DPRINT("VFAT: Recognized volume\n");
585 Status
= IoCreateDevice(VfatGlobalData
->DriverObject
,
586 ROUND_UP(sizeof (DEVICE_EXTENSION
), sizeof(ULONG
)) + sizeof(HASHENTRY
*) * HashTableSize
,
588 FILE_DEVICE_DISK_FILE_SYSTEM
,
589 DeviceToMount
->Characteristics
,
592 if (!NT_SUCCESS(Status
))
597 DeviceExt
= DeviceObject
->DeviceExtension
;
598 RtlZeroMemory(DeviceExt
, ROUND_UP(sizeof(DEVICE_EXTENSION
), sizeof(ULONG
)) + sizeof(HASHENTRY
*) * HashTableSize
);
599 DeviceExt
->FcbHashTable
= (HASHENTRY
**)((ULONG_PTR
)DeviceExt
+ ROUND_UP(sizeof(DEVICE_EXTENSION
), sizeof(ULONG
)));
600 DeviceExt
->HashTableSize
= HashTableSize
;
601 DeviceExt
->VolumeDevice
= DeviceObject
;
603 KeInitializeSpinLock(&DeviceExt
->OverflowQueueSpinLock
);
604 InitializeListHead(&DeviceExt
->OverflowQueue
);
605 DeviceExt
->OverflowQueueCount
= 0;
606 DeviceExt
->PostedRequestCount
= 0;
608 /* use same vpb as device disk */
609 DeviceObject
->Vpb
= Vpb
;
610 DeviceToMount
->Vpb
= Vpb
;
612 RtlCopyMemory(&DeviceExt
->FatInfo
, &FatInfo
, sizeof(FATINFO
));
614 DPRINT("BytesPerSector: %u\n", DeviceExt
->FatInfo
.BytesPerSector
);
615 DPRINT("SectorsPerCluster: %u\n", DeviceExt
->FatInfo
.SectorsPerCluster
);
616 DPRINT("FATCount: %u\n", DeviceExt
->FatInfo
.FATCount
);
617 DPRINT("FATSectors: %u\n", DeviceExt
->FatInfo
.FATSectors
);
618 DPRINT("RootStart: %u\n", DeviceExt
->FatInfo
.rootStart
);
619 DPRINT("DataStart: %u\n", DeviceExt
->FatInfo
.dataStart
);
620 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
622 DPRINT("RootCluster: %u\n", DeviceExt
->FatInfo
.RootCluster
);
625 switch (DeviceExt
->FatInfo
.FatType
)
628 DeviceExt
->GetNextCluster
= FAT12GetNextCluster
;
629 DeviceExt
->FindAndMarkAvailableCluster
= FAT12FindAndMarkAvailableCluster
;
630 DeviceExt
->WriteCluster
= FAT12WriteCluster
;
631 /* We don't define dirty bit functions here
632 * FAT12 doesn't have such bit and they won't get called
638 DeviceExt
->GetNextCluster
= FAT16GetNextCluster
;
639 DeviceExt
->FindAndMarkAvailableCluster
= FAT16FindAndMarkAvailableCluster
;
640 DeviceExt
->WriteCluster
= FAT16WriteCluster
;
641 DeviceExt
->GetDirtyStatus
= FAT16GetDirtyStatus
;
642 DeviceExt
->SetDirtyStatus
= FAT16SetDirtyStatus
;
647 DeviceExt
->GetNextCluster
= FAT32GetNextCluster
;
648 DeviceExt
->FindAndMarkAvailableCluster
= FAT32FindAndMarkAvailableCluster
;
649 DeviceExt
->WriteCluster
= FAT32WriteCluster
;
650 DeviceExt
->GetDirtyStatus
= FAT32GetDirtyStatus
;
651 DeviceExt
->SetDirtyStatus
= FAT32SetDirtyStatus
;
655 if (DeviceExt
->FatInfo
.FatType
== FATX16
||
656 DeviceExt
->FatInfo
.FatType
== FATX32
)
658 DeviceExt
->Flags
|= VCB_IS_FATX
;
659 DeviceExt
->BaseDateYear
= 2000;
660 RtlCopyMemory(&DeviceExt
->Dispatch
, &FatXDispatch
, sizeof(VFAT_DISPATCH
));
664 DeviceExt
->BaseDateYear
= 1980;
665 RtlCopyMemory(&DeviceExt
->Dispatch
, &FatDispatch
, sizeof(VFAT_DISPATCH
));
668 DeviceExt
->StorageDevice
= DeviceToMount
;
669 DeviceExt
->StorageDevice
->Vpb
->DeviceObject
= DeviceObject
;
670 DeviceExt
->StorageDevice
->Vpb
->RealDevice
= DeviceExt
->StorageDevice
;
671 DeviceExt
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
672 DeviceObject
->StackSize
= DeviceExt
->StorageDevice
->StackSize
+ 1;
673 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
675 DPRINT("FsDeviceObject %p\n", DeviceObject
);
677 /* Initialize this resource early ... it's used in VfatCleanup */
678 ExInitializeResourceLite(&DeviceExt
->DirResource
);
680 DeviceExt
->IoVPB
= DeviceObject
->Vpb
;
681 DeviceExt
->SpareVPB
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(VPB
), TAG_VPB
);
682 if (DeviceExt
->SpareVPB
== NULL
)
684 Status
= STATUS_INSUFFICIENT_RESOURCES
;
688 DeviceExt
->Statistics
= ExAllocatePoolWithTag(NonPagedPool
,
689 sizeof(STATISTICS
) * VfatGlobalData
->NumberProcessors
,
691 if (DeviceExt
->Statistics
== NULL
)
693 Status
= STATUS_INSUFFICIENT_RESOURCES
;
697 RtlZeroMemory(DeviceExt
->Statistics
, sizeof(STATISTICS
) * VfatGlobalData
->NumberProcessors
);
698 for (i
= 0; i
< VfatGlobalData
->NumberProcessors
; ++i
)
700 DeviceExt
->Statistics
[i
].Base
.FileSystemType
= FILESYSTEM_STATISTICS_TYPE_FAT
;
701 DeviceExt
->Statistics
[i
].Base
.Version
= 1;
702 DeviceExt
->Statistics
[i
].Base
.SizeOfCompleteStructure
= sizeof(STATISTICS
);
705 DeviceExt
->FATFileObject
= IoCreateStreamFileObject(NULL
, DeviceExt
->StorageDevice
);
706 Fcb
= vfatNewFCB(DeviceExt
, &NameU
);
709 Status
= STATUS_INSUFFICIENT_RESOURCES
;
713 Status
= vfatAttachFCBToFileObject(DeviceExt
, Fcb
, DeviceExt
->FATFileObject
);
714 if (!NT_SUCCESS(Status
))
717 DeviceExt
->FATFileObject
->PrivateCacheMap
= NULL
;
718 Fcb
->FileObject
= DeviceExt
->FATFileObject
;
720 Fcb
->Flags
= FCB_IS_FAT
;
721 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
;
722 Fcb
->RFCB
.ValidDataLength
= Fcb
->RFCB
.FileSize
;
723 Fcb
->RFCB
.AllocationSize
= Fcb
->RFCB
.FileSize
;
727 CcInitializeCacheMap(DeviceExt
->FATFileObject
,
728 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
730 &VfatGlobalData
->CacheMgrCallbacks
,
733 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
735 Status
= _SEH2_GetExceptionCode();
740 DeviceExt
->LastAvailableCluster
= 2;
741 CountAvailableClusters(DeviceExt
, NULL
);
742 ExInitializeResourceLite(&DeviceExt
->FatResource
);
744 InitializeListHead(&DeviceExt
->FcbListHead
);
746 VolumeFcb
= vfatNewFCB(DeviceExt
, &VolumeNameU
);
747 if (VolumeFcb
== NULL
)
749 Status
= STATUS_INSUFFICIENT_RESOURCES
;
753 VolumeFcb
->Flags
= FCB_IS_VOLUME
;
754 VolumeFcb
->RFCB
.FileSize
.QuadPart
= (LONGLONG
) DeviceExt
->FatInfo
.Sectors
* DeviceExt
->FatInfo
.BytesPerSector
;
755 VolumeFcb
->RFCB
.ValidDataLength
= VolumeFcb
->RFCB
.FileSize
;
756 VolumeFcb
->RFCB
.AllocationSize
= VolumeFcb
->RFCB
.FileSize
;
757 DeviceExt
->VolumeFcb
= VolumeFcb
;
759 ExAcquireResourceExclusiveLite(&VfatGlobalData
->VolumeListLock
, TRUE
);
760 InsertHeadList(&VfatGlobalData
->VolumeListHead
, &DeviceExt
->VolumeListEntry
);
761 ExReleaseResourceLite(&VfatGlobalData
->VolumeListLock
);
763 /* read serial number */
764 DeviceObject
->Vpb
->SerialNumber
= DeviceExt
->FatInfo
.VolumeID
;
766 /* read volume label */
767 VolumeLabelU
.Buffer
= DeviceObject
->Vpb
->VolumeLabel
;
768 VolumeLabelU
.Length
= 0;
769 VolumeLabelU
.MaximumLength
= sizeof(DeviceObject
->Vpb
->VolumeLabel
);
770 ReadVolumeLabel(DeviceExt
, 0, vfatVolumeIsFatX(DeviceExt
), &VolumeLabelU
);
771 Vpb
->VolumeLabelLength
= VolumeLabelU
.Length
;
773 /* read dirty bit status */
774 Status
= GetDirtyStatus(DeviceExt
, &Dirty
);
775 if (NT_SUCCESS(Status
))
777 /* The volume wasn't dirty, it was properly dismounted */
780 /* Mark it dirty now! */
781 SetDirtyStatus(DeviceExt
, TRUE
);
782 VolumeFcb
->Flags
|= VCB_CLEAR_DIRTY
;
786 DPRINT1("Mounting a dirty volume\n");
790 VolumeFcb
->Flags
|= VCB_IS_DIRTY
;
791 if (BooleanFlagOn(Vpb
->RealDevice
->Flags
, DO_SYSTEM_BOOT_PARTITION
))
793 SetFlag(DeviceExt
->Flags
, VCB_IS_SYS_OR_HAS_PAGE
);
796 /* Initialize the notify list and synchronization object */
797 InitializeListHead(&DeviceExt
->NotifyList
);
798 FsRtlNotifyInitializeSync(&DeviceExt
->NotifySync
);
800 /* The VCB is OK for usage */
801 SetFlag(DeviceExt
->Flags
, VCB_GOOD
);
803 /* Send the mount notification */
804 FsRtlNotifyVolumeEvent(DeviceExt
->FATFileObject
, FSRTL_VOLUME_MOUNT
);
806 DPRINT("Mount success\n");
808 Status
= STATUS_SUCCESS
;
811 if (!NT_SUCCESS(Status
))
814 if (DeviceExt
&& DeviceExt
->FATFileObject
)
816 LARGE_INTEGER Zero
= {{0,0}};
817 PVFATCCB Ccb
= (PVFATCCB
)DeviceExt
->FATFileObject
->FsContext2
;
819 CcUninitializeCacheMap(DeviceExt
->FATFileObject
,
822 ObDereferenceObject(DeviceExt
->FATFileObject
);
825 DeviceExt
->FATFileObject
= NULL
;
829 if (DeviceExt
&& DeviceExt
->SpareVPB
)
830 ExFreePoolWithTag(DeviceExt
->SpareVPB
, TAG_VPB
);
831 if (DeviceExt
&& DeviceExt
->Statistics
)
832 ExFreePoolWithTag(DeviceExt
->Statistics
, TAG_STATS
);
834 IoDeleteDevice(DeviceObject
);
842 * FUNCTION: Verify the filesystem
847 PVFAT_IRP_CONTEXT IrpContext
)
849 PDEVICE_OBJECT DeviceToVerify
;
852 BOOLEAN RecognizedFS
;
853 PDEVICE_EXTENSION DeviceExt
;
856 ULONG ChangeCount
, BufSize
= sizeof(ChangeCount
);
858 DPRINT("VfatVerify(IrpContext %p)\n", IrpContext
);
860 DeviceToVerify
= IrpContext
->Stack
->Parameters
.VerifyVolume
.DeviceObject
;
861 DeviceExt
= DeviceToVerify
->DeviceExtension
;
862 Vpb
= IrpContext
->Stack
->Parameters
.VerifyVolume
.Vpb
;
863 AllowRaw
= BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_ALLOW_RAW_MOUNT
);
865 if (!BooleanFlagOn(Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
))
867 DPRINT("Already verified\n");
868 return STATUS_SUCCESS
;
871 Status
= VfatBlockDeviceIoControl(DeviceExt
->StorageDevice
,
872 IOCTL_DISK_CHECK_VERIFY
,
878 if (!NT_SUCCESS(Status
) && Status
!= STATUS_VERIFY_REQUIRED
)
880 DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status
);
881 Status
= (AllowRaw
? STATUS_WRONG_VOLUME
: Status
);
885 Status
= VfatHasFileSystem(DeviceExt
->StorageDevice
, &RecognizedFS
, &FatInfo
, TRUE
);
886 if (!NT_SUCCESS(Status
) || RecognizedFS
== FALSE
)
888 if (NT_SUCCESS(Status
) || AllowRaw
)
890 Status
= STATUS_WRONG_VOLUME
;
893 else if (sizeof(FATINFO
) == RtlCompareMemory(&FatInfo
, &DeviceExt
->FatInfo
, sizeof(FATINFO
)))
895 WCHAR BufferU
[MAXIMUM_VOLUME_LABEL_LENGTH
/ sizeof(WCHAR
)];
896 UNICODE_STRING VolumeLabelU
;
897 UNICODE_STRING VpbLabelU
;
899 VolumeLabelU
.Buffer
= BufferU
;
900 VolumeLabelU
.Length
= 0;
901 VolumeLabelU
.MaximumLength
= sizeof(BufferU
);
902 Status
= ReadVolumeLabel(DeviceExt
->StorageDevice
, FatInfo
.rootStart
* FatInfo
.BytesPerSector
, (FatInfo
.FatType
>= FATX16
), &VolumeLabelU
);
903 if (!NT_SUCCESS(Status
))
907 Status
= STATUS_WRONG_VOLUME
;
912 VpbLabelU
.Buffer
= Vpb
->VolumeLabel
;
913 VpbLabelU
.Length
= Vpb
->VolumeLabelLength
;
914 VpbLabelU
.MaximumLength
= sizeof(Vpb
->VolumeLabel
);
916 if (RtlCompareUnicodeString(&VpbLabelU
, &VolumeLabelU
, FALSE
) != 0)
918 Status
= STATUS_WRONG_VOLUME
;
922 DPRINT1("Same volume\n");
928 Status
= STATUS_WRONG_VOLUME
;
932 Vpb
->RealDevice
->Flags
&= ~DO_VERIFY_VOLUME
;
941 PVFAT_IRP_CONTEXT IrpContext
)
943 DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext
);
944 return STATUS_INVALID_DEVICE_REQUEST
;
950 VfatGetRetrievalPointers(
951 PVFAT_IRP_CONTEXT IrpContext
)
953 PIO_STACK_LOCATION Stack
;
955 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
956 PFILE_OBJECT FileObject
;
957 ULONG MaxExtentCount
;
959 PDEVICE_EXTENSION DeviceExt
;
961 ULONG CurrentCluster
;
965 DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext
);
967 DeviceExt
= IrpContext
->DeviceExt
;
968 FileObject
= IrpContext
->FileObject
;
969 Stack
= IrpContext
->Stack
;
970 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(STARTING_VCN_INPUT_BUFFER
) ||
971 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
== NULL
)
973 return STATUS_INVALID_PARAMETER
;
976 if (IrpContext
->Irp
->UserBuffer
== NULL
||
977 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(RETRIEVAL_POINTERS_BUFFER
))
979 return STATUS_BUFFER_TOO_SMALL
;
982 Fcb
= FileObject
->FsContext
;
984 ExAcquireResourceSharedLite(&Fcb
->MainResource
, TRUE
);
986 Vcn
= ((PSTARTING_VCN_INPUT_BUFFER
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->StartingVcn
;
987 RetrievalPointers
= IrpContext
->Irp
->UserBuffer
;
989 MaxExtentCount
= ((Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(RetrievalPointers
->ExtentCount
) - sizeof(RetrievalPointers
->StartingVcn
)) / sizeof(RetrievalPointers
->Extents
[0]));
991 if (Vcn
.QuadPart
>= Fcb
->RFCB
.AllocationSize
.QuadPart
/ DeviceExt
->FatInfo
.BytesPerCluster
)
993 Status
= STATUS_INVALID_PARAMETER
;
997 CurrentCluster
= FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
998 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
999 Vcn
.u
.LowPart
* DeviceExt
->FatInfo
.BytesPerCluster
,
1000 &CurrentCluster
, FALSE
);
1001 if (!NT_SUCCESS(Status
))
1006 RetrievalPointers
->StartingVcn
= Vcn
;
1007 RetrievalPointers
->ExtentCount
= 0;
1008 RetrievalPointers
->Extents
[0].Lcn
.u
.HighPart
= 0;
1009 RetrievalPointers
->Extents
[0].Lcn
.u
.LowPart
= CurrentCluster
- 2;
1011 while (CurrentCluster
!= 0xffffffff && RetrievalPointers
->ExtentCount
< MaxExtentCount
)
1013 LastCluster
= CurrentCluster
;
1014 Status
= NextCluster(DeviceExt
, CurrentCluster
, &CurrentCluster
, FALSE
);
1016 if (!NT_SUCCESS(Status
))
1021 if (LastCluster
+ 1 != CurrentCluster
)
1023 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].NextVcn
= Vcn
;
1024 RetrievalPointers
->ExtentCount
++;
1025 if (RetrievalPointers
->ExtentCount
< MaxExtentCount
)
1027 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].Lcn
.u
.HighPart
= 0;
1028 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].Lcn
.u
.LowPart
= CurrentCluster
- 2;
1033 IrpContext
->Irp
->IoStatus
.Information
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + (sizeof(RetrievalPointers
->Extents
[0]) * (RetrievalPointers
->ExtentCount
- 1));
1034 Status
= STATUS_SUCCESS
;
1037 ExReleaseResourceLite(&Fcb
->MainResource
);
1045 PVFAT_IRP_CONTEXT IrpContext
)
1047 DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext
);
1048 return STATUS_INVALID_DEVICE_REQUEST
;
1054 PVFAT_IRP_CONTEXT IrpContext
)
1058 DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext
);
1060 if (IrpContext
->Stack
->Parameters
.FileSystemControl
.OutputBufferLength
!= sizeof(ULONG
))
1061 return STATUS_INVALID_BUFFER_SIZE
;
1062 else if (!IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
)
1063 return STATUS_INVALID_USER_BUFFER
;
1065 Flags
= (PULONG
)IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1068 if (BooleanFlagOn(IrpContext
->DeviceExt
->VolumeFcb
->Flags
, VCB_IS_DIRTY
) &&
1069 !BooleanFlagOn(IrpContext
->DeviceExt
->VolumeFcb
->Flags
, VCB_CLEAR_DIRTY
))
1071 *Flags
|= VOLUME_IS_DIRTY
;
1074 IrpContext
->Irp
->IoStatus
.Information
= sizeof(ULONG
);
1076 return STATUS_SUCCESS
;
1081 VfatMarkVolumeDirty(
1082 PVFAT_IRP_CONTEXT IrpContext
)
1084 PDEVICE_EXTENSION DeviceExt
;
1085 NTSTATUS Status
= STATUS_SUCCESS
;
1087 DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext
);
1088 DeviceExt
= IrpContext
->DeviceExt
;
1090 if (!BooleanFlagOn(DeviceExt
->VolumeFcb
->Flags
, VCB_IS_DIRTY
))
1092 Status
= SetDirtyStatus(DeviceExt
, TRUE
);
1095 DeviceExt
->VolumeFcb
->Flags
&= ~VCB_CLEAR_DIRTY
;
1102 VfatLockOrUnlockVolume(
1103 PVFAT_IRP_CONTEXT IrpContext
,
1106 PFILE_OBJECT FileObject
;
1107 PDEVICE_EXTENSION DeviceExt
;
1111 DPRINT("VfatLockOrUnlockVolume(%p, %d)\n", IrpContext
, Lock
);
1113 DeviceExt
= IrpContext
->DeviceExt
;
1114 FileObject
= IrpContext
->FileObject
;
1115 Fcb
= FileObject
->FsContext
;
1116 Vpb
= DeviceExt
->FATFileObject
->Vpb
;
1118 /* Only allow locking with the volume open */
1119 if (!BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
))
1121 return STATUS_ACCESS_DENIED
;
1124 /* Bail out if it's already in the demanded state */
1125 if ((BooleanFlagOn(DeviceExt
->Flags
, VCB_VOLUME_LOCKED
) && Lock
) ||
1126 (!BooleanFlagOn(DeviceExt
->Flags
, VCB_VOLUME_LOCKED
) && !Lock
))
1128 return STATUS_ACCESS_DENIED
;
1131 /* Bail out if it's already in the demanded state */
1132 if ((BooleanFlagOn(Vpb
->Flags
, VPB_LOCKED
) && Lock
) ||
1133 (!BooleanFlagOn(Vpb
->Flags
, VPB_LOCKED
) && !Lock
))
1135 return STATUS_ACCESS_DENIED
;
1140 FsRtlNotifyVolumeEvent(IrpContext
->Stack
->FileObject
, FSRTL_VOLUME_LOCK
);
1143 /* Deny locking if we're not alone */
1144 if (Lock
&& DeviceExt
->OpenHandleCount
!= 1)
1146 PLIST_ENTRY ListEntry
;
1149 /* FIXME: Hack that allows locking the system volume on
1150 * boot so that autochk can run properly
1151 * That hack is, on purpose, really restrictive
1152 * it will only allow locking with two directories
1153 * open: current directory of smss and autochk.
1155 BOOLEAN ForceLock
= TRUE
;
1156 ULONG HandleCount
= 0;
1158 /* Only allow boot volume */
1159 if (BooleanFlagOn(DeviceExt
->Flags
, VCB_IS_SYS_OR_HAS_PAGE
))
1161 /* We'll browse all the FCB */
1162 ListEntry
= DeviceExt
->FcbListHead
.Flink
;
1163 while (ListEntry
!= &DeviceExt
->FcbListHead
)
1165 Fcb
= CONTAINING_RECORD(ListEntry
, VFATFCB
, FcbListEntry
);
1166 ListEntry
= ListEntry
->Flink
;
1168 /* If no handle: that FCB is no problem for locking
1171 if (Fcb
->OpenHandleCount
== 0)
1176 /* Not a dir? We're no longer at boot */
1177 if (!vfatFCBIsDirectory(Fcb
))
1183 /* If we have cached initialized and several handles, we're
1184 not in the boot case
1186 if (Fcb
->FileObject
!= NULL
&& Fcb
->OpenHandleCount
> 1)
1192 /* Count the handles */
1193 HandleCount
+= Fcb
->OpenHandleCount
;
1194 /* More than two handles? Then, we're not booting anymore */
1195 if (HandleCount
> 2)
1207 /* Here comes the hack, ignore the failure! */
1212 DPRINT1("Can't lock: %u opened\n", DeviceExt
->OpenHandleCount
);
1214 ListEntry
= DeviceExt
->FcbListHead
.Flink
;
1215 while (ListEntry
!= &DeviceExt
->FcbListHead
)
1217 Fcb
= CONTAINING_RECORD(ListEntry
, VFATFCB
, FcbListEntry
);
1218 ListEntry
= ListEntry
->Flink
;
1220 if (Fcb
->OpenHandleCount
> 0)
1222 DPRINT1("Opened (%u - %u): %wZ\n", Fcb
->OpenHandleCount
, Fcb
->RefCount
, &Fcb
->PathNameU
);
1226 FsRtlNotifyVolumeEvent(IrpContext
->Stack
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
1228 return STATUS_ACCESS_DENIED
;
1231 /* End of the hack: be verbose about its usage,
1232 * just in case we would mess up everything!
1237 DPRINT1("HACK: Using lock-hack!\n");
1242 /* Finally, proceed */
1245 /* Flush volume & files */
1246 VfatFlushVolume(DeviceExt
, DeviceExt
->VolumeFcb
);
1248 /* The volume is now clean */
1249 if (BooleanFlagOn(DeviceExt
->VolumeFcb
->Flags
, VCB_CLEAR_DIRTY
) &&
1250 BooleanFlagOn(DeviceExt
->VolumeFcb
->Flags
, VCB_IS_DIRTY
))
1252 /* Drop the dirty bit */
1253 if (NT_SUCCESS(SetDirtyStatus(DeviceExt
, FALSE
)))
1254 ClearFlag(DeviceExt
->VolumeFcb
->Flags
, VCB_IS_DIRTY
);
1257 DeviceExt
->Flags
|= VCB_VOLUME_LOCKED
;
1258 Vpb
->Flags
|= VPB_LOCKED
;
1262 DeviceExt
->Flags
&= ~VCB_VOLUME_LOCKED
;
1263 Vpb
->Flags
&= ~VPB_LOCKED
;
1265 FsRtlNotifyVolumeEvent(IrpContext
->Stack
->FileObject
, FSRTL_VOLUME_UNLOCK
);
1268 return STATUS_SUCCESS
;
1274 PVFAT_IRP_CONTEXT IrpContext
)
1276 PDEVICE_EXTENSION DeviceExt
;
1277 PLIST_ENTRY NextEntry
;
1279 PFILE_OBJECT FileObject
;
1281 DPRINT("VfatDismountVolume(%p)\n", IrpContext
);
1283 DeviceExt
= IrpContext
->DeviceExt
;
1284 FileObject
= IrpContext
->FileObject
;
1286 /* We HAVE to be locked. Windows also allows dismount with no lock
1287 * but we're here mainly for 1st stage, so KISS
1289 if (!BooleanFlagOn(DeviceExt
->Flags
, VCB_VOLUME_LOCKED
))
1291 return STATUS_ACCESS_DENIED
;
1294 /* Deny dismount of boot volume */
1295 if (BooleanFlagOn(DeviceExt
->Flags
, VCB_IS_SYS_OR_HAS_PAGE
))
1297 return STATUS_ACCESS_DENIED
;
1300 /* Race condition? */
1301 if (BooleanFlagOn(DeviceExt
->Flags
, VCB_DISMOUNT_PENDING
))
1303 return STATUS_VOLUME_DISMOUNTED
;
1306 /* Notify we'll dismount. Pass that point there's no reason we fail */
1307 FsRtlNotifyVolumeEvent(IrpContext
->Stack
->FileObject
, FSRTL_VOLUME_DISMOUNT
);
1309 ExAcquireResourceExclusiveLite(&DeviceExt
->FatResource
, TRUE
);
1311 /* Flush volume & files */
1312 VfatFlushVolume(DeviceExt
, (PVFATFCB
)FileObject
->FsContext
);
1314 /* The volume is now clean */
1315 if (BooleanFlagOn(DeviceExt
->VolumeFcb
->Flags
, VCB_CLEAR_DIRTY
) &&
1316 BooleanFlagOn(DeviceExt
->VolumeFcb
->Flags
, VCB_IS_DIRTY
))
1318 /* Drop the dirty bit */
1319 if (NT_SUCCESS(SetDirtyStatus(DeviceExt
, FALSE
)))
1320 DeviceExt
->VolumeFcb
->Flags
&= ~VCB_IS_DIRTY
;
1323 /* Rebrowse the FCB in order to free them now */
1324 while (!IsListEmpty(&DeviceExt
->FcbListHead
))
1326 NextEntry
= RemoveTailList(&DeviceExt
->FcbListHead
);
1327 Fcb
= CONTAINING_RECORD(NextEntry
, VFATFCB
, FcbListEntry
);
1329 if (Fcb
== DeviceExt
->RootFcb
)
1330 DeviceExt
->RootFcb
= NULL
;
1331 else if (Fcb
== DeviceExt
->VolumeFcb
)
1332 DeviceExt
->VolumeFcb
= NULL
;
1334 vfatDestroyFCB(Fcb
);
1337 /* We are uninitializing, the VCB cannot be used anymore */
1338 ClearFlag(DeviceExt
->Flags
, VCB_GOOD
);
1340 /* Mark we're being dismounted */
1341 DeviceExt
->Flags
|= VCB_DISMOUNT_PENDING
;
1342 #ifndef ENABLE_SWAPOUT
1343 IrpContext
->DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
1346 ExReleaseResourceLite(&DeviceExt
->FatResource
);
1348 return STATUS_SUCCESS
;
1354 PVFAT_IRP_CONTEXT IrpContext
)
1359 PDEVICE_EXTENSION DeviceExt
;
1361 DeviceExt
= IrpContext
->DeviceExt
;
1362 Length
= IrpContext
->Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
1363 Buffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1365 if (Length
< sizeof(FILESYSTEM_STATISTICS
))
1367 return STATUS_BUFFER_TOO_SMALL
;
1372 return STATUS_INVALID_USER_BUFFER
;
1375 if (Length
>= sizeof(STATISTICS
) * VfatGlobalData
->NumberProcessors
)
1377 Length
= sizeof(STATISTICS
) * VfatGlobalData
->NumberProcessors
;
1378 Status
= STATUS_SUCCESS
;
1382 Status
= STATUS_BUFFER_OVERFLOW
;
1385 RtlCopyMemory(Buffer
, DeviceExt
->Statistics
, Length
);
1386 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1392 * FUNCTION: File system control
1395 VfatFileSystemControl(
1396 PVFAT_IRP_CONTEXT IrpContext
)
1400 DPRINT("VfatFileSystemControl(IrpContext %p)\n", IrpContext
);
1403 ASSERT(IrpContext
->Irp
);
1404 ASSERT(IrpContext
->Stack
);
1406 IrpContext
->Irp
->IoStatus
.Information
= 0;
1408 switch (IrpContext
->MinorFunction
)
1410 case IRP_MN_KERNEL_CALL
:
1411 case IRP_MN_USER_FS_REQUEST
:
1412 switch(IrpContext
->Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
1414 case FSCTL_GET_VOLUME_BITMAP
:
1415 Status
= VfatGetVolumeBitmap(IrpContext
);
1418 case FSCTL_GET_RETRIEVAL_POINTERS
:
1419 Status
= VfatGetRetrievalPointers(IrpContext
);
1422 case FSCTL_MOVE_FILE
:
1423 Status
= VfatMoveFile(IrpContext
);
1426 case FSCTL_IS_VOLUME_DIRTY
:
1427 Status
= VfatIsVolumeDirty(IrpContext
);
1430 case FSCTL_MARK_VOLUME_DIRTY
:
1431 Status
= VfatMarkVolumeDirty(IrpContext
);
1434 case FSCTL_LOCK_VOLUME
:
1435 Status
= VfatLockOrUnlockVolume(IrpContext
, TRUE
);
1438 case FSCTL_UNLOCK_VOLUME
:
1439 Status
= VfatLockOrUnlockVolume(IrpContext
, FALSE
);
1442 case FSCTL_DISMOUNT_VOLUME
:
1443 Status
= VfatDismountVolume(IrpContext
);
1446 case FSCTL_FILESYSTEM_GET_STATISTICS
:
1447 Status
= VfatGetStatistics(IrpContext
);
1451 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1455 case IRP_MN_MOUNT_VOLUME
:
1456 Status
= VfatMount(IrpContext
);
1459 case IRP_MN_VERIFY_VOLUME
:
1460 DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n");
1461 Status
= VfatVerify(IrpContext
);
1465 DPRINT("VFAT FSC: MinorFunction %u\n", IrpContext
->MinorFunction
);
1466 Status
= STATUS_INVALID_DEVICE_REQUEST
;