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>
39 /* FUNCTIONS ****************************************************************/
41 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
42 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
46 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
47 PBOOLEAN RecognizedFS,
51 PARTITION_INFORMATION PartitionInfo;
52 DISK_GEOMETRY DiskGeometry;
57 struct _BootSector* Boot;
59 *RecognizedFS = FALSE;
61 Size = sizeof(DISK_GEOMETRY);
62 Status = VfatBlockDeviceIoControl(DeviceToMount,
63 IOCTL_DISK_GET_DRIVE_GEOMETRY,
68 if (!NT_SUCCESS(Status))
70 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
73 if (DiskGeometry.MediaType == FixedMedia)
75 // We have found a hard disk
76 Size = sizeof(PARTITION_INFORMATION);
77 Status = VfatBlockDeviceIoControl(DeviceToMount,
78 IOCTL_DISK_GET_PARTITION_INFO,
83 if (!NT_SUCCESS(Status))
85 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
89 DbgPrint("Partition Information:\n");
90 DbgPrint("StartingOffset %u\n", PartitionInfo.StartingOffset.QuadPart / 512);
91 DbgPrint("PartitionLength %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
92 DbgPrint("HiddenSectors %u\n", PartitionInfo.HiddenSectors);
93 DbgPrint("PartitionNumber %u\n", PartitionInfo.PartitionNumber);
94 DbgPrint("PartitionType %u\n", PartitionInfo.PartitionType);
95 DbgPrint("BootIndicator %u\n", PartitionInfo.BootIndicator);
96 DbgPrint("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
97 DbgPrint("RewritePartition %u\n", PartitionInfo.RewritePartition);
99 if (PartitionInfo.PartitionType == PARTITION_FAT_12 ||
100 PartitionInfo.PartitionType == PARTITION_FAT_16 ||
101 PartitionInfo.PartitionType == PARTITION_HUGE ||
102 PartitionInfo.PartitionType == PARTITION_FAT32 ||
103 PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
104 PartitionInfo.PartitionType == PARTITION_XINT13)
106 *RecognizedFS = TRUE;
109 else if (DiskGeometry.MediaType > Unknown && DiskGeometry.MediaType <= RemovableMedia)
111 *RecognizedFS = TRUE;
113 if (*RecognizedFS == FALSE)
115 return STATUS_SUCCESS;
118 Boot = ExAllocatePool(NonPagedPool, DiskGeometry.BytesPerSector);
122 return STATUS_INSUFFICIENT_RESOURCES;
125 Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot);
126 if (NT_SUCCESS(Status))
128 FatInfo.VolumeID = Boot->VolumeID;
129 FatInfo.FATStart = Boot->ReservedSectors;
130 FatInfo.FATCount = Boot->FATCount;
131 FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
132 FatInfo.BytesPerSector = Boot->BytesPerSector;
133 FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
134 FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
135 FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
136 FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
137 FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
138 FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
139 Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
140 FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
141 if (FatInfo.NumberOfClusters < 4085)
144 FatInfo.FatType = FAT12;
146 else if (FatInfo.NumberOfClusters >= 65525)
149 FatInfo.FatType = FAT32;
150 FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
151 FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
152 FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
157 FatInfo.FatType = FAT16;
169 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
170 PDEVICE_OBJECT DeviceToMount)
172 * FUNCTION: Mounts the device
176 BOOLEAN RecognizedFS;
178 DPRINT("Mounting VFAT device...\n");
180 Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
181 if (!NT_SUCCESS(Status))
186 if (DeviceExt->FatInfo.BytesPerCluster >= PAGE_SIZE &&
187 (DeviceExt->FatInfo.BytesPerCluster % PAGE_SIZE) != 0)
189 DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__, __LINE__);
192 else if (DeviceExt->FatInfo.BytesPerCluster < PAGE_SIZE &&
193 (PAGE_SIZE % DeviceExt->FatInfo.BytesPerCluster) != 0)
195 DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__, __LINE__);
199 return(STATUS_SUCCESS);
204 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
206 * FUNCTION: Mount the filesystem
209 PDEVICE_OBJECT DeviceObject = NULL;
210 PDEVICE_EXTENSION DeviceExt = NULL;
211 BOOLEAN RecognizedFS;
214 PVFATFCB VolumeFcb = NULL;
216 PDEVICE_OBJECT DeviceToMount;
218 DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
222 if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
224 Status = STATUS_INVALID_DEVICE_REQUEST;
228 DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
230 Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, NULL);
231 if (!NT_SUCCESS(Status))
236 if (RecognizedFS == FALSE)
238 DPRINT("VFAT: Unrecognized Volume\n");
239 Status = STATUS_UNRECOGNIZED_VOLUME;
243 DPRINT("VFAT: Recognized volume\n");
244 Status = IoCreateDevice(VfatGlobalData->DriverObject,
245 sizeof (DEVICE_EXTENSION),
247 FILE_DEVICE_FILE_SYSTEM,
251 if (!NT_SUCCESS(Status))
256 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
257 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
258 RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
260 /* use same vpb as device disk */
261 DeviceObject->Vpb = DeviceToMount->Vpb;
262 Status = VfatMountDevice(DeviceExt, DeviceToMount);
263 if (!NT_SUCCESS(Status))
265 /* FIXME: delete device object */
270 DbgPrint("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector);
271 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster);
272 DbgPrint("FATCount: %d\n", DeviceExt->FatInfo.FATCount);
273 DbgPrint("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors);
274 DbgPrint("RootStart: %d\n", DeviceExt->FatInfo.rootStart);
275 DbgPrint("DataStart: %d\n", DeviceExt->FatInfo.dataStart);
276 if (DeviceExt->FatInfo.FatType == FAT32)
278 DbgPrint("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster);
282 DeviceExt->StorageDevice = DeviceToMount;
283 DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
284 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
285 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
286 DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
287 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
289 DPRINT("FsDeviceObject %lx\n", DeviceObject);
291 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
292 Fcb = vfatNewFCB(NULL);
295 Status = STATUS_INSUFFICIENT_RESOURCES;
298 Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
301 Status = STATUS_INSUFFICIENT_RESOURCES;
304 memset(Ccb, 0, sizeof (VFATCCB));
305 wcscpy(Fcb->PathName, L"$$Fat$$");
306 Fcb->ObjectName = Fcb->PathName;
307 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
308 DeviceExt->FATFileObject->FsContext = Fcb;
309 DeviceExt->FATFileObject->FsContext2 = Ccb;
310 DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
311 DeviceExt->FATFileObject->PrivateCacheMap = NULL;
312 DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
313 Fcb->FileObject = DeviceExt->FATFileObject;
315 Fcb->Flags = FCB_IS_FAT;
317 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
318 Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
319 Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
321 if (DeviceExt->FatInfo.FatType != FAT12)
323 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, CACHEPAGESIZE(DeviceExt));
327 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, 2 * PAGE_SIZE);
329 if (!NT_SUCCESS (Status))
331 DbgPrint ("CcRosInitializeFileCache failed\n");
334 DeviceExt->LastAvailableCluster = 2;
335 ExInitializeResourceLite(&DeviceExt->DirResource);
336 ExInitializeResourceLite(&DeviceExt->FatResource);
338 KeInitializeSpinLock(&DeviceExt->FcbListLock);
339 InitializeListHead(&DeviceExt->FcbListHead);
341 VolumeFcb = vfatNewFCB(NULL);
342 if (VolumeFcb == NULL)
344 Status = STATUS_INSUFFICIENT_RESOURCES;
347 wcscpy(VolumeFcb->PathName, L"$$Volume$$");
348 VolumeFcb->ObjectName = VolumeFcb->PathName;
349 VolumeFcb->Flags = FCB_IS_VOLUME;
350 VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
351 VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
352 VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
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: Verify the filesystem
392 PDEVICE_OBJECT DeviceToVerify;
395 DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);
397 DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
398 Status = VfatBlockDeviceIoControl(DeviceToVerify,
399 IOCTL_DISK_CHECK_VERIFY,
404 if (!NT_SUCCESS(Status))
406 DPRINT1("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
408 /* FIXME: Compare volume label */
410 DPRINT1(" returning STATUS_WRONG_VOLUME\n");
412 return STATUS_WRONG_VOLUME;
415 return STATUS_SUCCESS;
420 VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
422 DPRINT("VfatGetVolumeBitmap (IrpContext %x)\n", IrpContext);
424 return STATUS_INVALID_DEVICE_REQUEST;
429 VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
431 PIO_STACK_LOCATION Stack;
433 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
434 PFILE_OBJECT FileObject;
435 ULONG MaxExtentCount;
437 PDEVICE_EXTENSION DeviceExt;
439 ULONG CurrentCluster;
443 DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
445 DeviceExt = IrpContext->DeviceExt;
446 FileObject = IrpContext->FileObject;
447 Stack = IrpContext->Stack;
448 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LARGE_INTEGER) ||
449 Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
451 return STATUS_INVALID_PARAMETER;
453 if (IrpContext->Irp->UserBuffer == NULL ||
454 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR))
456 return STATUS_BUFFER_TOO_SMALL;
459 Fcb = FileObject->FsContext;
461 ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
463 Vcn = *(PLARGE_INTEGER)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
464 RetrievalPointers = IrpContext->Irp->UserBuffer;
466 MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(GET_RETRIEVAL_DESCRIPTOR)) / sizeof(MAPPING_PAIR));
469 if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
471 Status = STATUS_INVALID_PARAMETER;
475 CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
476 Status = OffsetToCluster(DeviceExt, FirstCluster,
477 Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
478 &CurrentCluster, FALSE);
479 if (!NT_SUCCESS(Status))
484 RetrievalPointers->StartVcn = Vcn.QuadPart;
485 RetrievalPointers->NumberOfPairs = 0;
486 RetrievalPointers->Pair[0].Lcn = CurrentCluster - 2;
488 while (CurrentCluster != 0xffffffff && RetrievalPointers->NumberOfPairs < MaxExtentCount)
491 LastCluster = CurrentCluster;
492 Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
494 if (!NT_SUCCESS(Status))
499 if (LastCluster + 1 != CurrentCluster)
501 RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Vcn = Vcn.QuadPart;
502 RetrievalPointers->NumberOfPairs++;
503 if (RetrievalPointers->NumberOfPairs < MaxExtentCount)
505 RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Lcn = CurrentCluster - 2;
510 IrpContext->Irp->IoStatus.Information = sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR) * RetrievalPointers->NumberOfPairs;
511 Status = STATUS_SUCCESS;
514 ExReleaseResourceLite(&Fcb->MainResource);
520 VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
522 DPRINT("VfatMoveFile(IrpContext %x)\n", IrpContext);
524 return STATUS_INVALID_DEVICE_REQUEST;
528 VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
530 PDEVICE_EXTENSION DeviceExt;
531 PROS_QUERY_LCN_MAPPING LcnQuery;
532 PIO_STACK_LOCATION Stack;
534 DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
536 DeviceExt = IrpContext->DeviceExt;
537 Stack = IrpContext->Stack;
538 if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
539 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
541 return STATUS_BUFFER_TOO_SMALL;
543 LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
544 LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
545 IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
546 return(STATUS_SUCCESS);
549 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
551 * FUNCTION: File system control
557 DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
560 assert (IrpContext->Irp);
561 assert (IrpContext->Stack);
563 IrpContext->Irp->IoStatus.Information = 0;
565 switch (IrpContext->MinorFunction)
567 case IRP_MN_USER_FS_REQUEST:
568 switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
570 case FSCTL_GET_VOLUME_BITMAP:
571 Status = VfatGetVolumeBitmap(IrpContext);
573 case FSCTL_GET_RETRIEVAL_POINTERS:
574 Status = VfatGetRetrievalPointers(IrpContext);
576 case FSCTL_MOVE_FILE:
577 Status = VfatMoveFile(IrpContext);
579 case FSCTL_ROS_QUERY_LCN_MAPPING:
580 Status = VfatRosQueryLcnMapping(IrpContext);
583 Status = STATUS_INVALID_DEVICE_REQUEST;
587 case IRP_MN_MOUNT_VOLUME:
588 Status = VfatMount(IrpContext);
591 case IRP_MN_VERIFY_VOLUME:
592 Status = VfatVerify(IrpContext);
596 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
597 Status = STATUS_INVALID_DEVICE_REQUEST;
601 IrpContext->Irp->IoStatus.Status = Status;
603 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
604 VfatFreeIrpContext(IrpContext);