All:
[reactos.git] / reactos / drivers / fs / vfat / fsctl.c
1 /* $Id: fsctl.c,v 1.1 2002/03/18 22:37:13 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/fsctl.c
6 * PURPOSE: VFAT Filesystem
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <wchar.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #include "vfat.h"
18
19 /* FUNCTIONS ****************************************************************/
20
21 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGESIZE ? \
22 (pDeviceExt)->FatInfo.BytesPerCluster : PAGESIZE)
23
24
25 static NTSTATUS
26 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
27 PBOOLEAN RecognizedFS,
28 PFATINFO pFatInfo)
29 {
30 NTSTATUS Status;
31 PARTITION_INFORMATION PartitionInfo;
32 DISK_GEOMETRY DiskGeometry;
33 FATINFO FatInfo;
34 ULONG Size;
35 ULONG Sectors;
36 struct _BootSector* Boot;
37
38 *RecognizedFS = FALSE;
39
40 Size = sizeof(DISK_GEOMETRY);
41 Status = VfatBlockDeviceIoControl(DeviceToMount,
42 IOCTL_DISK_GET_DRIVE_GEOMETRY,
43 NULL,
44 0,
45 &DiskGeometry,
46 &Size);
47 if (!NT_SUCCESS(Status))
48 {
49 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
50 return Status;
51 }
52 if (DiskGeometry.MediaType == FixedMedia)
53 {
54 // We have found a hard disk
55 Size = sizeof(PARTITION_INFORMATION);
56 Status = VfatBlockDeviceIoControl(DeviceToMount,
57 IOCTL_DISK_GET_PARTITION_INFO,
58 NULL,
59 0,
60 &PartitionInfo,
61 &Size);
62 if (!NT_SUCCESS(Status))
63 {
64 DPRINT1("VfatBlockDeviceIoControl faild (%x)\n", Status);
65 return Status;
66 }
67 #ifdef DBG
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);
77 #endif
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)
84 {
85 *RecognizedFS = TRUE;
86 }
87 }
88 else if (DiskGeometry.MediaType > Unknown && DiskGeometry.MediaType < RemovableMedia)
89 {
90 *RecognizedFS = TRUE;
91 }
92 if (*RecognizedFS == FALSE)
93 {
94 return STATUS_SUCCESS;
95 }
96 ReadSector:
97 Boot = ExAllocatePool(NonPagedPool, BLOCKSIZE);
98 if (Boot == NULL)
99 {
100 *RecognizedFS=FALSE;
101 return STATUS_INSUFFICIENT_RESOURCES;
102 }
103 Status = VfatReadSectors(DeviceToMount, 0, 1, (PUCHAR) Boot);
104 if (NT_SUCCESS(Status))
105 {
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 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)
120 {
121 DPRINT("FAT12\n");
122 FatInfo.FatType = FAT12;
123 }
124 else if (FatInfo.NumberOfClusters >= 65525)
125 {
126 DPRINT("FAT32\n");
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;
131 }
132 else
133 {
134 DPRINT("FAT16\n");
135 FatInfo.FatType = FAT16;
136 }
137 if (pFatInfo)
138 {
139 *pFatInfo = FatInfo;
140 }
141 }
142 ExFreePool(Boot);
143 return Status;
144 }
145
146 static NTSTATUS
147 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
148 PDEVICE_OBJECT DeviceToMount)
149 /*
150 * FUNCTION: Mounts the device
151 */
152 {
153 NTSTATUS Status;
154 BOOLEAN RecognizedFS;
155
156 DPRINT1("Mounting VFAT device...\n");
157
158 Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
159 if (!NT_SUCCESS(Status))
160 {
161 return(Status);
162 }
163
164 if (DeviceExt->FatInfo.BytesPerCluster >= PAGESIZE &&
165 (DeviceExt->FatInfo.BytesPerCluster % PAGESIZE) != 0)
166 {
167 DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__, __LINE__);
168 KeBugCheck(0);
169 }
170 else if (DeviceExt->FatInfo.BytesPerCluster < PAGESIZE &&
171 (PAGESIZE % DeviceExt->FatInfo.BytesPerCluster) != 0)
172 {
173 DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__, __LINE__);
174 KeBugCheck(0);
175 }
176
177 return(STATUS_SUCCESS);
178 }
179
180
181 static NTSTATUS
182 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
183 /*
184 * FUNCTION: Mount the filesystem
185 */
186 {
187 PDEVICE_OBJECT DeviceObject = NULL;
188 PDEVICE_EXTENSION DeviceExt = NULL;
189 BOOLEAN RecognizedFS;
190 NTSTATUS Status;
191 PVFATFCB Fcb = NULL;
192 PVFATCCB Ccb = NULL;
193 LARGE_INTEGER timeout;
194
195 DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
196
197 assert (IrpContext);
198
199 if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
200 {
201 Status = STATUS_INVALID_DEVICE_REQUEST;
202 goto ByeBye;
203 }
204
205 Status = VfatHasFileSystem (IrpContext->Stack->Parameters.Mount.DeviceObject, &RecognizedFS, NULL);
206 if (!NT_SUCCESS(Status))
207 {
208 goto ByeBye;
209 }
210
211 if (RecognizedFS == FALSE)
212 {
213 DPRINT("VFAT: Unrecognized Volume\n");
214 Status = STATUS_UNRECOGNIZED_VOLUME;
215 goto ByeBye;
216 }
217
218 DPRINT("VFAT: Recognized volume\n");
219 Status = IoCreateDevice(VfatGlobalData->DriverObject,
220 sizeof (DEVICE_EXTENSION),
221 NULL,
222 FILE_DEVICE_FILE_SYSTEM,
223 0,
224 FALSE,
225 &DeviceObject);
226 if (!NT_SUCCESS(Status))
227 {
228 goto ByeBye;
229 }
230
231 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
232 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
233 RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
234
235 /* use same vpb as device disk */
236 DeviceObject->Vpb = IrpContext->Stack->Parameters.Mount.DeviceObject->Vpb;
237 Status = VfatMountDevice(DeviceExt, IrpContext->Stack->Parameters.Mount.DeviceObject);
238 if (!NT_SUCCESS(Status))
239 {
240 /* FIXME: delete device object */
241 goto ByeBye;
242 }
243
244 #ifdef DBG
245 DbgPrint("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector);
246 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster);
247 DbgPrint("FATCount: %d\n", DeviceExt->FatInfo.FATCount);
248 DbgPrint("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors);
249 DbgPrint("RootStart: %d\n", DeviceExt->FatInfo.rootStart);
250 DbgPrint("DataStart: %d\n", DeviceExt->FatInfo.dataStart);
251 if (DeviceExt->FatInfo.FatType == FAT32)
252 {
253 DbgPrint("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster);
254 }
255 #endif
256 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
257 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject, IrpContext->Stack->Parameters.Mount.DeviceObject);
258
259 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
260 Fcb = vfatNewFCB(NULL);
261 if (Fcb == NULL)
262 {
263 Status = STATUS_INSUFFICIENT_RESOURCES;
264 goto ByeBye;
265 }
266 Ccb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
267 if (Ccb == NULL)
268 {
269 Status = STATUS_INSUFFICIENT_RESOURCES;
270 goto ByeBye;
271 }
272 memset(Ccb, 0, sizeof (VFATCCB));
273 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
274 DeviceExt->FATFileObject->FsContext = (PVOID) &Fcb->RFCB;
275 DeviceExt->FATFileObject->FsContext2 = Ccb;
276 DeviceExt->FATFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
277 DeviceExt->FATFileObject->PrivateCacheMap = NULL;
278 DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
279 Ccb->pFcb = Fcb;
280 Ccb->PtrFileObject = DeviceExt->FATFileObject;
281 Fcb->FileObject = DeviceExt->FATFileObject;
282 Fcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
283
284 Fcb->Flags = FCB_IS_FAT;
285
286 if (DeviceExt->FatInfo.FatType != FAT12)
287 {
288 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * BLOCKSIZE;
289 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->FatInfo.FATSectors * BLOCKSIZE;
290 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(DeviceExt->FatInfo.FATSectors * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
291 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
292 }
293 else
294 {
295 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * BLOCKSIZE;
296 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->FatInfo.FATSectors * BLOCKSIZE;
297 Fcb->RFCB.AllocationSize.QuadPart = 2 * PAGESIZE;
298 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, 2 * PAGESIZE);
299 }
300 if (!NT_SUCCESS (Status))
301 {
302 DbgPrint ("CcRosInitializeFileCache failed\n");
303 goto ByeBye;
304 }
305 DeviceExt->LastAvailableCluster = 0;
306 ExInitializeResourceLite(&DeviceExt->DirResource);
307 ExInitializeResourceLite(&DeviceExt->FatResource);
308
309 KeInitializeSpinLock(&DeviceExt->FcbListLock);
310 InitializeListHead(&DeviceExt->FcbListHead);
311
312 /* read serial number */
313 DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
314
315 /* read volume label */
316 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
317
318 Status = STATUS_SUCCESS;
319
320 ByeBye:
321
322 if (!NT_SUCCESS(Status))
323 {
324 // cleanup
325 if (DeviceExt && DeviceExt->FATFileObject)
326 ObDereferenceObject (DeviceExt->FATFileObject);
327 if (Fcb)
328 ExFreePool(Fcb);
329 if (Ccb)
330 ExFreePool(Ccb);
331 if (DeviceObject)
332 IoDeleteDevice(DeviceObject);
333 }
334 return Status;
335 }
336
337 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
338 /*
339 * FUNCTION: File system control
340 */
341 {
342
343 NTSTATUS Status;
344
345 DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
346
347 assert (IrpContext);
348
349 switch (IrpContext->MinorFunction)
350 {
351 case IRP_MN_USER_FS_REQUEST:
352 DPRINT("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
353 Status = STATUS_INVALID_DEVICE_REQUEST;
354 break;
355
356 case IRP_MN_MOUNT_VOLUME:
357 Status = VfatMount(IrpContext);
358 break;
359
360 case IRP_MN_VERIFY_VOLUME:
361 DPRINT("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
362 Status = STATUS_INVALID_DEVICE_REQUEST;
363 break;
364
365 default:
366 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
367 Status = STATUS_INVALID_DEVICE_REQUEST;
368 break;
369 }
370
371 IrpContext->Irp->IoStatus.Status = Status;
372 IrpContext->Irp->IoStatus.Information = 0;
373
374 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
375 VfatFreeIrpContext(IrpContext);
376 return (Status);
377 }
378