Merging r37048, r37051, r37052, r37055 from the-real-msvc branch
[reactos.git] / reactos / drivers / filesystems / fastfat / fsctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/fs/vfat/fsctl.c
23 * PURPOSE: VFAT Filesystem
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #define NDEBUG
29 #include "vfat.h"
30
31 /* FUNCTIONS ****************************************************************/
32
33 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
34 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
35
36 #define VOLUME_IS_DIRTY 0x00000001
37
38 static NTSTATUS
39 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
40 PBOOLEAN RecognizedFS,
41 PFATINFO pFatInfo)
42 {
43 NTSTATUS Status;
44 PARTITION_INFORMATION PartitionInfo;
45 DISK_GEOMETRY DiskGeometry;
46 FATINFO FatInfo;
47 ULONG Size;
48 ULONG Sectors;
49 LARGE_INTEGER Offset;
50 struct _BootSector* Boot;
51 struct _BootSectorFatX* BootFatX;
52 BOOLEAN PartitionInfoIsValid = FALSE;
53
54 DPRINT("VfatHasFileSystem\n");
55
56 *RecognizedFS = FALSE;
57
58 Size = sizeof(DISK_GEOMETRY);
59 Status = VfatBlockDeviceIoControl(DeviceToMount,
60 IOCTL_DISK_GET_DRIVE_GEOMETRY,
61 NULL,
62 0,
63 &DiskGeometry,
64 &Size,
65 FALSE);
66 if (!NT_SUCCESS(Status))
67 {
68 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
69 return Status;
70 }
71 FatInfo.FixedMedia = DiskGeometry.MediaType == FixedMedia ? TRUE : FALSE;
72 if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia)
73 {
74 // We have found a hard disk
75 Size = sizeof(PARTITION_INFORMATION);
76 Status = VfatBlockDeviceIoControl(DeviceToMount,
77 IOCTL_DISK_GET_PARTITION_INFO,
78 NULL,
79 0,
80 &PartitionInfo,
81 &Size,
82 FALSE);
83 if (!NT_SUCCESS(Status))
84 {
85 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
86 return Status;
87 }
88 PartitionInfoIsValid = TRUE;
89 DPRINT("Partition Information:\n");
90 DPRINT("StartingOffset %u\n", PartitionInfo.StartingOffset.QuadPart / 512);
91 DPRINT("PartitionLength %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
92 DPRINT("HiddenSectors %u\n", PartitionInfo.HiddenSectors);
93 DPRINT("PartitionNumber %u\n", PartitionInfo.PartitionNumber);
94 DPRINT("PartitionType %u\n", PartitionInfo.PartitionType);
95 DPRINT("BootIndicator %u\n", PartitionInfo.BootIndicator);
96 DPRINT("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
97 DPRINT("RewritePartition %u\n", PartitionInfo.RewritePartition);
98 if (PartitionInfo.PartitionType)
99 {
100 if (PartitionInfo.PartitionType == PARTITION_FAT_12 ||
101 PartitionInfo.PartitionType == PARTITION_FAT_16 ||
102 PartitionInfo.PartitionType == PARTITION_HUGE ||
103 PartitionInfo.PartitionType == PARTITION_FAT32 ||
104 PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
105 PartitionInfo.PartitionType == PARTITION_XINT13)
106 {
107 *RecognizedFS = TRUE;
108 }
109 }
110 else if (DiskGeometry.MediaType == RemovableMedia &&
111 PartitionInfo.PartitionNumber > 0 &&
112 PartitionInfo.StartingOffset.QuadPart == 0 &&
113 PartitionInfo.PartitionLength.QuadPart > 0)
114 {
115 /* This is possible a removable media formated as super floppy */
116 *RecognizedFS = TRUE;
117 }
118 }
119 else if (DiskGeometry.MediaType == Unknown)
120 {
121 /*
122 * Floppy disk driver can return Unknown as media type if it
123 * doesn't know yet what floppy in the drive really is. This is
124 * perfectly correct to do under Windows.
125 */
126 *RecognizedFS = TRUE;
127 DiskGeometry.BytesPerSector = 512;
128 }
129 else
130 {
131 *RecognizedFS = TRUE;
132 }
133 if (*RecognizedFS)
134 {
135
136 Boot = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_VFAT);
137 if (Boot == NULL)
138 {
139 return STATUS_INSUFFICIENT_RESOURCES;
140 }
141
142 Offset.QuadPart = 0;
143
144 /* Try to recognize FAT12/FAT16/FAT32 partitions */
145 Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, FALSE);
146 if (NT_SUCCESS(Status))
147 {
148 if (Boot->Signatur1 != 0xaa55)
149 {
150 *RecognizedFS = FALSE;
151 }
152 if (*RecognizedFS &&
153 Boot->BytesPerSector != 512 &&
154 Boot->BytesPerSector != 1024 &&
155 Boot->BytesPerSector != 2048 &&
156 Boot->BytesPerSector != 4096)
157 {
158 DPRINT1("BytesPerSector %d\n", Boot->BytesPerSector);
159 *RecognizedFS = FALSE;
160 }
161
162 if (*RecognizedFS &&
163 Boot->FATCount != 1 &&
164 Boot->FATCount != 2)
165 {
166 DPRINT1("FATCount %d\n", Boot->FATCount);
167 *RecognizedFS = FALSE;
168 }
169
170 if (*RecognizedFS &&
171 Boot->Media != 0xf0 &&
172 Boot->Media != 0xf8 &&
173 Boot->Media != 0xf9 &&
174 Boot->Media != 0xfa &&
175 Boot->Media != 0xfb &&
176 Boot->Media != 0xfc &&
177 Boot->Media != 0xfd &&
178 Boot->Media != 0xfe &&
179 Boot->Media != 0xff)
180 {
181 DPRINT1("Media %02x\n", Boot->Media);
182 *RecognizedFS = FALSE;
183 }
184
185 if (*RecognizedFS &&
186 Boot->SectorsPerCluster != 1 &&
187 Boot->SectorsPerCluster != 2 &&
188 Boot->SectorsPerCluster != 4 &&
189 Boot->SectorsPerCluster != 8 &&
190 Boot->SectorsPerCluster != 16 &&
191 Boot->SectorsPerCluster != 32 &&
192 Boot->SectorsPerCluster != 64 &&
193 Boot->SectorsPerCluster != 128)
194 {
195 DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster);
196 *RecognizedFS = FALSE;
197 }
198
199 if (*RecognizedFS &&
200 Boot->BytesPerSector * Boot->SectorsPerCluster > 32 * 1024)
201 {
202 DPRINT1("ClusterSize %dx\n", Boot->BytesPerSector * Boot->SectorsPerCluster);
203 *RecognizedFS = FALSE;
204 }
205
206 if (*RecognizedFS)
207 {
208 FatInfo.VolumeID = Boot->VolumeID;
209 FatInfo.FATStart = Boot->ReservedSectors;
210 FatInfo.FATCount = Boot->FATCount;
211 FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
212 FatInfo.BytesPerSector = Boot->BytesPerSector;
213 FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
214 FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
215 FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
216 FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
217 FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
218 FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
219 Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
220 FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
221 if (FatInfo.NumberOfClusters < 4085)
222 {
223 DPRINT("FAT12\n");
224 FatInfo.FatType = FAT12;
225 FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
226 }
227 else if (FatInfo.NumberOfClusters >= 65525)
228 {
229 DPRINT("FAT32\n");
230 FatInfo.FatType = FAT32;
231 FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
232 FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
233 FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
234 }
235 else
236 {
237 DPRINT("FAT16\n");
238 FatInfo.FatType = FAT16;
239 FatInfo.RootCluster = FatInfo.rootStart / FatInfo.SectorsPerCluster;
240 }
241 if (PartitionInfoIsValid &&
242 FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
243 {
244 *RecognizedFS = FALSE;
245 }
246
247 if (pFatInfo && *RecognizedFS)
248 {
249 *pFatInfo = FatInfo;
250 }
251 }
252 }
253
254 ExFreePool(Boot);
255 }
256
257 if (!*RecognizedFS && PartitionInfoIsValid)
258 {
259 BootFatX = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _BootSectorFatX), TAG_VFAT);
260 if (BootFatX == NULL)
261 {
262 *RecognizedFS=FALSE;
263 return STATUS_INSUFFICIENT_RESOURCES;
264 }
265
266 Offset.QuadPart = 0;
267
268 /* Try to recognize FATX16/FATX32 partitions (Xbox) */
269 Status = VfatReadDisk(DeviceToMount, &Offset, sizeof(struct _BootSectorFatX), (PUCHAR) BootFatX, FALSE);
270 if (NT_SUCCESS(Status))
271 {
272 *RecognizedFS = TRUE;
273 if (BootFatX->SysType[0] != 'F' ||
274 BootFatX->SysType[1] != 'A' ||
275 BootFatX->SysType[2] != 'T' ||
276 BootFatX->SysType[3] != 'X')
277 {
278 DPRINT1("SysType %c%c%c%c\n", BootFatX->SysType[0], BootFatX->SysType[1], BootFatX->SysType[2], BootFatX->SysType[3]);
279 *RecognizedFS=FALSE;
280 }
281
282 if (*RecognizedFS &&
283 BootFatX->SectorsPerCluster != 1 &&
284 BootFatX->SectorsPerCluster != 2 &&
285 BootFatX->SectorsPerCluster != 4 &&
286 BootFatX->SectorsPerCluster != 8 &&
287 BootFatX->SectorsPerCluster != 16 &&
288 BootFatX->SectorsPerCluster != 32 &&
289 BootFatX->SectorsPerCluster != 64 &&
290 BootFatX->SectorsPerCluster != 128)
291 {
292 DPRINT1("SectorsPerCluster %lu\n", BootFatX->SectorsPerCluster);
293 *RecognizedFS=FALSE;
294 }
295
296 if (*RecognizedFS)
297 {
298 FatInfo.BytesPerSector = DiskGeometry.BytesPerSector;
299 FatInfo.SectorsPerCluster = BootFatX->SectorsPerCluster;
300 FatInfo.rootDirectorySectors = BootFatX->SectorsPerCluster;
301 FatInfo.BytesPerCluster = BootFatX->SectorsPerCluster * DiskGeometry.BytesPerSector;
302 FatInfo.Sectors = (ULONG)(PartitionInfo.PartitionLength.QuadPart / DiskGeometry.BytesPerSector);
303 if (FatInfo.Sectors / FatInfo.SectorsPerCluster < 65525)
304 {
305 DPRINT("FATX16\n");
306 FatInfo.FatType = FATX16;
307 }
308 else
309 {
310 DPRINT("FATX32\n");
311 FatInfo.FatType = FATX32;
312 }
313 FatInfo.VolumeID = BootFatX->VolumeID;
314 FatInfo.FATStart = sizeof(struct _BootSectorFatX) / DiskGeometry.BytesPerSector;
315 FatInfo.FATCount = BootFatX->FATCount;
316 FatInfo.FATSectors =
317 ROUND_UP(FatInfo.Sectors / FatInfo.SectorsPerCluster * (FatInfo.FatType == FATX16 ? 2 : 4), 4096) /
318 FatInfo.BytesPerSector;
319 FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
320 FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
321 FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
322 FatInfo.NumberOfClusters = (FatInfo.Sectors - FatInfo.dataStart) / FatInfo.SectorsPerCluster;
323
324 if (pFatInfo && *RecognizedFS)
325 {
326 *pFatInfo = FatInfo;
327 }
328 }
329 }
330 ExFreePool(BootFatX);
331 }
332
333 DPRINT("VfatHasFileSystem done\n");
334 return Status;
335 }
336
337 static NTSTATUS
338 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
339 PDEVICE_OBJECT DeviceToMount)
340 /*
341 * FUNCTION: Mounts the device
342 */
343 {
344 NTSTATUS Status;
345 BOOLEAN RecognizedFS;
346
347 DPRINT("Mounting VFAT device...\n");
348
349 Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
350 if (!NT_SUCCESS(Status))
351 {
352 return(Status);
353 }
354 DPRINT("MountVfatdev %d, PAGE_SIZE = %d\n", DeviceExt->FatInfo.BytesPerCluster, PAGE_SIZE);
355
356
357 return(STATUS_SUCCESS);
358 }
359
360
361 static NTSTATUS
362 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
363 /*
364 * FUNCTION: Mount the filesystem
365 */
366 {
367 PDEVICE_OBJECT DeviceObject = NULL;
368 PDEVICE_EXTENSION DeviceExt = NULL;
369 BOOLEAN RecognizedFS;
370 NTSTATUS Status;
371 PVFATFCB Fcb = NULL;
372 PVFATFCB VolumeFcb = NULL;
373 PVFATCCB Ccb = NULL;
374 PDEVICE_OBJECT DeviceToMount;
375 UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\$$Fat$$");
376 UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$");
377 ULONG HashTableSize;
378 ULONG eocMark;
379 FATINFO FatInfo;
380
381 DPRINT("VfatMount(IrpContext %p)\n", IrpContext);
382
383 ASSERT(IrpContext);
384
385 if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
386 {
387 Status = STATUS_INVALID_DEVICE_REQUEST;
388 goto ByeBye;
389 }
390
391 DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
392
393 Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, &FatInfo);
394 if (!NT_SUCCESS(Status))
395 {
396 goto ByeBye;
397 }
398
399 if (RecognizedFS == FALSE)
400 {
401 DPRINT("VFAT: Unrecognized Volume\n");
402 Status = STATUS_UNRECOGNIZED_VOLUME;
403 goto ByeBye;
404 }
405
406 /* Use prime numbers for the table size */
407 if (FatInfo.FatType == FAT12)
408 {
409 HashTableSize = 4099; // 4096 = 4 * 1024
410 }
411 else if (FatInfo.FatType == FAT16 ||
412 FatInfo.FatType == FATX16)
413 {
414 HashTableSize = 16411; // 16384 = 16 * 1024
415 }
416 else
417 {
418 HashTableSize = 65537; // 65536 = 64 * 1024;
419 }
420 HashTableSize = FCB_HASH_TABLE_SIZE;
421 DPRINT("VFAT: Recognized volume\n");
422 Status = IoCreateDevice(VfatGlobalData->DriverObject,
423 ROUND_UP(sizeof (DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize,
424 NULL,
425 FILE_DEVICE_DISK_FILE_SYSTEM,
426 0,
427 FALSE,
428 &DeviceObject);
429 if (!NT_SUCCESS(Status))
430 {
431 goto ByeBye;
432 }
433
434 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
435 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
436 RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize);
437 DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)));
438 DeviceExt->HashTableSize = HashTableSize;
439
440 /* use same vpb as device disk */
441 DeviceObject->Vpb = DeviceToMount->Vpb;
442 Status = VfatMountDevice(DeviceExt, DeviceToMount);
443 if (!NT_SUCCESS(Status))
444 {
445 /* FIXME: delete device object */
446 goto ByeBye;
447 }
448
449 DPRINT("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector);
450 DPRINT("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster);
451 DPRINT("FATCount: %d\n", DeviceExt->FatInfo.FATCount);
452 DPRINT("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors);
453 DPRINT("RootStart: %d\n", DeviceExt->FatInfo.rootStart);
454 DPRINT("DataStart: %d\n", DeviceExt->FatInfo.dataStart);
455 if (DeviceExt->FatInfo.FatType == FAT32)
456 {
457 DPRINT("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster);
458 }
459
460 switch (DeviceExt->FatInfo.FatType)
461 {
462 case FAT12:
463 DeviceExt->GetNextCluster = FAT12GetNextCluster;
464 DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
465 DeviceExt->WriteCluster = FAT12WriteCluster;
466 DeviceExt->CleanShutBitMask = 0;
467 break;
468
469 case FAT16:
470 case FATX16:
471 DeviceExt->GetNextCluster = FAT16GetNextCluster;
472 DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
473 DeviceExt->WriteCluster = FAT16WriteCluster;
474 DeviceExt->CleanShutBitMask = 0x8000;
475 break;
476
477 case FAT32:
478 case FATX32:
479 DeviceExt->GetNextCluster = FAT32GetNextCluster;
480 DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
481 DeviceExt->WriteCluster = FAT32WriteCluster;
482 DeviceExt->CleanShutBitMask = 0x80000000;
483 break;
484 }
485
486 if (DeviceExt->FatInfo.FatType == FATX16
487 || DeviceExt->FatInfo.FatType == FATX32)
488 {
489 DeviceExt->Flags |= VCB_IS_FATX;
490 DeviceExt->GetNextDirEntry = FATXGetNextDirEntry;
491 DeviceExt->BaseDateYear = 2000;
492 }
493 else
494 {
495 DeviceExt->GetNextDirEntry = FATGetNextDirEntry;
496 DeviceExt->BaseDateYear = 1980;
497 }
498
499 DeviceExt->StorageDevice = DeviceToMount;
500 DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
501 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
502 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
503 DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
504 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
505
506 DPRINT("FsDeviceObject %p\n", DeviceObject);
507
508 /* Initialize this resource early ... it's used in VfatCleanup */
509 ExInitializeResourceLite(&DeviceExt->DirResource);
510
511 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
512 Fcb = vfatNewFCB(DeviceExt, &NameU);
513 if (Fcb == NULL)
514 {
515 Status = STATUS_INSUFFICIENT_RESOURCES;
516 goto ByeBye;
517 }
518 Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
519 if (Ccb == NULL)
520 {
521 Status = STATUS_INSUFFICIENT_RESOURCES;
522 goto ByeBye;
523 }
524
525 RtlZeroMemory(Ccb, sizeof (VFATCCB));
526 DeviceExt->FATFileObject->FsContext = Fcb;
527 DeviceExt->FATFileObject->FsContext2 = Ccb;
528 DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
529 DeviceExt->FATFileObject->PrivateCacheMap = NULL;
530 DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
531 Fcb->FileObject = DeviceExt->FATFileObject;
532
533 Fcb->Flags |= FCB_IS_FAT;
534
535 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
536 Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
537 Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
538
539 CcInitializeCacheMap(DeviceExt->FATFileObject,
540 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
541 FALSE,
542 &VfatGlobalData->CacheMgrCallbacks,
543 Fcb);
544
545 DeviceExt->LastAvailableCluster = 2;
546 ExInitializeResourceLite(&DeviceExt->FatResource);
547
548 InitializeListHead(&DeviceExt->FcbListHead);
549
550 VolumeFcb = vfatNewFCB(DeviceExt, &VolumeNameU);
551 if (VolumeFcb == NULL)
552 {
553 Status = STATUS_INSUFFICIENT_RESOURCES;
554 goto ByeBye;
555 }
556 VolumeFcb->Flags = FCB_IS_VOLUME;
557 VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
558 VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
559 VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
560 DeviceExt->VolumeFcb = VolumeFcb;
561
562 ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
563 InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
564 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
565
566 /* read serial number */
567 DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
568
569 /* read volume label */
570 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
571
572 /* read clean shutdown bit status */
573 Status = GetNextCluster(DeviceExt, 1, &eocMark);
574 if (NT_SUCCESS(Status))
575 {
576 if (eocMark & DeviceExt->CleanShutBitMask)
577 {
578 /* unset clean shutdown bit */
579 eocMark &= ~DeviceExt->CleanShutBitMask;
580 WriteCluster(DeviceExt, 1, eocMark);
581 VolumeFcb->Flags |= VCB_CLEAR_DIRTY;
582 }
583 }
584 VolumeFcb->Flags |= VCB_IS_DIRTY;
585
586 Status = STATUS_SUCCESS;
587 ByeBye:
588
589 if (!NT_SUCCESS(Status))
590 {
591 // cleanup
592 if (DeviceExt && DeviceExt->FATFileObject)
593 ObDereferenceObject (DeviceExt->FATFileObject);
594 if (Fcb)
595 vfatDestroyFCB(Fcb);
596 if (Ccb)
597 vfatDestroyCCB(Ccb);
598 if (DeviceObject)
599 IoDeleteDevice(DeviceObject);
600 if (VolumeFcb)
601 vfatDestroyFCB(VolumeFcb);
602 }
603 return Status;
604 }
605
606
607 static NTSTATUS
608 VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
609 /*
610 * FUNCTION: Verify the filesystem
611 */
612 {
613 PDEVICE_OBJECT DeviceToVerify;
614 NTSTATUS Status = STATUS_SUCCESS;
615 FATINFO FatInfo;
616 BOOLEAN RecognizedFS;
617 PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
618
619 DPRINT("VfatVerify(IrpContext %p)\n", IrpContext);
620
621 DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
622 Status = VfatBlockDeviceIoControl(DeviceToVerify,
623 IOCTL_DISK_CHECK_VERIFY,
624 NULL,
625 0,
626 NULL,
627 0,
628 TRUE);
629 DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME;
630 if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED)
631 {
632 DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
633 Status = STATUS_WRONG_VOLUME;
634 }
635 else
636 {
637 Status = VfatHasFileSystem(DeviceToVerify, &RecognizedFS, &FatInfo);
638 if (!NT_SUCCESS(Status) || RecognizedFS == FALSE)
639 {
640 Status = STATUS_WRONG_VOLUME;
641 }
642 else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO)))
643 {
644 /*
645 * FIXME:
646 * Preformated floppy disks have very often a serial number of 0000:0000.
647 * We should calculate a crc sum over the sectors from the root directory as secondary volume number.
648 * Each write to the root directory must update this crc sum.
649 */
650
651 }
652 else
653 {
654 Status = STATUS_WRONG_VOLUME;
655 }
656 }
657
658 return Status;
659 }
660
661
662 static NTSTATUS
663 VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
664 {
665 DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext);
666
667 return STATUS_INVALID_DEVICE_REQUEST;
668 }
669
670
671 static NTSTATUS
672 VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
673 {
674 PIO_STACK_LOCATION Stack;
675 LARGE_INTEGER Vcn;
676 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
677 PFILE_OBJECT FileObject;
678 ULONG MaxExtentCount;
679 PVFATFCB Fcb;
680 PDEVICE_EXTENSION DeviceExt;
681 ULONG FirstCluster;
682 ULONG CurrentCluster;
683 ULONG LastCluster;
684 NTSTATUS Status;
685
686 DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext);
687
688 DeviceExt = IrpContext->DeviceExt;
689 FileObject = IrpContext->FileObject;
690 Stack = IrpContext->Stack;
691 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) ||
692 Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
693 {
694 return STATUS_INVALID_PARAMETER;
695 }
696 if (IrpContext->Irp->UserBuffer == NULL ||
697 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))
698 {
699 return STATUS_BUFFER_TOO_SMALL;
700 }
701
702 Fcb = FileObject->FsContext;
703
704 ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
705
706 Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn;
707 RetrievalPointers = IrpContext->Irp->UserBuffer;
708
709 MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0]));
710
711
712 if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
713 {
714 Status = STATUS_INVALID_PARAMETER;
715 goto ByeBye;
716 }
717
718 CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
719 Status = OffsetToCluster(DeviceExt, FirstCluster,
720 Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
721 &CurrentCluster, FALSE);
722 if (!NT_SUCCESS(Status))
723 {
724 goto ByeBye;
725 }
726
727 RetrievalPointers->StartingVcn = Vcn;
728 RetrievalPointers->ExtentCount = 0;
729 RetrievalPointers->Extents[0].Lcn.u.HighPart = 0;
730 RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2;
731 LastCluster = 0;
732 while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount)
733 {
734
735 LastCluster = CurrentCluster;
736 Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
737 Vcn.QuadPart++;
738 if (!NT_SUCCESS(Status))
739 {
740 goto ByeBye;
741 }
742
743 if (LastCluster + 1 != CurrentCluster)
744 {
745 RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn;
746 RetrievalPointers->ExtentCount++;
747 if (RetrievalPointers->ExtentCount < MaxExtentCount)
748 {
749 RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0;
750 RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2;
751 }
752 }
753 }
754
755 IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1));
756 Status = STATUS_SUCCESS;
757
758 ByeBye:
759 ExReleaseResourceLite(&Fcb->MainResource);
760
761 return Status;
762 }
763
764 static NTSTATUS
765 VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
766 {
767 DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext);
768
769 return STATUS_INVALID_DEVICE_REQUEST;
770 }
771
772 #ifdef USE_ROS_CC_AND_FS
773 static NTSTATUS
774 VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
775 {
776 PDEVICE_EXTENSION DeviceExt;
777 PROS_QUERY_LCN_MAPPING LcnQuery;
778 PIO_STACK_LOCATION Stack;
779
780 DPRINT("VfatRosQueryLcnMapping(IrpContext %p)\n", IrpContext);
781
782 DeviceExt = IrpContext->DeviceExt;
783 Stack = IrpContext->Stack;
784 if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
785 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
786 {
787 return STATUS_BUFFER_TOO_SMALL;
788 }
789 LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
790 LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
791 IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
792 return(STATUS_SUCCESS);
793 }
794 #endif
795
796 static NTSTATUS
797 VfatIsVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
798 {
799 PULONG Flags;
800
801 DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext);
802
803 if (IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength != sizeof(ULONG))
804 return STATUS_INVALID_BUFFER_SIZE;
805 else if (!IrpContext->Irp->AssociatedIrp.SystemBuffer)
806 return STATUS_INVALID_USER_BUFFER;
807
808 Flags = (PULONG)IrpContext->Irp->AssociatedIrp.SystemBuffer;
809 *Flags = 0;
810
811 if (IrpContext->DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY
812 && !(IrpContext->DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY))
813 {
814 *Flags |= VOLUME_IS_DIRTY;
815 }
816
817 return STATUS_SUCCESS;
818 }
819
820 static NTSTATUS
821 VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
822 {
823 ULONG eocMark;
824 PDEVICE_EXTENSION DeviceExt;
825 NTSTATUS Status = STATUS_SUCCESS;
826
827 DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext);
828 DeviceExt = IrpContext->DeviceExt;
829
830 if (!(DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY))
831 {
832 Status = GetNextCluster(DeviceExt, 1, &eocMark);
833 if (NT_SUCCESS(Status))
834 {
835 /* unset clean shutdown bit */
836 eocMark &= ~DeviceExt->CleanShutBitMask;
837 Status = WriteCluster(DeviceExt, 1, eocMark);
838 }
839 }
840
841 DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY;
842
843 return Status;
844 }
845
846 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
847 /*
848 * FUNCTION: File system control
849 */
850 {
851
852 NTSTATUS Status;
853
854 DPRINT("VfatFileSystemControl(IrpContext %p)\n", IrpContext);
855
856 ASSERT(IrpContext);
857 ASSERT(IrpContext->Irp);
858 ASSERT(IrpContext->Stack);
859
860 IrpContext->Irp->IoStatus.Information = 0;
861
862 switch (IrpContext->MinorFunction)
863 {
864 case IRP_MN_USER_FS_REQUEST:
865 switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
866 {
867 case FSCTL_GET_VOLUME_BITMAP:
868 Status = VfatGetVolumeBitmap(IrpContext);
869 break;
870 case FSCTL_GET_RETRIEVAL_POINTERS:
871 Status = VfatGetRetrievalPointers(IrpContext);
872 break;
873 case FSCTL_MOVE_FILE:
874 Status = VfatMoveFile(IrpContext);
875 break;
876 #ifdef USE_ROS_CC_AND_FS
877 case FSCTL_ROS_QUERY_LCN_MAPPING:
878 Status = VfatRosQueryLcnMapping(IrpContext);
879 break;
880 #endif
881 case FSCTL_IS_VOLUME_DIRTY:
882 Status = VfatIsVolumeDirty(IrpContext);
883 break;
884 case FSCTL_MARK_VOLUME_DIRTY:
885 Status = VfatMarkVolumeDirty(IrpContext);
886 break;
887 default:
888 Status = STATUS_INVALID_DEVICE_REQUEST;
889 }
890 break;
891
892 case IRP_MN_MOUNT_VOLUME:
893 Status = VfatMount(IrpContext);
894 break;
895
896 case IRP_MN_VERIFY_VOLUME:
897 DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n");
898 Status = VfatVerify(IrpContext);
899 break;
900
901 default:
902 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
903 Status = STATUS_INVALID_DEVICE_REQUEST;
904 break;
905 }
906
907 IrpContext->Irp->IoStatus.Status = Status;
908
909 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
910 VfatFreeIrpContext(IrpContext);
911 return (Status);
912 }