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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 *****************************************************************/
31 /* FUNCTIONS ****************************************************************/
33 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
34 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
36 #define VOLUME_IS_DIRTY 0x00000001
39 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount
,
40 PBOOLEAN RecognizedFS
,
44 PARTITION_INFORMATION PartitionInfo
;
45 DISK_GEOMETRY DiskGeometry
;
50 struct _BootSector
* Boot
;
51 struct _BootSectorFatX
* BootFatX
;
52 BOOLEAN PartitionInfoIsValid
= FALSE
;
54 DPRINT("VfatHasFileSystem\n");
56 *RecognizedFS
= FALSE
;
58 Size
= sizeof(DISK_GEOMETRY
);
59 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
60 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
66 if (!NT_SUCCESS(Status
))
68 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status
);
71 FatInfo
.FixedMedia
= DiskGeometry
.MediaType
== FixedMedia
? TRUE
: FALSE
;
72 if (DiskGeometry
.MediaType
== FixedMedia
|| DiskGeometry
.MediaType
== RemovableMedia
)
74 // We have found a hard disk
75 Size
= sizeof(PARTITION_INFORMATION
);
76 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
77 IOCTL_DISK_GET_PARTITION_INFO
,
83 if (!NT_SUCCESS(Status
))
85 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status
);
88 PartitionInfoIsValid
= TRUE
;
89 DPRINT("Partition Information:\n");
90 DPRINT("StartingOffset %u\n", PartitionInfo
.StartingOffset
.QuadPart
/ 512);
91 DPRINT("PartitionLength %u\n", PartitionInfo
.PartitionLength
.QuadPart
/ 512);
92 DPRINT("HiddenSectors %u\n", PartitionInfo
.HiddenSectors
);
93 DPRINT("PartitionNumber %u\n", PartitionInfo
.PartitionNumber
);
94 DPRINT("PartitionType %u\n", PartitionInfo
.PartitionType
);
95 DPRINT("BootIndicator %u\n", PartitionInfo
.BootIndicator
);
96 DPRINT("RecognizedPartition %u\n", PartitionInfo
.RecognizedPartition
);
97 DPRINT("RewritePartition %u\n", PartitionInfo
.RewritePartition
);
98 if (PartitionInfo
.PartitionType
)
100 if (PartitionInfo
.PartitionType
== PARTITION_FAT_12
||
101 PartitionInfo
.PartitionType
== PARTITION_FAT_16
||
102 PartitionInfo
.PartitionType
== PARTITION_HUGE
||
103 PartitionInfo
.PartitionType
== PARTITION_FAT32
||
104 PartitionInfo
.PartitionType
== PARTITION_FAT32_XINT13
||
105 PartitionInfo
.PartitionType
== PARTITION_XINT13
)
107 *RecognizedFS
= TRUE
;
110 else if (DiskGeometry
.MediaType
== RemovableMedia
&&
111 PartitionInfo
.PartitionNumber
> 0 &&
112 PartitionInfo
.StartingOffset
.QuadPart
== 0 &&
113 PartitionInfo
.PartitionLength
.QuadPart
> 0)
115 /* This is possible a removable media formated as super floppy */
116 *RecognizedFS
= TRUE
;
119 else if (DiskGeometry
.MediaType
== Unknown
)
122 * Floppy disk driver can return Unknown as media type if it
123 * doesn't know yet what floppy in the drive really is. This is
124 * perfectly correct to do under Windows.
126 *RecognizedFS
= TRUE
;
127 DiskGeometry
.BytesPerSector
= 512;
131 *RecognizedFS
= TRUE
;
136 Boot
= ExAllocatePoolWithTag(NonPagedPool
, DiskGeometry
.BytesPerSector
, TAG_VFAT
);
139 return STATUS_INSUFFICIENT_RESOURCES
;
144 /* Try to recognize FAT12/FAT16/FAT32 partitions */
145 Status
= VfatReadDisk(DeviceToMount
, &Offset
, DiskGeometry
.BytesPerSector
, (PUCHAR
) Boot
, FALSE
);
146 if (NT_SUCCESS(Status
))
148 if (Boot
->Signatur1
!= 0xaa55)
150 *RecognizedFS
= FALSE
;
153 Boot
->BytesPerSector
!= 512 &&
154 Boot
->BytesPerSector
!= 1024 &&
155 Boot
->BytesPerSector
!= 2048 &&
156 Boot
->BytesPerSector
!= 4096)
158 DPRINT1("BytesPerSector %d\n", Boot
->BytesPerSector
);
159 *RecognizedFS
= FALSE
;
163 Boot
->FATCount
!= 1 &&
166 DPRINT1("FATCount %d\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
> 32 * 1024)
202 DPRINT1("ClusterSize %dx\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
;
227 else if (FatInfo
.NumberOfClusters
>= 65525)
230 FatInfo
.FatType
= FAT32
;
231 FatInfo
.RootCluster
= ((struct _BootSector32
*) Boot
)->RootCluster
;
232 FatInfo
.rootStart
= FatInfo
.dataStart
+ ((FatInfo
.RootCluster
- 2) * FatInfo
.SectorsPerCluster
);
233 FatInfo
.VolumeID
= ((struct _BootSector32
*) Boot
)->VolumeID
;
238 FatInfo
.FatType
= FAT16
;
239 FatInfo
.RootCluster
= FatInfo
.rootStart
/ FatInfo
.SectorsPerCluster
;
241 if (PartitionInfoIsValid
&&
242 FatInfo
.Sectors
> PartitionInfo
.PartitionLength
.QuadPart
/ FatInfo
.BytesPerSector
)
245 *RecognizedFS
= FALSE
;
248 if (pFatInfo
&& *RecognizedFS
)
258 if (!*RecognizedFS
&& PartitionInfoIsValid
)
260 BootFatX
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(struct _BootSectorFatX
), TAG_VFAT
);
261 if (BootFatX
== NULL
)
264 return STATUS_INSUFFICIENT_RESOURCES
;
269 /* Try to recognize FATX16/FATX32 partitions (Xbox) */
270 Status
= VfatReadDisk(DeviceToMount
, &Offset
, sizeof(struct _BootSectorFatX
), (PUCHAR
) BootFatX
, FALSE
);
271 if (NT_SUCCESS(Status
))
273 *RecognizedFS
= TRUE
;
274 if (BootFatX
->SysType
[0] != 'F' ||
275 BootFatX
->SysType
[1] != 'A' ||
276 BootFatX
->SysType
[2] != 'T' ||
277 BootFatX
->SysType
[3] != 'X')
279 DPRINT1("SysType %c%c%c%c\n", BootFatX
->SysType
[0], BootFatX
->SysType
[1], BootFatX
->SysType
[2], BootFatX
->SysType
[3]);
284 BootFatX
->SectorsPerCluster
!= 1 &&
285 BootFatX
->SectorsPerCluster
!= 2 &&
286 BootFatX
->SectorsPerCluster
!= 4 &&
287 BootFatX
->SectorsPerCluster
!= 8 &&
288 BootFatX
->SectorsPerCluster
!= 16 &&
289 BootFatX
->SectorsPerCluster
!= 32 &&
290 BootFatX
->SectorsPerCluster
!= 64 &&
291 BootFatX
->SectorsPerCluster
!= 128)
293 DPRINT1("SectorsPerCluster %lu\n", BootFatX
->SectorsPerCluster
);
299 FatInfo
.BytesPerSector
= DiskGeometry
.BytesPerSector
;
300 FatInfo
.SectorsPerCluster
= BootFatX
->SectorsPerCluster
;
301 FatInfo
.rootDirectorySectors
= BootFatX
->SectorsPerCluster
;
302 FatInfo
.BytesPerCluster
= BootFatX
->SectorsPerCluster
* DiskGeometry
.BytesPerSector
;
303 FatInfo
.Sectors
= (ULONG
)(PartitionInfo
.PartitionLength
.QuadPart
/ DiskGeometry
.BytesPerSector
);
304 if (FatInfo
.Sectors
/ FatInfo
.SectorsPerCluster
< 65525)
307 FatInfo
.FatType
= FATX16
;
312 FatInfo
.FatType
= FATX32
;
314 FatInfo
.VolumeID
= BootFatX
->VolumeID
;
315 FatInfo
.FATStart
= sizeof(struct _BootSectorFatX
) / DiskGeometry
.BytesPerSector
;
316 FatInfo
.FATCount
= BootFatX
->FATCount
;
318 ROUND_UP(FatInfo
.Sectors
/ FatInfo
.SectorsPerCluster
* (FatInfo
.FatType
== FATX16
? 2 : 4), 4096) /
319 FatInfo
.BytesPerSector
;
320 FatInfo
.rootStart
= FatInfo
.FATStart
+ FatInfo
.FATCount
* FatInfo
.FATSectors
;
321 FatInfo
.RootCluster
= (FatInfo
.rootStart
- 1) / FatInfo
.SectorsPerCluster
;
322 FatInfo
.dataStart
= FatInfo
.rootStart
+ FatInfo
.rootDirectorySectors
;
323 FatInfo
.NumberOfClusters
= (FatInfo
.Sectors
- FatInfo
.dataStart
) / FatInfo
.SectorsPerCluster
;
325 if (pFatInfo
&& *RecognizedFS
)
331 ExFreePool(BootFatX
);
334 DPRINT("VfatHasFileSystem done\n");
339 VfatMountDevice(PDEVICE_EXTENSION DeviceExt
,
340 PDEVICE_OBJECT DeviceToMount
)
342 * FUNCTION: Mounts the device
346 BOOLEAN RecognizedFS
;
348 DPRINT("Mounting VFAT device...\n");
350 Status
= VfatHasFileSystem(DeviceToMount
, &RecognizedFS
, &DeviceExt
->FatInfo
);
351 if (!NT_SUCCESS(Status
))
355 DPRINT("MountVfatdev %d, PAGE_SIZE = %d\n", DeviceExt
->FatInfo
.BytesPerCluster
, PAGE_SIZE
);
358 return(STATUS_SUCCESS
);
363 VfatMount (PVFAT_IRP_CONTEXT IrpContext
)
365 * FUNCTION: Mount the filesystem
368 PDEVICE_OBJECT DeviceObject
= NULL
;
369 PDEVICE_EXTENSION DeviceExt
= NULL
;
370 BOOLEAN RecognizedFS
;
373 PVFATFCB VolumeFcb
= NULL
;
375 PDEVICE_OBJECT DeviceToMount
;
376 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\$$Fat$$");
377 UNICODE_STRING VolumeNameU
= RTL_CONSTANT_STRING(L
"\\$$Volume$$");
382 DPRINT("VfatMount(IrpContext %p)\n", IrpContext
);
386 if (IrpContext
->DeviceObject
!= VfatGlobalData
->DeviceObject
)
388 Status
= STATUS_INVALID_DEVICE_REQUEST
;
392 DeviceToMount
= IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
;
394 Status
= VfatHasFileSystem (DeviceToMount
, &RecognizedFS
, &FatInfo
);
395 if (!NT_SUCCESS(Status
))
400 if (RecognizedFS
== FALSE
)
402 DPRINT("VFAT: Unrecognized Volume\n");
403 Status
= STATUS_UNRECOGNIZED_VOLUME
;
407 /* Use prime numbers for the table size */
408 if (FatInfo
.FatType
== FAT12
)
410 HashTableSize
= 4099; // 4096 = 4 * 1024
412 else if (FatInfo
.FatType
== FAT16
||
413 FatInfo
.FatType
== FATX16
)
415 HashTableSize
= 16411; // 16384 = 16 * 1024
419 HashTableSize
= 65537; // 65536 = 64 * 1024;
421 HashTableSize
= FCB_HASH_TABLE_SIZE
;
422 DPRINT("VFAT: Recognized volume\n");
423 Status
= IoCreateDevice(VfatGlobalData
->DriverObject
,
424 ROUND_UP(sizeof (DEVICE_EXTENSION
), sizeof(ULONG
)) + sizeof(HASHENTRY
*) * HashTableSize
,
426 FILE_DEVICE_FILE_SYSTEM
,
430 if (!NT_SUCCESS(Status
))
435 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
436 DeviceExt
= (PVOID
) DeviceObject
->DeviceExtension
;
437 RtlZeroMemory(DeviceExt
, ROUND_UP(sizeof(DEVICE_EXTENSION
), sizeof(ULONG
)) + sizeof(HASHENTRY
*) * HashTableSize
);
438 DeviceExt
->FcbHashTable
= (HASHENTRY
**)((ULONG_PTR
)DeviceExt
+ ROUND_UP(sizeof(DEVICE_EXTENSION
), sizeof(ULONG
)));
439 DeviceExt
->HashTableSize
= HashTableSize
;
441 /* use same vpb as device disk */
442 DeviceObject
->Vpb
= DeviceToMount
->Vpb
;
443 Status
= VfatMountDevice(DeviceExt
, DeviceToMount
);
444 if (!NT_SUCCESS(Status
))
446 /* FIXME: delete device object */
450 DPRINT("BytesPerSector: %d\n", DeviceExt
->FatInfo
.BytesPerSector
);
451 DPRINT("SectorsPerCluster: %d\n", DeviceExt
->FatInfo
.SectorsPerCluster
);
452 DPRINT("FATCount: %d\n", DeviceExt
->FatInfo
.FATCount
);
453 DPRINT("FATSectors: %d\n", DeviceExt
->FatInfo
.FATSectors
);
454 DPRINT("RootStart: %d\n", DeviceExt
->FatInfo
.rootStart
);
455 DPRINT("DataStart: %d\n", DeviceExt
->FatInfo
.dataStart
);
456 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
458 DPRINT("RootCluster: %d\n", DeviceExt
->FatInfo
.RootCluster
);
461 switch (DeviceExt
->FatInfo
.FatType
)
464 DeviceExt
->GetNextCluster
= FAT12GetNextCluster
;
465 DeviceExt
->FindAndMarkAvailableCluster
= FAT12FindAndMarkAvailableCluster
;
466 DeviceExt
->WriteCluster
= FAT12WriteCluster
;
467 DeviceExt
->CleanShutBitMask
= 0;
472 DeviceExt
->GetNextCluster
= FAT16GetNextCluster
;
473 DeviceExt
->FindAndMarkAvailableCluster
= FAT16FindAndMarkAvailableCluster
;
474 DeviceExt
->WriteCluster
= FAT16WriteCluster
;
475 DeviceExt
->CleanShutBitMask
= 0x8000;
480 DeviceExt
->GetNextCluster
= FAT32GetNextCluster
;
481 DeviceExt
->FindAndMarkAvailableCluster
= FAT32FindAndMarkAvailableCluster
;
482 DeviceExt
->WriteCluster
= FAT32WriteCluster
;
483 DeviceExt
->CleanShutBitMask
= 0x80000000;
487 if (DeviceExt
->FatInfo
.FatType
== FATX16
488 || DeviceExt
->FatInfo
.FatType
== FATX32
)
490 DeviceExt
->Flags
|= VCB_IS_FATX
;
491 DeviceExt
->GetNextDirEntry
= FATXGetNextDirEntry
;
492 DeviceExt
->BaseDateYear
= 2000;
496 DeviceExt
->GetNextDirEntry
= FATGetNextDirEntry
;
497 DeviceExt
->BaseDateYear
= 1980;
500 DeviceExt
->StorageDevice
= DeviceToMount
;
501 DeviceExt
->StorageDevice
->Vpb
->DeviceObject
= DeviceObject
;
502 DeviceExt
->StorageDevice
->Vpb
->RealDevice
= DeviceExt
->StorageDevice
;
503 DeviceExt
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
504 DeviceObject
->StackSize
= DeviceExt
->StorageDevice
->StackSize
+ 1;
505 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
507 DPRINT("FsDeviceObject %p\n", DeviceObject
);
509 /* Initialize this resource early ... it's used in VfatCleanup */
510 ExInitializeResourceLite(&DeviceExt
->DirResource
);
512 DeviceExt
->FATFileObject
= IoCreateStreamFileObject(NULL
, DeviceExt
->StorageDevice
);
513 Fcb
= vfatNewFCB(DeviceExt
, &NameU
);
516 Status
= STATUS_INSUFFICIENT_RESOURCES
;
519 Ccb
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
522 Status
= STATUS_INSUFFICIENT_RESOURCES
;
526 RtlZeroMemory(Ccb
, sizeof (VFATCCB
));
527 DeviceExt
->FATFileObject
->FsContext
= Fcb
;
528 DeviceExt
->FATFileObject
->FsContext2
= Ccb
;
529 DeviceExt
->FATFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
530 DeviceExt
->FATFileObject
->PrivateCacheMap
= NULL
;
531 DeviceExt
->FATFileObject
->Vpb
= DeviceObject
->Vpb
;
532 Fcb
->FileObject
= DeviceExt
->FATFileObject
;
534 Fcb
->Flags
|= FCB_IS_FAT
;
536 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
;
537 Fcb
->RFCB
.ValidDataLength
= Fcb
->RFCB
.FileSize
;
538 Fcb
->RFCB
.AllocationSize
= Fcb
->RFCB
.FileSize
;
540 CcInitializeCacheMap(DeviceExt
->FATFileObject
,
541 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
543 &VfatGlobalData
->CacheMgrCallbacks
,
546 DeviceExt
->LastAvailableCluster
= 2;
547 ExInitializeResourceLite(&DeviceExt
->FatResource
);
549 InitializeListHead(&DeviceExt
->FcbListHead
);
551 VolumeFcb
= vfatNewFCB(DeviceExt
, &VolumeNameU
);
552 if (VolumeFcb
== NULL
)
554 Status
= STATUS_INSUFFICIENT_RESOURCES
;
557 VolumeFcb
->Flags
= FCB_IS_VOLUME
;
558 VolumeFcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.Sectors
* DeviceExt
->FatInfo
.BytesPerSector
;
559 VolumeFcb
->RFCB
.ValidDataLength
= VolumeFcb
->RFCB
.FileSize
;
560 VolumeFcb
->RFCB
.AllocationSize
= VolumeFcb
->RFCB
.FileSize
;
561 DeviceExt
->VolumeFcb
= VolumeFcb
;
563 ExAcquireResourceExclusiveLite(&VfatGlobalData
->VolumeListLock
, TRUE
);
564 InsertHeadList(&VfatGlobalData
->VolumeListHead
, &DeviceExt
->VolumeListEntry
);
565 ExReleaseResourceLite(&VfatGlobalData
->VolumeListLock
);
567 /* read serial number */
568 DeviceObject
->Vpb
->SerialNumber
= DeviceExt
->FatInfo
.VolumeID
;
570 /* read volume label */
571 ReadVolumeLabel(DeviceExt
, DeviceObject
->Vpb
);
573 /* read clean shutdown bit status */
574 Status
= GetNextCluster(DeviceExt
, 1, &eocMark
);
575 if (NT_SUCCESS(Status
))
577 if (eocMark
& DeviceExt
->CleanShutBitMask
)
579 /* unset clean shutdown bit */
580 eocMark
&= ~DeviceExt
->CleanShutBitMask
;
581 WriteCluster(DeviceExt
, 1, eocMark
);
582 VolumeFcb
->Flags
|= VCB_CLEAR_DIRTY
;
585 VolumeFcb
->Flags
|= VCB_IS_DIRTY
;
587 Status
= STATUS_SUCCESS
;
590 if (!NT_SUCCESS(Status
))
593 if (DeviceExt
&& DeviceExt
->FATFileObject
)
594 ObDereferenceObject (DeviceExt
->FATFileObject
);
600 IoDeleteDevice(DeviceObject
);
602 vfatDestroyFCB(VolumeFcb
);
609 VfatVerify (PVFAT_IRP_CONTEXT IrpContext
)
611 * FUNCTION: Verify the filesystem
614 PDEVICE_OBJECT DeviceToVerify
;
615 NTSTATUS Status
= STATUS_SUCCESS
;
617 BOOLEAN RecognizedFS
;
618 PDEVICE_EXTENSION DeviceExt
= IrpContext
->DeviceExt
;
620 DPRINT("VfatVerify(IrpContext %p)\n", IrpContext
);
622 DeviceToVerify
= IrpContext
->Stack
->Parameters
.VerifyVolume
.DeviceObject
;
623 Status
= VfatBlockDeviceIoControl(DeviceToVerify
,
624 IOCTL_DISK_CHECK_VERIFY
,
630 DeviceToVerify
->Flags
&= ~DO_VERIFY_VOLUME
;
631 if (!NT_SUCCESS(Status
) && Status
!= STATUS_VERIFY_REQUIRED
)
633 DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status
);
634 Status
= STATUS_WRONG_VOLUME
;
638 Status
= VfatHasFileSystem(DeviceToVerify
, &RecognizedFS
, &FatInfo
);
639 if (!NT_SUCCESS(Status
) || RecognizedFS
== FALSE
)
641 Status
= STATUS_WRONG_VOLUME
;
643 else if (sizeof(FATINFO
) == RtlCompareMemory(&FatInfo
, &DeviceExt
->FatInfo
, sizeof(FATINFO
)))
647 * Preformated floppy disks have very often a serial number of 0000:0000.
648 * We should calculate a crc sum over the sectors from the root directory as secondary volume number.
649 * Each write to the root directory must update this crc sum.
655 Status
= STATUS_WRONG_VOLUME
;
664 VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext
)
666 DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext
);
668 return STATUS_INVALID_DEVICE_REQUEST
;
673 VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext
)
675 PIO_STACK_LOCATION Stack
;
677 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
678 PFILE_OBJECT FileObject
;
679 ULONG MaxExtentCount
;
681 PDEVICE_EXTENSION DeviceExt
;
683 ULONG CurrentCluster
;
687 DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext
);
689 DeviceExt
= IrpContext
->DeviceExt
;
690 FileObject
= IrpContext
->FileObject
;
691 Stack
= IrpContext
->Stack
;
692 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(STARTING_VCN_INPUT_BUFFER
) ||
693 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
== NULL
)
695 return STATUS_INVALID_PARAMETER
;
697 if (IrpContext
->Irp
->UserBuffer
== NULL
||
698 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(RETRIEVAL_POINTERS_BUFFER
))
700 return STATUS_BUFFER_TOO_SMALL
;
703 Fcb
= FileObject
->FsContext
;
705 ExAcquireResourceSharedLite(&Fcb
->MainResource
, TRUE
);
707 Vcn
= ((PSTARTING_VCN_INPUT_BUFFER
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->StartingVcn
;
708 RetrievalPointers
= IrpContext
->Irp
->UserBuffer
;
710 MaxExtentCount
= ((Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof(RetrievalPointers
->ExtentCount
) - sizeof(RetrievalPointers
->StartingVcn
)) / sizeof(RetrievalPointers
->Extents
[0]));
713 if (Vcn
.QuadPart
>= Fcb
->RFCB
.AllocationSize
.QuadPart
/ DeviceExt
->FatInfo
.BytesPerCluster
)
715 Status
= STATUS_INVALID_PARAMETER
;
719 CurrentCluster
= FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
720 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
721 Vcn
.u
.LowPart
* DeviceExt
->FatInfo
.BytesPerCluster
,
722 &CurrentCluster
, FALSE
);
723 if (!NT_SUCCESS(Status
))
728 RetrievalPointers
->StartingVcn
= Vcn
;
729 RetrievalPointers
->ExtentCount
= 0;
730 RetrievalPointers
->Extents
[0].Lcn
.u
.HighPart
= 0;
731 RetrievalPointers
->Extents
[0].Lcn
.u
.LowPart
= CurrentCluster
- 2;
733 while (CurrentCluster
!= 0xffffffff && RetrievalPointers
->ExtentCount
< MaxExtentCount
)
736 LastCluster
= CurrentCluster
;
737 Status
= NextCluster(DeviceExt
, CurrentCluster
, &CurrentCluster
, FALSE
);
739 if (!NT_SUCCESS(Status
))
744 if (LastCluster
+ 1 != CurrentCluster
)
746 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].NextVcn
= Vcn
;
747 RetrievalPointers
->ExtentCount
++;
748 if (RetrievalPointers
->ExtentCount
< MaxExtentCount
)
750 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].Lcn
.u
.HighPart
= 0;
751 RetrievalPointers
->Extents
[RetrievalPointers
->ExtentCount
].Lcn
.u
.LowPart
= CurrentCluster
- 2;
756 IrpContext
->Irp
->IoStatus
.Information
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + (sizeof(RetrievalPointers
->Extents
[0]) * (RetrievalPointers
->ExtentCount
- 1));
757 Status
= STATUS_SUCCESS
;
760 ExReleaseResourceLite(&Fcb
->MainResource
);
766 VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext
)
768 DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext
);
770 return STATUS_INVALID_DEVICE_REQUEST
;
773 #ifdef USE_ROS_CC_AND_FS
775 VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext
)
777 PDEVICE_EXTENSION DeviceExt
;
778 PROS_QUERY_LCN_MAPPING LcnQuery
;
779 PIO_STACK_LOCATION Stack
;
781 DPRINT("VfatRosQueryLcnMapping(IrpContext %p)\n", IrpContext
);
783 DeviceExt
= IrpContext
->DeviceExt
;
784 Stack
= IrpContext
->Stack
;
785 if (IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
== NULL
||
786 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ROS_QUERY_LCN_MAPPING
))
788 return STATUS_BUFFER_TOO_SMALL
;
790 LcnQuery
= (PROS_QUERY_LCN_MAPPING
)(IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
);
791 LcnQuery
->LcnDiskOffset
.QuadPart
= DeviceExt
->FatInfo
.dataStart
* DeviceExt
->FatInfo
.BytesPerSector
;
792 IrpContext
->Irp
->IoStatus
.Information
= sizeof(ROS_QUERY_LCN_MAPPING
);
793 return(STATUS_SUCCESS
);
798 VfatIsVolumeDirty(PVFAT_IRP_CONTEXT IrpContext
)
802 DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext
);
804 if (IrpContext
->Stack
->Parameters
.FileSystemControl
.OutputBufferLength
!= sizeof(ULONG
))
805 return STATUS_INVALID_BUFFER_SIZE
;
806 else if (!IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
)
807 return STATUS_INVALID_USER_BUFFER
;
809 Flags
= (PULONG
)IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
812 if (IrpContext
->DeviceExt
->VolumeFcb
->Flags
& VCB_IS_DIRTY
813 && !(IrpContext
->DeviceExt
->VolumeFcb
->Flags
& VCB_CLEAR_DIRTY
))
815 *Flags
|= VOLUME_IS_DIRTY
;
818 return STATUS_SUCCESS
;
822 VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext
)
825 PDEVICE_EXTENSION DeviceExt
;
826 NTSTATUS Status
= STATUS_SUCCESS
;
828 DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext
);
829 DeviceExt
= IrpContext
->DeviceExt
;
831 if (!(DeviceExt
->VolumeFcb
->Flags
& VCB_IS_DIRTY
))
833 Status
= GetNextCluster(DeviceExt
, 1, &eocMark
);
834 if (NT_SUCCESS(Status
))
836 /* unset clean shutdown bit */
837 eocMark
&= ~DeviceExt
->CleanShutBitMask
;
838 Status
= WriteCluster(DeviceExt
, 1, eocMark
);
842 DeviceExt
->VolumeFcb
->Flags
&= ~VCB_CLEAR_DIRTY
;
847 NTSTATUS
VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext
)
849 * FUNCTION: File system control
855 DPRINT("VfatFileSystemControl(IrpContext %p)\n", IrpContext
);
858 ASSERT(IrpContext
->Irp
);
859 ASSERT(IrpContext
->Stack
);
861 IrpContext
->Irp
->IoStatus
.Information
= 0;
863 switch (IrpContext
->MinorFunction
)
865 case IRP_MN_USER_FS_REQUEST
:
866 switch(IrpContext
->Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
868 case FSCTL_GET_VOLUME_BITMAP
:
869 Status
= VfatGetVolumeBitmap(IrpContext
);
871 case FSCTL_GET_RETRIEVAL_POINTERS
:
872 Status
= VfatGetRetrievalPointers(IrpContext
);
874 case FSCTL_MOVE_FILE
:
875 Status
= VfatMoveFile(IrpContext
);
877 #ifdef USE_ROS_CC_AND_FS
878 case FSCTL_ROS_QUERY_LCN_MAPPING
:
879 Status
= VfatRosQueryLcnMapping(IrpContext
);
882 case FSCTL_IS_VOLUME_DIRTY
:
883 Status
= VfatIsVolumeDirty(IrpContext
);
885 case FSCTL_MARK_VOLUME_DIRTY
:
886 Status
= VfatMarkVolumeDirty(IrpContext
);
889 Status
= STATUS_INVALID_DEVICE_REQUEST
;
893 case IRP_MN_MOUNT_VOLUME
:
894 Status
= VfatMount(IrpContext
);
897 case IRP_MN_VERIFY_VOLUME
:
898 DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n");
899 Status
= VfatVerify(IrpContext
);
903 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext
->MinorFunction
);
904 Status
= STATUS_INVALID_DEVICE_REQUEST
;
908 IrpContext
->Irp
->IoStatus
.Status
= Status
;
910 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
911 VfatFreeIrpContext(IrpContext
);