1 /* $Id: fsctl.c,v 1.3 2002/05/05 20:19:14 hbirr Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/fsctl.c
6 * PURPOSE: VFAT Filesystem
9 /* INCLUDES *****************************************************************/
11 #include <ddk/ntddk.h>
19 /* FUNCTIONS ****************************************************************/
21 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGESIZE ? \
22 (pDeviceExt)->FatInfo.BytesPerCluster : PAGESIZE)
26 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount
,
27 PBOOLEAN RecognizedFS
,
31 PARTITION_INFORMATION PartitionInfo
;
32 DISK_GEOMETRY DiskGeometry
;
36 struct _BootSector
* Boot
;
38 *RecognizedFS
= FALSE
;
40 Size
= sizeof(DISK_GEOMETRY
);
41 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
42 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
47 if (!NT_SUCCESS(Status
))
49 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status
);
52 if (DiskGeometry
.MediaType
== FixedMedia
)
54 // We have found a hard disk
55 Size
= sizeof(PARTITION_INFORMATION
);
56 Status
= VfatBlockDeviceIoControl(DeviceToMount
,
57 IOCTL_DISK_GET_PARTITION_INFO
,
62 if (!NT_SUCCESS(Status
))
64 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status
);
68 DbgPrint("Partition Information:\n");
69 DbgPrint("StartingOffset %u\n", PartitionInfo
.StartingOffset
.QuadPart
/ 512);
70 DbgPrint("PartitionLength %u\n", PartitionInfo
.PartitionLength
.QuadPart
/ 512);
71 DbgPrint("HiddenSectors %u\n", PartitionInfo
.HiddenSectors
);
72 DbgPrint("PartitionNumber %u\n", PartitionInfo
.PartitionNumber
);
73 DbgPrint("PartitionType %u\n", PartitionInfo
.PartitionType
);
74 DbgPrint("BootIndicator %u\n", PartitionInfo
.BootIndicator
);
75 DbgPrint("RecognizedPartition %u\n", PartitionInfo
.RecognizedPartition
);
76 DbgPrint("RewritePartition %u\n", PartitionInfo
.RewritePartition
);
78 if (PartitionInfo
.PartitionType
== PTDOS3xPrimary
||
79 PartitionInfo
.PartitionType
== PTOLDDOS16Bit
||
80 PartitionInfo
.PartitionType
== PTDos5xPrimary
||
81 PartitionInfo
.PartitionType
== PTWin95FAT32
||
82 PartitionInfo
.PartitionType
== PTWin95FAT32LBA
||
83 PartitionInfo
.PartitionType
== PTWin95FAT16LBA
)
88 else if (DiskGeometry
.MediaType
> Unknown
&& DiskGeometry
.MediaType
< RemovableMedia
)
92 if (*RecognizedFS
== FALSE
)
94 return STATUS_SUCCESS
;
97 Boot
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
);
101 return STATUS_INSUFFICIENT_RESOURCES
;
103 Status
= VfatReadSectors(DeviceToMount
, 0, 1, (PUCHAR
) Boot
);
104 if (NT_SUCCESS(Status
))
106 FatInfo
.VolumeID
= Boot
->VolumeID
;
107 FatInfo
.FATStart
= Boot
->ReservedSectors
;
108 FatInfo
.FATCount
= Boot
->FATCount
;
109 FatInfo
.FATSectors
= Boot
->FATSectors
? Boot
->FATSectors
: ((struct _BootSector32
*) Boot
)->FATSectors32
;
110 FatInfo
.BytesPerSector
= Boot
->BytesPerSector
;
111 FatInfo
.SectorsPerCluster
= Boot
->SectorsPerCluster
;
112 FatInfo
.BytesPerCluster
= FatInfo
.BytesPerSector
* FatInfo
.SectorsPerCluster
;
113 FatInfo
.rootDirectorySectors
= ((Boot
->RootEntries
* 32) + Boot
->BytesPerSector
- 1) / Boot
->BytesPerSector
;
114 FatInfo
.rootStart
= FatInfo
.FATStart
+ FatInfo
.FATCount
* FatInfo
.FATSectors
;
115 FatInfo
.dataStart
= FatInfo
.rootStart
+ FatInfo
.rootDirectorySectors
;
116 FatInfo
.Sectors
= Sectors
= Boot
->Sectors
? Boot
->Sectors
: Boot
->SectorsHuge
;
117 Sectors
-= Boot
->ReservedSectors
+ FatInfo
.FATCount
* FatInfo
.FATSectors
+ FatInfo
.rootDirectorySectors
;
118 FatInfo
.NumberOfClusters
= Sectors
/ Boot
->SectorsPerCluster
;
119 if (FatInfo
.NumberOfClusters
< 4085)
122 FatInfo
.FatType
= FAT12
;
124 else if (FatInfo
.NumberOfClusters
>= 65525)
127 FatInfo
.FatType
= FAT32
;
128 FatInfo
.RootCluster
= ((struct _BootSector32
*) Boot
)->RootCluster
;
129 FatInfo
.rootStart
= FatInfo
.dataStart
+ ((FatInfo
.RootCluster
- 2) * FatInfo
.SectorsPerCluster
);
130 FatInfo
.VolumeID
= ((struct _BootSector32
*) Boot
)->VolumeID
;
135 FatInfo
.FatType
= FAT16
;
147 VfatMountDevice(PDEVICE_EXTENSION DeviceExt
,
148 PDEVICE_OBJECT DeviceToMount
)
150 * FUNCTION: Mounts the device
154 BOOLEAN RecognizedFS
;
156 DPRINT("Mounting VFAT device...\n");
158 Status
= VfatHasFileSystem(DeviceToMount
, &RecognizedFS
, &DeviceExt
->FatInfo
);
159 if (!NT_SUCCESS(Status
))
164 if (DeviceExt
->FatInfo
.BytesPerCluster
>= PAGESIZE
&&
165 (DeviceExt
->FatInfo
.BytesPerCluster
% PAGESIZE
) != 0)
167 DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__
, __LINE__
);
170 else if (DeviceExt
->FatInfo
.BytesPerCluster
< PAGESIZE
&&
171 (PAGESIZE
% DeviceExt
->FatInfo
.BytesPerCluster
) != 0)
173 DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__
, __LINE__
);
177 return(STATUS_SUCCESS
);
182 VfatMount (PVFAT_IRP_CONTEXT IrpContext
)
184 * FUNCTION: Mount the filesystem
187 PDEVICE_OBJECT DeviceObject
= NULL
;
188 PDEVICE_EXTENSION DeviceExt
= NULL
;
189 BOOLEAN RecognizedFS
;
192 PVFATFCB VolumeFcb
= NULL
;
194 LARGE_INTEGER timeout
;
196 DPRINT("VfatMount(IrpContext %x)\n", IrpContext
);
200 if (IrpContext
->DeviceObject
!= VfatGlobalData
->DeviceObject
)
202 Status
= STATUS_INVALID_DEVICE_REQUEST
;
206 Status
= VfatHasFileSystem (IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
, &RecognizedFS
, NULL
);
207 if (!NT_SUCCESS(Status
))
212 if (RecognizedFS
== FALSE
)
214 DPRINT("VFAT: Unrecognized Volume\n");
215 Status
= STATUS_UNRECOGNIZED_VOLUME
;
219 DPRINT("VFAT: Recognized volume\n");
220 Status
= IoCreateDevice(VfatGlobalData
->DriverObject
,
221 sizeof (DEVICE_EXTENSION
),
223 FILE_DEVICE_FILE_SYSTEM
,
227 if (!NT_SUCCESS(Status
))
232 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
233 DeviceExt
= (PVOID
) DeviceObject
->DeviceExtension
;
234 RtlZeroMemory(DeviceExt
, sizeof(DEVICE_EXTENSION
));
236 /* use same vpb as device disk */
237 DeviceObject
->Vpb
= IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
->Vpb
;
238 Status
= VfatMountDevice(DeviceExt
, IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
);
239 if (!NT_SUCCESS(Status
))
241 /* FIXME: delete device object */
246 DbgPrint("BytesPerSector: %d\n", DeviceExt
->FatInfo
.BytesPerSector
);
247 DbgPrint("SectorsPerCluster: %d\n", DeviceExt
->FatInfo
.SectorsPerCluster
);
248 DbgPrint("FATCount: %d\n", DeviceExt
->FatInfo
.FATCount
);
249 DbgPrint("FATSectors: %d\n", DeviceExt
->FatInfo
.FATSectors
);
250 DbgPrint("RootStart: %d\n", DeviceExt
->FatInfo
.rootStart
);
251 DbgPrint("DataStart: %d\n", DeviceExt
->FatInfo
.dataStart
);
252 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
254 DbgPrint("RootCluster: %d\n", DeviceExt
->FatInfo
.RootCluster
);
257 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
258 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, IrpContext
->Stack
->Parameters
.MountVolume
.DeviceObject
);
260 DeviceExt
->FATFileObject
= IoCreateStreamFileObject(NULL
, DeviceExt
->StorageDevice
);
261 Fcb
= vfatNewFCB(NULL
);
264 Status
= STATUS_INSUFFICIENT_RESOURCES
;
267 Ccb
= ExAllocatePoolWithTag (NonPagedPool
, sizeof (VFATCCB
), TAG_CCB
);
270 Status
= STATUS_INSUFFICIENT_RESOURCES
;
273 memset(Ccb
, 0, sizeof (VFATCCB
));
274 wcscpy(Fcb
->PathName
, L
"$$Fat$$");
275 Fcb
->ObjectName
= Fcb
->PathName
;
276 DeviceExt
->FATFileObject
->Flags
= DeviceExt
->FATFileObject
->Flags
| FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
277 DeviceExt
->FATFileObject
->FsContext
= (PVOID
) &Fcb
->RFCB
;
278 DeviceExt
->FATFileObject
->FsContext2
= Ccb
;
279 DeviceExt
->FATFileObject
->SectionObjectPointers
= &Fcb
->SectionObjectPointers
;
280 DeviceExt
->FATFileObject
->PrivateCacheMap
= NULL
;
281 DeviceExt
->FATFileObject
->Vpb
= DeviceObject
->Vpb
;
283 Ccb
->PtrFileObject
= DeviceExt
->FATFileObject
;
284 Fcb
->FileObject
= DeviceExt
->FATFileObject
;
285 Fcb
->pDevExt
= (PDEVICE_EXTENSION
)DeviceExt
->StorageDevice
;
287 Fcb
->Flags
= FCB_IS_FAT
;
289 if (DeviceExt
->FatInfo
.FatType
!= FAT12
)
291 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* BLOCKSIZE
;
292 Fcb
->RFCB
.ValidDataLength
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* BLOCKSIZE
;
293 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(DeviceExt
->FatInfo
.FATSectors
* BLOCKSIZE
, CACHEPAGESIZE(DeviceExt
));
294 Status
= CcRosInitializeFileCache(DeviceExt
->FATFileObject
, &Fcb
->RFCB
.Bcb
, CACHEPAGESIZE(DeviceExt
));
298 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* BLOCKSIZE
;
299 Fcb
->RFCB
.ValidDataLength
.QuadPart
= DeviceExt
->FatInfo
.FATSectors
* BLOCKSIZE
;
300 Fcb
->RFCB
.AllocationSize
.QuadPart
= 2 * PAGESIZE
;
301 Status
= CcRosInitializeFileCache(DeviceExt
->FATFileObject
, &Fcb
->RFCB
.Bcb
, 2 * PAGESIZE
);
303 if (!NT_SUCCESS (Status
))
305 DbgPrint ("CcRosInitializeFileCache failed\n");
308 DeviceExt
->LastAvailableCluster
= 0;
309 ExInitializeResourceLite(&DeviceExt
->DirResource
);
310 ExInitializeResourceLite(&DeviceExt
->FatResource
);
312 KeInitializeSpinLock(&DeviceExt
->FcbListLock
);
313 InitializeListHead(&DeviceExt
->FcbListHead
);
315 VolumeFcb
= vfatNewFCB(NULL
);
316 if (VolumeFcb
== NULL
)
318 Status
= STATUS_INSUFFICIENT_RESOURCES
;
321 wcscpy(VolumeFcb
->PathName
, L
"$$Volume$$");
322 VolumeFcb
->ObjectName
= VolumeFcb
->PathName
;
323 VolumeFcb
->Flags
= FCB_IS_VOLUME
;
324 VolumeFcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->FatInfo
.Sectors
* BLOCKSIZE
;
325 VolumeFcb
->RFCB
.ValidDataLength
= VolumeFcb
->RFCB
.FileSize
;
326 VolumeFcb
->RFCB
.AllocationSize
= VolumeFcb
->RFCB
.FileSize
;
327 VolumeFcb
->pDevExt
= (PDEVICE_EXTENSION
)DeviceExt
->StorageDevice
;
328 DeviceExt
->VolumeFcb
= VolumeFcb
;
330 /* read serial number */
331 DeviceObject
->Vpb
->SerialNumber
= DeviceExt
->FatInfo
.VolumeID
;
333 /* read volume label */
334 ReadVolumeLabel(DeviceExt
, DeviceObject
->Vpb
);
336 Status
= STATUS_SUCCESS
;
340 if (!NT_SUCCESS(Status
))
343 if (DeviceExt
&& DeviceExt
->FATFileObject
)
344 ObDereferenceObject (DeviceExt
->FATFileObject
);
350 IoDeleteDevice(DeviceObject
);
352 vfatDestroyFCB(VolumeFcb
);
359 VfatVerify (PVFAT_IRP_CONTEXT IrpContext
)
361 * FUNCTION: Mount the filesystem
364 DPRINT("VfatVerify(IrpContext %x)\n", IrpContext
);
368 return(STATUS_INVALID_DEVICE_REQUEST
);
372 NTSTATUS
VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext
)
374 * FUNCTION: File system control
380 DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext
);
384 switch (IrpContext
->MinorFunction
)
386 case IRP_MN_USER_FS_REQUEST
:
387 DPRINT("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
388 Status
= STATUS_INVALID_DEVICE_REQUEST
;
391 case IRP_MN_MOUNT_VOLUME
:
392 Status
= VfatMount(IrpContext
);
395 case IRP_MN_VERIFY_VOLUME
:
396 Status
= VfatVerify(IrpContext
);
400 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext
->MinorFunction
);
401 Status
= STATUS_INVALID_DEVICE_REQUEST
;
405 IrpContext
->Irp
->IoStatus
.Status
= Status
;
406 IrpContext
->Irp
->IoStatus
.Information
= 0;
408 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
409 VfatFreeIrpContext(IrpContext
);