Reworked code for handling of asynchonous i/o requests.
[reactos.git] / reactos / drivers / fs / vfat / iface.c
1 /* $Id: iface.c,v 1.59 2001/11/02 22:47:36 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/iface.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
8 * UPDATE HISTORY:
9 * ?? Created
10 * 24-10-1998 Fixed bugs in long filename support
11 * Fixed a bug that prevented unsuccessful file open requests
12 * being reported
13 * Now works with long filenames that span over a sector
14 * boundary
15 * 28-10-1998 Reads entire FAT into memory
16 * VFatReadSector modified to read in more than one sector at a
17 * time
18 * 7-11-1998 Fixed bug that assumed that directory data could be
19 * fragmented
20 * 8-12-1998 Added FAT32 support
21 * Added initial writability functions
22 * WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
23 * 12-12-1998 Added basic support for FILE_STANDARD_INFORMATION request
24 *
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <ddk/ntddk.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 #include "vfat.h"
35
36 /* GLOBALS *****************************************************************/
37
38 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->BytesPerCluster > PAGESIZE ? \
39 (pDeviceExt)->BytesPerCluster : PAGESIZE)
40
41 static PDRIVER_OBJECT VfatDriverObject;
42
43 /* FUNCTIONS ****************************************************************/
44
45 static NTSTATUS
46 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
47 PBOOLEAN RecognizedFS)
48 /*
49 * FUNCTION: Tests if the device contains a filesystem that can be mounted
50 * by this fsd
51 */
52 {
53 BootSector *Boot;
54 NTSTATUS Status;
55
56 Boot = ExAllocatePool(NonPagedPool, 512);
57
58 Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) Boot);
59 if (!NT_SUCCESS(Status))
60 {
61 return(Status);
62 }
63
64 DPRINT1("Boot->SysType %.5s\n", Boot->SysType);
65 if (strncmp(Boot->SysType, "FAT12", 5) == 0 ||
66 strncmp(Boot->SysType, "FAT16", 5) == 0 ||
67 strncmp(((struct _BootSector32 *) (Boot))->SysType, "FAT32", 5) == 0)
68 {
69 *RecognizedFS = TRUE;
70 }
71 else
72 {
73 *RecognizedFS = FALSE;
74 }
75
76 ExFreePool(Boot);
77
78 return(STATUS_SUCCESS);
79 }
80
81
82 static NTSTATUS
83 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
84 PDEVICE_OBJECT DeviceToMount)
85 /*
86 * FUNCTION: Mounts the device
87 */
88 {
89 NTSTATUS Status;
90
91 DPRINT("Mounting VFAT device...");
92 DPRINT("DeviceExt %x\n", DeviceExt);
93
94 DeviceExt->Boot = ExAllocatePool(NonPagedPool, 512);
95
96 Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) DeviceExt->Boot);
97 if (!NT_SUCCESS(Status))
98 {
99 return(Status);
100 }
101
102 DeviceExt->FATStart = DeviceExt->Boot->ReservedSectors;
103 DeviceExt->rootDirectorySectors =
104 (DeviceExt->Boot->RootEntries * 32) / DeviceExt->Boot->BytesPerSector;
105 DeviceExt->rootStart =
106 DeviceExt->FATStart +
107 DeviceExt->Boot->FATCount * DeviceExt->Boot->FATSectors;
108 DeviceExt->dataStart =
109 DeviceExt->rootStart + DeviceExt->rootDirectorySectors;
110 DeviceExt->BytesPerSector = DeviceExt->Boot->BytesPerSector;
111 DeviceExt->FATEntriesPerSector = DeviceExt->Boot->BytesPerSector / 32;
112 DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
113 DeviceExt->Boot->BytesPerSector;
114
115 if (DeviceExt->BytesPerCluster >= PAGESIZE &&
116 (DeviceExt->BytesPerCluster % PAGESIZE) != 0)
117 {
118 DbgPrint("Invalid cluster size\n");
119 KeBugCheck(0);
120 }
121 else if (DeviceExt->BytesPerCluster < PAGESIZE &&
122 (PAGESIZE % DeviceExt->BytesPerCluster) != 0)
123 {
124 DbgPrint("Invalid cluster size2\n");
125 KeBugCheck(0);
126 }
127
128 if (strncmp (DeviceExt->Boot->SysType, "FAT12", 5) == 0)
129 {
130 DbgPrint("FAT12\n");
131 DeviceExt->FatType = FAT12;
132 }
133 else if (strncmp
134 (((struct _BootSector32 *) (DeviceExt->Boot))->SysType, "FAT32",
135 5) == 0)
136 {
137 DbgPrint("FAT32\n");
138 DeviceExt->FatType = FAT32;
139 DeviceExt->rootDirectorySectors = DeviceExt->Boot->SectorsPerCluster;
140 DeviceExt->dataStart = DeviceExt->FATStart + DeviceExt->Boot->FATCount
141 * ((struct _BootSector32 *) (DeviceExt->Boot))->FATSectors32;
142 DeviceExt->rootStart = ClusterToSector (DeviceExt,
143 ((struct _BootSector32 *)(DeviceExt->Boot))->RootCluster);
144 }
145 else
146 {
147 DbgPrint("FAT16\n");
148 DeviceExt->FatType = FAT16;
149 }
150
151 return(STATUS_SUCCESS);
152 }
153
154
155 static NTSTATUS
156 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
157 /*
158 * FUNCTION: Mount the filesystem
159 */
160 {
161 PDEVICE_OBJECT DeviceObject = NULL;
162 PDEVICE_EXTENSION DeviceExt = NULL;
163 BOOLEAN RecognizedFS;
164 NTSTATUS Status;
165 PVFATFCB Fcb = NULL;
166 PVFATCCB Ccb = NULL;
167
168 DPRINT1("VfatMount(IrpContext %x)\n", IrpContext);
169
170 assert (IrpContext);
171
172 if (IrpContext->DeviceObject != VfatDriverObject->DeviceObject)
173 {
174 // Only allowed on the main device object
175 Status = STATUS_INVALID_DEVICE_REQUEST;
176 goto ByeBye;
177 }
178
179 Status = VfatHasFileSystem (IrpContext->Stack->Parameters.Mount.DeviceObject, &RecognizedFS);
180 if (!NT_SUCCESS(Status))
181 {
182 goto ByeBye;
183 }
184
185 if (RecognizedFS == FALSE)
186 {
187 DPRINT("VFAT: Unrecognized Volume\n");
188 Status = STATUS_UNRECOGNIZED_VOLUME;
189 goto ByeBye;
190 }
191
192 DPRINT("VFAT: Recognized volume\n");
193
194 Status = IoCreateDevice(VfatDriverObject,
195 sizeof (DEVICE_EXTENSION),
196 NULL,
197 FILE_DEVICE_FILE_SYSTEM,
198 0,
199 FALSE,
200 &DeviceObject);
201 if (!NT_SUCCESS(Status))
202 {
203 goto ByeBye;
204 }
205
206 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
207 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
208 RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
209
210 /* use same vpb as device disk */
211 DeviceObject->Vpb = IrpContext->Stack->Parameters.Mount.DeviceObject->Vpb;
212 Status = VfatMountDevice(DeviceExt, IrpContext->Stack->Parameters.Mount.DeviceObject);
213 if (!NT_SUCCESS(Status))
214 {
215 /* FIXME: delete device object */
216 goto ByeBye;
217 }
218
219 #if 1
220 DbgPrint("BytesPerSector: %d\n", DeviceExt->Boot->BytesPerSector);
221 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->Boot->SectorsPerCluster);
222 DbgPrint("ReservedSectors: %d\n", DeviceExt->Boot->ReservedSectors);
223 DbgPrint("FATCount: %d\n", DeviceExt->Boot->FATCount);
224 DbgPrint("RootEntries: %d\n", DeviceExt->Boot->RootEntries);
225 DbgPrint("Sectors: %d\n", DeviceExt->Boot->Sectors);
226 DbgPrint("FATSectors: %d\n", DeviceExt->Boot->FATSectors);
227 DbgPrint("SectorsPerTrack: %d\n", DeviceExt->Boot->SectorsPerTrack);
228 DbgPrint("Heads: %d\n", DeviceExt->Boot->Heads);
229 DbgPrint("HiddenSectors: %d\n", DeviceExt->Boot->HiddenSectors);
230 DbgPrint("SectorsHuge: %d\n", DeviceExt->Boot->SectorsHuge);
231 DbgPrint("RootStart: %d\n", DeviceExt->rootStart);
232 DbgPrint("DataStart: %d\n", DeviceExt->dataStart);
233 if (DeviceExt->FatType == FAT32)
234 {
235 DbgPrint("FATSectors32: %d\n",
236 ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32);
237 DbgPrint("RootCluster: %d\n",
238 ((struct _BootSector32*)(DeviceExt->Boot))->RootCluster);
239 DbgPrint("FSInfoSector: %d\n",
240 ((struct _BootSector32*)(DeviceExt->Boot))->FSInfoSector);
241 DbgPrint("BootBackup: %d\n",
242 ((struct _BootSector32*)(DeviceExt->Boot))->BootBackup);
243 }
244 #endif
245 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
246 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject, IrpContext->Stack->Parameters.Mount.DeviceObject);
247
248 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
249 Fcb = vfatNewFCB(NULL);
250 if (Fcb == NULL)
251 {
252 Status = STATUS_INSUFFICIENT_RESOURCES;
253 goto ByeBye;
254 }
255 Ccb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
256 if (Ccb == NULL)
257 {
258 Status = STATUS_INSUFFICIENT_RESOURCES;
259 goto ByeBye;
260 }
261 memset(Ccb, 0, sizeof (VFATCCB));
262 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
263 DeviceExt->FATFileObject->FsContext = (PVOID) &Fcb->RFCB;
264 DeviceExt->FATFileObject->FsContext2 = Ccb;
265 DeviceExt->FATFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
266 Ccb->pFcb = Fcb;
267 Ccb->PtrFileObject = DeviceExt->FATFileObject;
268 Fcb->FileObject = DeviceExt->FATFileObject;
269 Fcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
270
271 Fcb->Flags = FCB_IS_FAT;
272
273 if (DeviceExt->Boot->Sectors != 0)
274 {
275 DeviceExt->NumberOfClusters = (DeviceExt->Boot->Sectors - DeviceExt->dataStart)
276 / DeviceExt->Boot->SectorsPerCluster + 2;
277 }
278 else
279 {
280 DeviceExt->NumberOfClusters = (DeviceExt->Boot->SectorsHuge - DeviceExt->dataStart)
281 / DeviceExt->Boot->SectorsPerCluster + 2;
282 }
283 if (DeviceExt->FatType == FAT32)
284 {
285 Fcb->RFCB.FileSize.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
286 Fcb->RFCB.ValidDataLength.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
287 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
288 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
289 }
290 else
291 {
292 if (DeviceExt->FatType == FAT16)
293 {
294 Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
295 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
296 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(DeviceExt->Boot->FATSectors * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
297 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
298 }
299 else
300 {
301 Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
302 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
303 Fcb->RFCB.AllocationSize.QuadPart = 2 * PAGESIZE;
304 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, 2 * PAGESIZE);
305 }
306 }
307 if (!NT_SUCCESS (Status))
308 {
309 DbgPrint ("CcRosInitializeFileCache failed\n");
310 goto ByeBye;
311 }
312
313 DeviceExt->LastAvailableCluster = 0;
314 ExInitializeResourceLite(&DeviceExt->DirResource);
315 ExInitializeResourceLite(&DeviceExt->FatResource);
316
317 KeInitializeSpinLock(&DeviceExt->FcbListLock);
318 InitializeListHead(&DeviceExt->FcbListHead);
319
320 /* read serial number */
321 if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
322 DeviceObject->Vpb->SerialNumber =
323 ((struct _BootSector *) (DeviceExt->Boot))->VolumeID;
324 else if (DeviceExt->FatType == FAT32)
325 DeviceObject->Vpb->SerialNumber =
326 ((struct _BootSector32 *) (DeviceExt->Boot))->VolumeID;
327
328 /* read volume label */
329 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
330 Status = STATUS_SUCCESS;
331
332 ByeBye:
333
334 if (!NT_SUCCESS(Status))
335 {
336 // cleanup
337 if (DeviceExt && DeviceExt->FATFileObject)
338 ObDereferenceObject (DeviceExt->FATFileObject);
339 if (Fcb)
340 ExFreePool(Fcb);
341 if (Ccb)
342 ExFreePool(Ccb);
343 if (DeviceObject)
344 IoDeleteDevice(DeviceObject);
345 }
346 return Status;
347 }
348
349
350 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
351 /*
352 * FUNCTION: File system control
353 */
354 {
355
356 NTSTATUS Status;
357
358 DPRINT1("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
359
360 assert (IrpContext);
361
362 switch (IrpContext->MinorFunction)
363 {
364 case IRP_MN_USER_FS_REQUEST:
365 DPRINT1("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
366 Status = STATUS_INVALID_DEVICE_REQUEST;
367 break;
368
369 case IRP_MN_MOUNT_VOLUME:
370 Status = VfatMount(IrpContext);
371 break;
372
373 case IRP_MN_VERIFY_VOLUME:
374 DPRINT1("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
375 Status = STATUS_INVALID_DEVICE_REQUEST;
376 break;
377
378 default:
379 DPRINT1("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
380 Status = STATUS_INVALID_DEVICE_REQUEST;
381 break;
382 }
383
384 IrpContext->Irp->IoStatus.Status = Status;
385 IrpContext->Irp->IoStatus.Information = 0;
386
387 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
388 return (Status);
389 }
390
391
392 NTSTATUS STDCALL
393 DriverEntry(PDRIVER_OBJECT _DriverObject,
394 PUNICODE_STRING RegistryPath)
395 /*
396 * FUNCTION: Called by the system to initalize the driver
397 * ARGUMENTS:
398 * DriverObject = object describing this driver
399 * RegistryPath = path to our configuration entries
400 * RETURNS: Success or failure
401 */
402 {
403 PDEVICE_OBJECT DeviceObject;
404 UNICODE_STRING DeviceName;
405 NTSTATUS Status;
406
407 DbgPrint("VFAT 0.0.6\n");
408
409 VfatDriverObject = _DriverObject;
410
411 RtlInitUnicodeString(&DeviceName,
412 L"\\Device\\Vfat");
413 Status = IoCreateDevice(VfatDriverObject,
414 0,
415 &DeviceName,
416 FILE_DEVICE_FILE_SYSTEM,
417 0,
418 FALSE,
419 &DeviceObject);
420 if (!NT_SUCCESS(Status))
421 {
422 return (Status);
423 }
424
425 DeviceObject->Flags = DO_DIRECT_IO;
426 VfatDriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest;
427 VfatDriverObject->MajorFunction[IRP_MJ_CREATE] = VfatBuildRequest;
428 VfatDriverObject->MajorFunction[IRP_MJ_READ] = VfatBuildRequest;
429 VfatDriverObject->MajorFunction[IRP_MJ_WRITE] = VfatBuildRequest;
430 VfatDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
431 VfatBuildRequest;
432 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
433 VfatBuildRequest;
434 VfatDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
435 VfatBuildRequest;
436 VfatDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
437 VfatBuildRequest;
438 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
439 VfatBuildRequest;
440 VfatDriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
441 VfatBuildRequest;
442 VfatDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown;
443 VfatDriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatBuildRequest;
444
445 VfatDriverObject->DriverUnload = NULL;
446
447 IoRegisterFileSystem(DeviceObject);
448
449 return STATUS_SUCCESS;
450 }
451
452 /* EOF */