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.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/fs/vfat/fsctl.c
24 * PURPOSE: VFAT Filesystem
27 /* INCLUDES *****************************************************************/
29 #include <ddk/ntddk.h>
37 /* FUNCTIONS ****************************************************************/
39 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
40 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
44 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
45 PBOOLEAN RecognizedFS,
49 PARTITION_INFORMATION PartitionInfo;
50 DISK_GEOMETRY DiskGeometry;
55 struct _BootSector* Boot;
57 *RecognizedFS = FALSE;
59 Size = sizeof(DISK_GEOMETRY);
60 Status = VfatBlockDeviceIoControl(DeviceToMount,
61 IOCTL_DISK_GET_DRIVE_GEOMETRY,
66 if (!NT_SUCCESS(Status))
68 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
71 if (DiskGeometry.MediaType == FixedMedia)
73 // We have found a hard disk
74 Size = sizeof(PARTITION_INFORMATION);
75 Status = VfatBlockDeviceIoControl(DeviceToMount,
76 IOCTL_DISK_GET_PARTITION_INFO,
81 if (!NT_SUCCESS(Status))
83 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
87 DbgPrint("Partition Information:\n");
88 DbgPrint("StartingOffset %u\n", PartitionInfo.StartingOffset.QuadPart / 512);
89 DbgPrint("PartitionLength %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
90 DbgPrint("HiddenSectors %u\n", PartitionInfo.HiddenSectors);
91 DbgPrint("PartitionNumber %u\n", PartitionInfo.PartitionNumber);
92 DbgPrint("PartitionType %u\n", PartitionInfo.PartitionType);
93 DbgPrint("BootIndicator %u\n", PartitionInfo.BootIndicator);
94 DbgPrint("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
95 DbgPrint("RewritePartition %u\n", PartitionInfo.RewritePartition);
97 if (PartitionInfo.PartitionType == PARTITION_FAT_12 ||
98 PartitionInfo.PartitionType == PARTITION_FAT_16 ||
99 PartitionInfo.PartitionType == PARTITION_HUGE ||
100 PartitionInfo.PartitionType == PARTITION_FAT32 ||
101 PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
102 PartitionInfo.PartitionType == PARTITION_XINT13)
104 *RecognizedFS = TRUE;
107 else if (DiskGeometry.MediaType > Unknown && DiskGeometry.MediaType <= RemovableMedia)
109 *RecognizedFS = TRUE;
111 if (*RecognizedFS == FALSE)
113 return STATUS_SUCCESS;
116 Boot = ExAllocatePool(NonPagedPool, DiskGeometry.BytesPerSector);
120 return STATUS_INSUFFICIENT_RESOURCES;
123 Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot);
124 if (NT_SUCCESS(Status))
126 FatInfo.VolumeID = Boot->VolumeID;
127 FatInfo.FATStart = Boot->ReservedSectors;
128 FatInfo.FATCount = Boot->FATCount;
129 FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
130 FatInfo.BytesPerSector = Boot->BytesPerSector;
131 FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
132 FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
133 FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
134 FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
135 FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
136 FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
137 Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
138 FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
139 if (FatInfo.NumberOfClusters < 4085)
142 FatInfo.FatType = FAT12;
144 else if (FatInfo.NumberOfClusters >= 65525)
147 FatInfo.FatType = FAT32;
148 FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
149 FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
150 FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
155 FatInfo.FatType = FAT16;
167 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
168 PDEVICE_OBJECT DeviceToMount)
170 * FUNCTION: Mounts the device
174 BOOLEAN RecognizedFS;
176 DPRINT("Mounting VFAT device...\n");
178 Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
179 if (!NT_SUCCESS(Status))
184 if (DeviceExt->FatInfo.BytesPerCluster >= PAGE_SIZE &&
185 (DeviceExt->FatInfo.BytesPerCluster % PAGE_SIZE) != 0)
187 DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__, __LINE__);
190 else if (DeviceExt->FatInfo.BytesPerCluster < PAGE_SIZE &&
191 (PAGE_SIZE % DeviceExt->FatInfo.BytesPerCluster) != 0)
193 DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__, __LINE__);
197 return(STATUS_SUCCESS);
202 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
204 * FUNCTION: Mount the filesystem
207 PDEVICE_OBJECT DeviceObject = NULL;
208 PDEVICE_EXTENSION DeviceExt = NULL;
209 BOOLEAN RecognizedFS;
212 PVFATFCB VolumeFcb = NULL;
214 LARGE_INTEGER timeout;
216 DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
220 if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
222 Status = STATUS_INVALID_DEVICE_REQUEST;
226 Status = VfatHasFileSystem (IrpContext->Stack->Parameters.MountVolume.DeviceObject, &RecognizedFS, NULL);
227 if (!NT_SUCCESS(Status))
232 if (RecognizedFS == FALSE)
234 DPRINT("VFAT: Unrecognized Volume\n");
235 Status = STATUS_UNRECOGNIZED_VOLUME;
239 DPRINT("VFAT: Recognized volume\n");
240 Status = IoCreateDevice(VfatGlobalData->DriverObject,
241 sizeof (DEVICE_EXTENSION),
243 FILE_DEVICE_FILE_SYSTEM,
247 if (!NT_SUCCESS(Status))
252 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
253 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
254 RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
256 /* use same vpb as device disk */
257 DeviceObject->Vpb = IrpContext->Stack->Parameters.MountVolume.DeviceObject->Vpb;
258 Status = VfatMountDevice(DeviceExt, IrpContext->Stack->Parameters.MountVolume.DeviceObject);
259 if (!NT_SUCCESS(Status))
261 /* FIXME: delete device object */
266 DbgPrint("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector);
267 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster);
268 DbgPrint("FATCount: %d\n", DeviceExt->FatInfo.FATCount);
269 DbgPrint("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors);
270 DbgPrint("RootStart: %d\n", DeviceExt->FatInfo.rootStart);
271 DbgPrint("DataStart: %d\n", DeviceExt->FatInfo.dataStart);
272 if (DeviceExt->FatInfo.FatType == FAT32)
274 DbgPrint("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster);
278 DeviceExt->StorageDevice = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
279 DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
280 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
281 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
282 DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
283 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
285 DPRINT("FsDeviceObject %lx\n", DeviceObject);
287 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
288 Fcb = vfatNewFCB(NULL);
291 Status = STATUS_INSUFFICIENT_RESOURCES;
294 Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
297 Status = STATUS_INSUFFICIENT_RESOURCES;
300 memset(Ccb, 0, sizeof (VFATCCB));
301 wcscpy(Fcb->PathName, L"$$Fat$$");
302 Fcb->ObjectName = Fcb->PathName;
303 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
304 DeviceExt->FATFileObject->FsContext = (PVOID) &Fcb->RFCB;
305 DeviceExt->FATFileObject->FsContext2 = Ccb;
306 DeviceExt->FATFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
307 DeviceExt->FATFileObject->PrivateCacheMap = NULL;
308 DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
310 Ccb->PtrFileObject = DeviceExt->FATFileObject;
311 Fcb->FileObject = DeviceExt->FATFileObject;
312 Fcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
314 Fcb->Flags = FCB_IS_FAT;
316 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
317 Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
318 Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
320 if (DeviceExt->FatInfo.FatType != FAT12)
322 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
326 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, 2 * PAGE_SIZE);
328 if (!NT_SUCCESS (Status))
330 DbgPrint ("CcRosInitializeFileCache failed\n");
333 DeviceExt->LastAvailableCluster = 2;
334 ExInitializeResourceLite(&DeviceExt->DirResource);
335 ExInitializeResourceLite(&DeviceExt->FatResource);
337 KeInitializeSpinLock(&DeviceExt->FcbListLock);
338 InitializeListHead(&DeviceExt->FcbListHead);
340 VolumeFcb = vfatNewFCB(NULL);
341 if (VolumeFcb == NULL)
343 Status = STATUS_INSUFFICIENT_RESOURCES;
346 wcscpy(VolumeFcb->PathName, L"$$Volume$$");
347 VolumeFcb->ObjectName = VolumeFcb->PathName;
348 VolumeFcb->Flags = FCB_IS_VOLUME;
349 VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
350 VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
351 VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
352 VolumeFcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
353 DeviceExt->VolumeFcb = VolumeFcb;
355 ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
356 InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
357 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
359 /* read serial number */
360 DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
362 /* read volume label */
363 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
365 Status = STATUS_SUCCESS;
368 if (!NT_SUCCESS(Status))
371 if (DeviceExt && DeviceExt->FATFileObject)
372 ObDereferenceObject (DeviceExt->FATFileObject);
378 IoDeleteDevice(DeviceObject);
380 vfatDestroyFCB(VolumeFcb);
387 VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
389 * FUNCTION: Mount the filesystem
392 DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);
396 return(STATUS_INVALID_DEVICE_REQUEST);
400 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
402 * FUNCTION: File system control
408 DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
412 switch (IrpContext->MinorFunction)
414 case IRP_MN_USER_FS_REQUEST:
415 DPRINT("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
416 Status = STATUS_INVALID_DEVICE_REQUEST;
419 case IRP_MN_MOUNT_VOLUME:
420 Status = VfatMount(IrpContext);
423 case IRP_MN_VERIFY_VOLUME:
424 Status = VfatVerify(IrpContext);
428 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
429 Status = STATUS_INVALID_DEVICE_REQUEST;
433 IrpContext->Irp->IoStatus.Status = Status;
434 IrpContext->Irp->IoStatus.Information = 0;
436 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
437 VfatFreeIrpContext(IrpContext);