Added support for FAT16 partition with clustersize greater than page size.
[reactos.git] / reactos / drivers / fs / vfat / iface.c
1 /* $Id: iface.c,v 1.55 2001/07/13 10:31:14 ekohl 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, PDEVICE_OBJECT DeviceToMount)
84 /*
85 * FUNCTION: Mounts the device
86 */
87 {
88 NTSTATUS Status;
89
90 DPRINT("Mounting VFAT device...");
91 DPRINT("DeviceExt %x\n", DeviceExt);
92
93 DeviceExt->Boot = ExAllocatePool(NonPagedPool, 512);
94
95 Status = VfatReadSectors(DeviceToMount, 0, 1, (UCHAR *) DeviceExt->Boot);
96 if (!NT_SUCCESS(Status))
97 {
98 return Status;
99 }
100
101 DeviceExt->FATStart = DeviceExt->Boot->ReservedSectors;
102 DeviceExt->rootDirectorySectors =
103 (DeviceExt->Boot->RootEntries * 32) / DeviceExt->Boot->BytesPerSector;
104 DeviceExt->rootStart =
105 DeviceExt->FATStart +
106 DeviceExt->Boot->FATCount * DeviceExt->Boot->FATSectors;
107 DeviceExt->dataStart =
108 DeviceExt->rootStart + DeviceExt->rootDirectorySectors;
109 DeviceExt->BytesPerSector = DeviceExt->Boot->BytesPerSector;
110 DeviceExt->FATEntriesPerSector = DeviceExt->Boot->BytesPerSector / 32;
111 DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
112 DeviceExt->Boot->BytesPerSector;
113
114 if (DeviceExt->BytesPerCluster >= PAGESIZE &&
115 (DeviceExt->BytesPerCluster % PAGESIZE) != 0)
116 {
117 DbgPrint("Invalid cluster size\n");
118 KeBugCheck(0);
119 }
120 else if (DeviceExt->BytesPerCluster < PAGESIZE &&
121 (PAGESIZE % DeviceExt->BytesPerCluster) != 0)
122 {
123 DbgPrint("Invalid cluster size2\n");
124 KeBugCheck(0);
125 }
126
127 if (strncmp (DeviceExt->Boot->SysType, "FAT12", 5) == 0)
128 {
129 DbgPrint("FAT12\n");
130 DeviceExt->FatType = FAT12;
131 }
132 else if (strncmp
133 (((struct _BootSector32 *) (DeviceExt->Boot))->SysType, "FAT32",
134 5) == 0)
135 {
136 DbgPrint("FAT32\n");
137 DeviceExt->FatType = FAT32;
138 DeviceExt->rootDirectorySectors = DeviceExt->Boot->SectorsPerCluster;
139 DeviceExt->rootStart =
140 DeviceExt->FATStart + DeviceExt->Boot->FATCount
141 * ((struct _BootSector32 *) (DeviceExt->Boot))->FATSectors32;
142 DeviceExt->dataStart = DeviceExt->rootStart;
143 }
144 else
145 {
146 DbgPrint("FAT16\n");
147 DeviceExt->FatType = FAT16;
148 }
149
150 return STATUS_SUCCESS;
151 }
152
153
154 static NTSTATUS
155 VfatMount (PDEVICE_OBJECT DeviceToMount)
156 /*
157 * FUNCTION: Mount the filesystem
158 */
159 {
160 PDEVICE_OBJECT DeviceObject;
161 PDEVICE_EXTENSION DeviceExt;
162 BOOLEAN RecognizedFS;
163 NTSTATUS Status;
164
165 Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS);
166 if (!NT_SUCCESS(Status))
167 {
168 return Status;
169 }
170
171 if (RecognizedFS == FALSE)
172 {
173 DPRINT("VFAT: Unrecognized Volume\n");
174 return STATUS_UNRECOGNIZED_VOLUME;
175 }
176
177 DPRINT("VFAT: Recognized volume\n");
178
179 Status = IoCreateDevice(VfatDriverObject,
180 sizeof (DEVICE_EXTENSION),
181 NULL,
182 FILE_DEVICE_FILE_SYSTEM,
183 0,
184 FALSE,
185 &DeviceObject);
186 if (!NT_SUCCESS(Status))
187 {
188 return Status;
189 }
190
191 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
192 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
193 /* use same vpb as device disk */
194 DeviceObject->Vpb = DeviceToMount->Vpb;
195 Status = VfatMountDevice (DeviceExt, DeviceToMount);
196 if (!NT_SUCCESS(Status))
197 {
198 /* FIXME: delete device object */
199 return Status;
200 }
201
202 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
203 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
204 DeviceToMount);
205 DeviceExt->StreamStorageDevice = IoCreateStreamFileObject(NULL,
206 DeviceExt->StorageDevice);
207 Status = CcRosInitializeFileCache(DeviceExt->StreamStorageDevice,
208 &DeviceExt->StorageBcb,
209 CACHEPAGESIZE(DeviceExt));
210 if (!NT_SUCCESS(Status))
211 {
212 /* FIXME: delete device object */
213 return Status;
214 }
215
216 if (DeviceExt->FatType == FAT12)
217 {
218 DeviceExt->Fat12StorageDevice =
219 IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
220 Status = CcRosInitializeFileCache(DeviceExt->Fat12StorageDevice,
221 &DeviceExt->Fat12StorageBcb,
222 PAGESIZE * 3);
223 if (!NT_SUCCESS(Status))
224 {
225 /* FIXME: delete device object */
226 return Status;
227 }
228 }
229 ExInitializeResourceLite (&DeviceExt->DirResource);
230 ExInitializeResourceLite (&DeviceExt->FatResource);
231
232 KeInitializeSpinLock (&DeviceExt->FcbListLock);
233 InitializeListHead (&DeviceExt->FcbListHead);
234
235 /* read serial number */
236 if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
237 DeviceObject->Vpb->SerialNumber =
238 ((struct _BootSector *) (DeviceExt->Boot))->VolumeID;
239 else if (DeviceExt->FatType == FAT32)
240 DeviceObject->Vpb->SerialNumber =
241 ((struct _BootSector32 *) (DeviceExt->Boot))->VolumeID;
242
243 /* read volume label */
244 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
245
246 return STATUS_SUCCESS;
247 }
248
249
250 NTSTATUS STDCALL
251 VfatFileSystemControl (PDEVICE_OBJECT DeviceObject, PIRP Irp)
252 /*
253 * FUNCTION: File system control
254 */
255 {
256 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation (Irp);
257 NTSTATUS Status;
258
259 switch (Stack->MinorFunction)
260 {
261 case IRP_MN_USER_FS_REQUEST:
262 DPRINT1("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
263 Status = STATUS_INVALID_DEVICE_REQUEST;
264 break;
265
266 case IRP_MN_MOUNT_VOLUME:
267 Status = VfatMount(Stack->Parameters.Mount.DeviceObject);
268 break;
269
270 case IRP_MN_VERIFY_VOLUME:
271 DPRINT1("VFAT FSC: IRP_MN_VERIFY_VOLUME\n");
272 Status = STATUS_INVALID_DEVICE_REQUEST;
273 break;
274
275 default:
276 DPRINT1("VFAT FSC: MinorFunction %d\n", Stack->MinorFunction);
277 Status = STATUS_INVALID_DEVICE_REQUEST;
278 break;
279 }
280
281 Irp->IoStatus.Status = Status;
282 Irp->IoStatus.Information = 0;
283
284 IoCompleteRequest (Irp, IO_NO_INCREMENT);
285 return (Status);
286 }
287
288
289 NTSTATUS STDCALL
290 DriverEntry(PDRIVER_OBJECT _DriverObject,
291 PUNICODE_STRING RegistryPath)
292 /*
293 * FUNCTION: Called by the system to initalize the driver
294 * ARGUMENTS:
295 * DriverObject = object describing this driver
296 * RegistryPath = path to our configuration entries
297 * RETURNS: Success or failure
298 */
299 {
300 PDEVICE_OBJECT DeviceObject;
301 UNICODE_STRING DeviceName;
302 NTSTATUS Status;
303
304 DbgPrint("VFAT 0.0.6\n");
305
306 VfatDriverObject = _DriverObject;
307
308 RtlInitUnicodeString(&DeviceName,
309 L"\\Device\\Vfat");
310 Status = IoCreateDevice(VfatDriverObject,
311 0,
312 &DeviceName,
313 FILE_DEVICE_FILE_SYSTEM,
314 0,
315 FALSE,
316 &DeviceObject);
317 if (!NT_SUCCESS(Status))
318 {
319 return (Status);
320 }
321
322 DeviceObject->Flags = DO_DIRECT_IO;
323 VfatDriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatClose;
324 VfatDriverObject->MajorFunction[IRP_MJ_CREATE] = VfatCreate;
325 VfatDriverObject->MajorFunction[IRP_MJ_READ] = VfatRead;
326 VfatDriverObject->MajorFunction[IRP_MJ_WRITE] = VfatWrite;
327 VfatDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
328 VfatFileSystemControl;
329 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
330 VfatQueryInformation;
331 VfatDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
332 VfatSetInformation;
333 VfatDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
334 VfatDirectoryControl;
335 VfatDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
336 VfatQueryVolumeInformation;
337 VfatDriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
338 VfatSetVolumeInformation;
339 VfatDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown;
340 VfatDriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatCleanup;
341
342 VfatDriverObject->DriverUnload = NULL;
343
344 IoRegisterFileSystem(DeviceObject);
345
346 return STATUS_SUCCESS;
347 }
348
349 /* EOF */