68268fd8f9598696072b67880146e6ee3c9eb968
[reactos.git] / reactos / drivers / fs / vfat / iface.c
1 /* $Id: iface.c,v 1.58 2001/10/10 22:18:58 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 DPRINT("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 (PDEVICE_OBJECT DeviceToMount)
157 /*
158 * FUNCTION: Mount the filesystem
159 */
160 {
161 PDEVICE_OBJECT DeviceObject;
162 PDEVICE_EXTENSION DeviceExt;
163 BOOLEAN RecognizedFS;
164 NTSTATUS Status;
165 PVFATFCB Fcb;
166 PVFATCCB Ccb;
167
168 Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS);
169 if (!NT_SUCCESS(Status))
170 {
171 return(Status);
172 }
173
174 if (RecognizedFS == FALSE)
175 {
176 DPRINT("VFAT: Unrecognized Volume\n");
177 return(STATUS_UNRECOGNIZED_VOLUME);
178 }
179
180 DPRINT("VFAT: Recognized volume\n");
181
182 Status = IoCreateDevice(VfatDriverObject,
183 sizeof (DEVICE_EXTENSION),
184 NULL,
185 FILE_DEVICE_FILE_SYSTEM,
186 0,
187 FALSE,
188 &DeviceObject);
189 if (!NT_SUCCESS(Status))
190 {
191 return(Status);
192 }
193
194 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
195 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
196 /* use same vpb as device disk */
197 DeviceObject->Vpb = DeviceToMount->Vpb;
198 Status = VfatMountDevice(DeviceExt,
199 DeviceToMount);
200 if (!NT_SUCCESS(Status))
201 {
202 /* FIXME: delete device object */
203 return(Status);
204 }
205
206 #if 1
207 DbgPrint("BytesPerSector: %d\n", DeviceExt->Boot->BytesPerSector);
208 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->Boot->SectorsPerCluster);
209 DbgPrint("ReservedSectors: %d\n", DeviceExt->Boot->ReservedSectors);
210 DbgPrint("FATCount: %d\n", DeviceExt->Boot->FATCount);
211 DbgPrint("RootEntries: %d\n", DeviceExt->Boot->RootEntries);
212 DbgPrint("Sectors: %d\n", DeviceExt->Boot->Sectors);
213 DbgPrint("FATSectors: %d\n", DeviceExt->Boot->FATSectors);
214 DbgPrint("SectorsPerTrack: %d\n", DeviceExt->Boot->SectorsPerTrack);
215 DbgPrint("Heads: %d\n", DeviceExt->Boot->Heads);
216 DbgPrint("HiddenSectors: %d\n", DeviceExt->Boot->HiddenSectors);
217 DbgPrint("SectorsHuge: %d\n", DeviceExt->Boot->SectorsHuge);
218 DbgPrint("RootStart: %d\n", DeviceExt->rootStart);
219 DbgPrint("DataStart: %d\n", DeviceExt->dataStart);
220 if (DeviceExt->FatType == FAT32)
221 {
222 DbgPrint("FATSectors32: %d\n",
223 ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32);
224 DbgPrint("RootCluster: %d\n",
225 ((struct _BootSector32*)(DeviceExt->Boot))->RootCluster);
226 DbgPrint("FSInfoSector: %d\n",
227 ((struct _BootSector32*)(DeviceExt->Boot))->FSInfoSector);
228 DbgPrint("BootBackup: %d\n",
229 ((struct _BootSector32*)(DeviceExt->Boot))->BootBackup);
230 }
231 #endif
232 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
233 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
234 DeviceToMount);
235
236 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
237 Fcb = vfatNewFCB(NULL);
238 if (Fcb == NULL)
239 {
240 return STATUS_INSUFFICIENT_RESOURCES;
241 }
242 Ccb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
243 if (Ccb == NULL)
244 {
245 return STATUS_INSUFFICIENT_RESOURCES;
246 }
247 memset(Ccb, 0, sizeof (VFATCCB));
248 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
249 DeviceExt->FATFileObject->FsContext = (PVOID) &Fcb->RFCB;
250 DeviceExt->FATFileObject->FsContext2 = Ccb;
251 Ccb->pFcb = Fcb;
252 Ccb->PtrFileObject = DeviceExt->FATFileObject;
253 Fcb->FileObject = DeviceExt->FATFileObject;
254 Fcb->pDevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
255
256 Fcb->Flags = FCB_IS_FAT;
257
258 if (DeviceExt->FatType == FAT32)
259 {
260 Fcb->RFCB.FileSize.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
261 Fcb->RFCB.ValidDataLength.QuadPart = ((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE;
262 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(((struct _BootSector32 *)DeviceExt->Boot)->FATSectors32 * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
263 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
264 }
265 else
266 {
267 if (DeviceExt->FatType == FAT16)
268 {
269 Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
270 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
271 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(DeviceExt->Boot->FATSectors * BLOCKSIZE, CACHEPAGESIZE(DeviceExt));
272 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, CACHEPAGESIZE(DeviceExt));
273 }
274 else
275 {
276 Fcb->RFCB.FileSize.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
277 Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->Boot->FATSectors * BLOCKSIZE;
278 Fcb->RFCB.AllocationSize.QuadPart = 2 * PAGESIZE;
279 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, &Fcb->RFCB.Bcb, 2 * PAGESIZE);
280 }
281 }
282 if (!NT_SUCCESS (Status))
283 {
284 DbgPrint ("CcRosInitializeFileCache failed\n");
285 // KeBugCheck (0);
286 // FIXME: delete device object
287 return(Status);
288 }
289
290
291 ExInitializeResourceLite(&DeviceExt->DirResource);
292 ExInitializeResourceLite(&DeviceExt->FatResource);
293
294 KeInitializeSpinLock(&DeviceExt->FcbListLock);
295 InitializeListHead(&DeviceExt->FcbListHead);
296
297 /* read serial number */
298 if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
299 DeviceObject->Vpb->SerialNumber =
300 ((struct _BootSector *) (DeviceExt->Boot))->VolumeID;
301 else if (DeviceExt->FatType == FAT32)
302 DeviceObject->Vpb->SerialNumber =
303 ((struct _BootSector32 *) (DeviceExt->Boot))->VolumeID;
304
305 /* read volume label */
306 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
307
308 return(STATUS_SUCCESS);
309 }
310
311
312 NTSTATUS STDCALL
313 VfatFileSystemControl(PDEVICE_OBJECT DeviceObject,
314 PIRP Irp)
315 /*
316 * FUNCTION: File system control
317 */
318 {
319 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation (Irp);
320 NTSTATUS Status;
321
322 switch (Stack->MinorFunction)
323 {
324 case IRP_MN_USER_FS_REQUEST:
325 DPRINT1("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
326 Status = STATUS_INVALID_DEVICE_REQUEST;
327 break;
328
329 case IRP_MN_MOUNT_VOLUME:
330 Status = VfatMount(Stack->Parameters.Mount.DeviceObject);
331 break;
332
333 case IRP_MN_VERIFY_VOLUME:
334 DPRINT1("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
335 Status = STATUS_INVALID_DEVICE_REQUEST;
336 break;
337
338 default:
339 DPRINT1("VFAT FSC: MinorFunction %d\n", Stack->MinorFunction);
340 Status = STATUS_INVALID_DEVICE_REQUEST;
341 break;
342 }
343
344 Irp->IoStatus.Status = Status;
345 Irp->IoStatus.Information = 0;
346
347 IoCompleteRequest (Irp, IO_NO_INCREMENT);
348 return (Status);
349 }
350
351
352 NTSTATUS STDCALL
353 DriverEntry(PDRIVER_OBJECT _DriverObject,
354 PUNICODE_STRING RegistryPath)
355 /*
356 * FUNCTION: Called by the system to initalize the driver
357 * ARGUMENTS:
358 * DriverObject = object describing this driver
359 * RegistryPath = path to our configuration entries
360 * RETURNS: Success or failure
361 */
362 {
363 PDEVICE_OBJECT DeviceObject;
364 UNICODE_STRING DeviceName;
365 NTSTATUS Status;
366
367 DbgPrint("VFAT 0.0.6\n");
368
369 VfatDriverObject = _DriverObject;
370
371 RtlInitUnicodeString(&DeviceName,
372 L"\\Device\\Vfat");
373 Status = IoCreateDevice(VfatDriverObject,
374 0,
375 &DeviceName,
376 FILE_DEVICE_FILE_SYSTEM,
377 0,
378 FALSE,
379 &DeviceObject);
380 if (!NT_SUCCESS(Status))
381 {
382 return (Status);
383 }
384
385 DeviceObject->Flags = DO_DIRECT_IO;
386 VfatDriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatClose;
387 VfatDriverObject->MajorFunction[IRP_MJ_CREATE] = VfatCreate;
388 VfatDriverObject->MajorFunction[IRP_MJ_READ] = VfatRead;
389 VfatDriverObject->MajorFunction[IRP_MJ_WRITE] = VfatWrite;
390 VfatDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
391 VfatFileSystemControl;
392 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
393 VfatQueryInformation;
394 VfatDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
395 VfatSetInformation;
396 VfatDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
397 VfatDirectoryControl;
398 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
399 VfatQueryVolumeInformation;
400 VfatDriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
401 VfatSetVolumeInformation;
402 VfatDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown;
403 VfatDriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatCleanup;
404
405 VfatDriverObject->DriverUnload = NULL;
406
407 IoRegisterFileSystem(DeviceObject);
408
409 return STATUS_SUCCESS;
410 }
411
412 /* EOF */