dad30d5e6b040ffea9e1a57d3a9cf3cc56105481
[reactos.git] / reactos / drivers / fs / vfat / 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 /* $Id: fsctl.c,v 1.35 2004/08/05 02:48:18 navaraf Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: drivers/fs/vfat/fsctl.c
24 * PURPOSE: VFAT Filesystem
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <ddk/ntddk.h>
30 #include <ntos/kefuncs.h>
31 #include <rosrtl/string.h>
32 #include <wchar.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 #include "vfat.h"
38
39 /* FUNCTIONS ****************************************************************/
40
41 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
42 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
43
44
45 static NTSTATUS
46 VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
47 PBOOLEAN RecognizedFS,
48 PFATINFO pFatInfo)
49 {
50 NTSTATUS Status;
51 PARTITION_INFORMATION PartitionInfo;
52 DISK_GEOMETRY DiskGeometry;
53 FATINFO FatInfo;
54 ULONG Size;
55 ULONG Sectors;
56 LARGE_INTEGER Offset;
57 struct _BootSector* Boot;
58 BOOL PartitionInfoIsValid = FALSE;
59
60 DPRINT("VfatHasFileSystem\n");
61
62 *RecognizedFS = FALSE;
63
64 Size = sizeof(DISK_GEOMETRY);
65 Status = VfatBlockDeviceIoControl(DeviceToMount,
66 IOCTL_DISK_GET_DRIVE_GEOMETRY,
67 NULL,
68 0,
69 &DiskGeometry,
70 &Size,
71 FALSE);
72 if (!NT_SUCCESS(Status))
73 {
74 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
75 return Status;
76 }
77 FatInfo.FixedMedia = DiskGeometry.MediaType == FixedMedia ? TRUE : FALSE;
78 if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia)
79 {
80 // We have found a hard disk
81 Size = sizeof(PARTITION_INFORMATION);
82 Status = VfatBlockDeviceIoControl(DeviceToMount,
83 IOCTL_DISK_GET_PARTITION_INFO,
84 NULL,
85 0,
86 &PartitionInfo,
87 &Size,
88 FALSE);
89 if (!NT_SUCCESS(Status))
90 {
91 DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
92 return Status;
93 }
94 PartitionInfoIsValid = TRUE;
95 #if defined(DBG) && !defined(NDEBUG)
96 DbgPrint("Partition Information:\n");
97 DbgPrint("StartingOffset %u\n", PartitionInfo.StartingOffset.QuadPart / 512);
98 DbgPrint("PartitionLength %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
99 DbgPrint("HiddenSectors %u\n", PartitionInfo.HiddenSectors);
100 DbgPrint("PartitionNumber %u\n", PartitionInfo.PartitionNumber);
101 DbgPrint("PartitionType %u\n", PartitionInfo.PartitionType);
102 DbgPrint("BootIndicator %u\n", PartitionInfo.BootIndicator);
103 DbgPrint("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
104 DbgPrint("RewritePartition %u\n", PartitionInfo.RewritePartition);
105 #endif
106 if (PartitionInfo.PartitionType)
107 {
108 if (PartitionInfo.PartitionType == PARTITION_FAT_12 ||
109 PartitionInfo.PartitionType == PARTITION_FAT_16 ||
110 PartitionInfo.PartitionType == PARTITION_HUGE ||
111 PartitionInfo.PartitionType == PARTITION_FAT32 ||
112 PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
113 PartitionInfo.PartitionType == PARTITION_XINT13)
114 {
115 *RecognizedFS = TRUE;
116 }
117 }
118 else if (DiskGeometry.MediaType == RemovableMedia &&
119 PartitionInfo.PartitionNumber > 0 &&
120 PartitionInfo.StartingOffset.QuadPart == 0LL &&
121 PartitionInfo.PartitionLength.QuadPart > 0LL)
122 {
123 /* This is possible a removable media formated as super floppy */
124 *RecognizedFS = TRUE;
125 }
126 }
127 /*
128 * Floppy disk driver can return Unknown as media type if it
129 * doesn't know yet what floppy in the drive really is. This is
130 * perfectly correct to do under Windows.
131 */
132 if (DiskGeometry.MediaType == Unknown)
133 {
134 *RecognizedFS = TRUE;
135 DiskGeometry.BytesPerSector = 512;
136 }
137 if (DiskGeometry.MediaType > Unknown && DiskGeometry.MediaType < RemovableMedia )
138 {
139 *RecognizedFS = TRUE;
140 }
141 if (*RecognizedFS == FALSE)
142 {
143 return STATUS_SUCCESS;
144 }
145
146 Boot = ExAllocatePool(NonPagedPool, DiskGeometry.BytesPerSector);
147 if (Boot == NULL)
148 {
149 *RecognizedFS=FALSE;
150 return STATUS_INSUFFICIENT_RESOURCES;
151 }
152
153 Offset.QuadPart = 0;
154
155 Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, FALSE);
156 if (NT_SUCCESS(Status))
157 {
158 if (Boot->Signatur1 != 0xaa55)
159 {
160 DPRINT1("Signature %04x\n", Boot->Signatur1);
161 *RecognizedFS=FALSE;
162 }
163 if (*RecognizedFS &&
164 Boot->BytesPerSector != 512 &&
165 Boot->BytesPerSector != 1024 &&
166 Boot->BytesPerSector != 2048 &&
167 Boot->BytesPerSector != 4096)
168 {
169 DPRINT1("BytesPerSector %d\n", Boot->BytesPerSector);
170 *RecognizedFS=FALSE;
171 }
172
173 if (*RecognizedFS &&
174 Boot->FATCount != 1 &&
175 Boot->FATCount != 2)
176 {
177 DPRINT1("FATCount %d\n", Boot->FATCount);
178 *RecognizedFS=FALSE;
179 }
180
181 if (*RecognizedFS &&
182 Boot->Media != 0xf0 &&
183 Boot->Media != 0xf8 &&
184 Boot->Media != 0xf9 &&
185 Boot->Media != 0xfa &&
186 Boot->Media != 0xfb &&
187 Boot->Media != 0xfc &&
188 Boot->Media != 0xfd &&
189 Boot->Media != 0xfe &&
190 Boot->Media != 0xff)
191 {
192 DPRINT1("Media %02x\n", Boot->Media);
193 *RecognizedFS=FALSE;
194 }
195
196 if (*RecognizedFS &&
197 Boot->SectorsPerCluster != 1 &&
198 Boot->SectorsPerCluster != 2 &&
199 Boot->SectorsPerCluster != 4 &&
200 Boot->SectorsPerCluster != 8 &&
201 Boot->SectorsPerCluster != 16 &&
202 Boot->SectorsPerCluster != 32 &&
203 Boot->SectorsPerCluster != 64 &&
204 Boot->SectorsPerCluster != 128)
205 {
206 DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster);
207 *RecognizedFS=FALSE;
208 }
209
210 if (*RecognizedFS &&
211 Boot->BytesPerSector * Boot->SectorsPerCluster > 32 * 1024)
212 {
213 DPRINT1("ClusterSize %dx\n", Boot->BytesPerSector * Boot->SectorsPerCluster);
214 *RecognizedFS=FALSE;
215 }
216
217 if (*RecognizedFS)
218 {
219 FatInfo.VolumeID = Boot->VolumeID;
220 FatInfo.FATStart = Boot->ReservedSectors;
221 FatInfo.FATCount = Boot->FATCount;
222 FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
223 FatInfo.BytesPerSector = Boot->BytesPerSector;
224 FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
225 FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
226 FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
227 FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
228 FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
229 FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
230 Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
231 FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
232 if (FatInfo.NumberOfClusters < 4085)
233 {
234 DPRINT("FAT12\n");
235 FatInfo.FatType = FAT12;
236 }
237 else if (FatInfo.NumberOfClusters >= 65525)
238 {
239 DPRINT("FAT32\n");
240 FatInfo.FatType = FAT32;
241 FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
242 FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
243 FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
244 }
245 else
246 {
247 DPRINT("FAT16\n");
248 FatInfo.FatType = FAT16;
249 }
250 if (PartitionInfoIsValid &&
251 FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
252 {
253 CHECKPOINT1;
254 *RecognizedFS = FALSE;
255 }
256
257 if (pFatInfo && *RecognizedFS)
258 {
259 *pFatInfo = FatInfo;
260 }
261 }
262 }
263
264 ExFreePool(Boot);
265 DPRINT("VfatHasFileSystem done\n");
266 return Status;
267 }
268
269 static NTSTATUS
270 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
271 PDEVICE_OBJECT DeviceToMount)
272 /*
273 * FUNCTION: Mounts the device
274 */
275 {
276 NTSTATUS Status;
277 BOOLEAN RecognizedFS;
278
279 DPRINT("Mounting VFAT device...\n");
280
281 Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
282 if (!NT_SUCCESS(Status))
283 {
284 return(Status);
285 }
286 DPRINT("MountVfatdev %d, PAGE_SIZE = %d\n", DeviceExt->FatInfo.BytesPerCluster, PAGE_SIZE);
287
288
289 return(STATUS_SUCCESS);
290 }
291
292
293 static NTSTATUS
294 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
295 /*
296 * FUNCTION: Mount the filesystem
297 */
298 {
299 PDEVICE_OBJECT DeviceObject = NULL;
300 PDEVICE_EXTENSION DeviceExt = NULL;
301 BOOLEAN RecognizedFS;
302 NTSTATUS Status;
303 PVFATFCB Fcb = NULL;
304 PVFATFCB VolumeFcb = NULL;
305 PVFATCCB Ccb = NULL;
306 PDEVICE_OBJECT DeviceToMount;
307 UNICODE_STRING NameU;
308
309 DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
310
311 assert (IrpContext);
312
313 if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
314 {
315 Status = STATUS_INVALID_DEVICE_REQUEST;
316 goto ByeBye;
317 }
318
319 DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
320
321 Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, NULL);
322 if (!NT_SUCCESS(Status))
323 {
324 goto ByeBye;
325 }
326
327 if (RecognizedFS == FALSE)
328 {
329 DPRINT("VFAT: Unrecognized Volume\n");
330 Status = STATUS_UNRECOGNIZED_VOLUME;
331 goto ByeBye;
332 }
333
334 DPRINT("VFAT: Recognized volume\n");
335 Status = IoCreateDevice(VfatGlobalData->DriverObject,
336 sizeof (DEVICE_EXTENSION),
337 NULL,
338 FILE_DEVICE_FILE_SYSTEM,
339 0,
340 FALSE,
341 &DeviceObject);
342 if (!NT_SUCCESS(Status))
343 {
344 goto ByeBye;
345 }
346
347 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
348 DeviceExt = (PVOID) DeviceObject->DeviceExtension;
349 RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
350
351 /* use same vpb as device disk */
352 DeviceObject->Vpb = DeviceToMount->Vpb;
353 Status = VfatMountDevice(DeviceExt, DeviceToMount);
354 if (!NT_SUCCESS(Status))
355 {
356 /* FIXME: delete device object */
357 goto ByeBye;
358 }
359
360 #ifndef NDEBUG
361 DbgPrint("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector);
362 DbgPrint("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster);
363 DbgPrint("FATCount: %d\n", DeviceExt->FatInfo.FATCount);
364 DbgPrint("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors);
365 DbgPrint("RootStart: %d\n", DeviceExt->FatInfo.rootStart);
366 DbgPrint("DataStart: %d\n", DeviceExt->FatInfo.dataStart);
367 if (DeviceExt->FatInfo.FatType == FAT32)
368 {
369 DbgPrint("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster);
370 }
371 #endif
372
373 DeviceExt->StorageDevice = DeviceToMount;
374 DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
375 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
376 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
377 DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
378 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
379
380 DPRINT("FsDeviceObject %lx\n", DeviceObject);
381
382 DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
383 RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\$$Fat$$");
384 Fcb = vfatNewFCB(&NameU);
385 if (Fcb == NULL)
386 {
387 Status = STATUS_INSUFFICIENT_RESOURCES;
388 goto ByeBye;
389 }
390 Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
391 if (Ccb == NULL)
392 {
393 Status = STATUS_INSUFFICIENT_RESOURCES;
394 goto ByeBye;
395 }
396
397 memset(Ccb, 0, sizeof (VFATCCB));
398 DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
399 DeviceExt->FATFileObject->FsContext = Fcb;
400 DeviceExt->FATFileObject->FsContext2 = Ccb;
401 DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
402 DeviceExt->FATFileObject->PrivateCacheMap = NULL;
403 DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
404 Fcb->FileObject = DeviceExt->FATFileObject;
405
406 Fcb->Flags = FCB_IS_FAT;
407
408 Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
409 Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
410 Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
411
412 if (DeviceExt->FatInfo.FatType != FAT12)
413 {
414 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, CACHEPAGESIZE(DeviceExt));
415 }
416 else
417 {
418 Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, 2 * PAGE_SIZE);
419 }
420 if (!NT_SUCCESS (Status))
421 {
422 DbgPrint ("CcRosInitializeFileCache failed\n");
423 goto ByeBye;
424 }
425 DeviceExt->LastAvailableCluster = 2;
426 ExInitializeResourceLite(&DeviceExt->DirResource);
427 ExInitializeResourceLite(&DeviceExt->FatResource);
428
429 switch (DeviceExt->FatInfo.FatType)
430 {
431 case FAT12:
432 DeviceExt->GetNextCluster = FAT12GetNextCluster;
433 DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
434 DeviceExt->WriteCluster = FAT12WriteCluster;
435 break;
436
437 case FAT16:
438 DeviceExt->GetNextCluster = FAT16GetNextCluster;
439 DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
440 DeviceExt->WriteCluster = FAT16WriteCluster;
441 break;
442
443 case FAT32:
444 DeviceExt->GetNextCluster = FAT32GetNextCluster;
445 DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
446 DeviceExt->WriteCluster = FAT32WriteCluster;
447 break;
448 }
449
450 InitializeListHead(&DeviceExt->FcbListHead);
451 RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\$$Volume$$");
452
453 VolumeFcb = vfatNewFCB(&NameU);
454 if (VolumeFcb == NULL)
455 {
456 Status = STATUS_INSUFFICIENT_RESOURCES;
457 goto ByeBye;
458 }
459 VolumeFcb->Flags = FCB_IS_VOLUME;
460 VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
461 VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
462 VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
463 DeviceExt->VolumeFcb = VolumeFcb;
464
465 ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
466 InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
467 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
468
469 /* read serial number */
470 DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
471
472 /* read volume label */
473 ReadVolumeLabel(DeviceExt, DeviceObject->Vpb);
474
475 Status = STATUS_SUCCESS;
476 ByeBye:
477
478 if (!NT_SUCCESS(Status))
479 {
480 // cleanup
481 if (DeviceExt && DeviceExt->FATFileObject)
482 ObDereferenceObject (DeviceExt->FATFileObject);
483 if (Fcb)
484 vfatDestroyFCB(Fcb);
485 if (Ccb)
486 vfatDestroyCCB(Ccb);
487 if (DeviceObject)
488 IoDeleteDevice(DeviceObject);
489 if (VolumeFcb)
490 vfatDestroyFCB(VolumeFcb);
491 }
492 return Status;
493 }
494
495
496 static NTSTATUS
497 VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
498 /*
499 * FUNCTION: Verify the filesystem
500 */
501 {
502 PDEVICE_OBJECT DeviceToVerify;
503 NTSTATUS Status = STATUS_SUCCESS;
504 FATINFO FatInfo;
505 BOOLEAN RecognizedFS;
506 PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
507
508 DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);
509
510 DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
511 Status = VfatBlockDeviceIoControl(DeviceToVerify,
512 IOCTL_DISK_CHECK_VERIFY,
513 NULL,
514 0,
515 NULL,
516 0,
517 TRUE);
518 DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME;
519 if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED)
520 {
521 DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
522 Status = STATUS_WRONG_VOLUME;
523 }
524 else
525 {
526 Status = VfatHasFileSystem(DeviceToVerify, &RecognizedFS, &FatInfo);
527 if (!NT_SUCCESS(Status) || RecognizedFS == FALSE)
528 {
529 Status = STATUS_WRONG_VOLUME;
530 }
531 else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO)))
532 {
533 /*
534 * FIXME:
535 * Preformated floppy disks have very often a serial number of 0000:0000.
536 * We should calculate a crc sum over the sectors from the root directory as secondary volume number.
537 * Each write to the root directory must update this crc sum.
538 */
539
540 }
541 else
542 {
543 Status = STATUS_WRONG_VOLUME;
544 }
545 }
546
547 return Status;
548 }
549
550
551 static NTSTATUS
552 VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
553 {
554 DPRINT("VfatGetVolumeBitmap (IrpContext %x)\n", IrpContext);
555
556 return STATUS_INVALID_DEVICE_REQUEST;
557 }
558
559
560 static NTSTATUS
561 VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
562 {
563 PIO_STACK_LOCATION Stack;
564 LARGE_INTEGER Vcn;
565 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
566 PFILE_OBJECT FileObject;
567 ULONG MaxExtentCount;
568 PVFATFCB Fcb;
569 PDEVICE_EXTENSION DeviceExt;
570 ULONG FirstCluster;
571 ULONG CurrentCluster;
572 ULONG LastCluster;
573 NTSTATUS Status;
574
575 DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
576
577 DeviceExt = IrpContext->DeviceExt;
578 FileObject = IrpContext->FileObject;
579 Stack = IrpContext->Stack;
580 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LARGE_INTEGER) ||
581 Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
582 {
583 return STATUS_INVALID_PARAMETER;
584 }
585 if (IrpContext->Irp->UserBuffer == NULL ||
586 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR))
587 {
588 return STATUS_BUFFER_TOO_SMALL;
589 }
590
591 Fcb = FileObject->FsContext;
592
593 ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
594
595 Vcn = *(PLARGE_INTEGER)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
596 RetrievalPointers = IrpContext->Irp->UserBuffer;
597
598 MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(GET_RETRIEVAL_DESCRIPTOR)) / sizeof(MAPPING_PAIR));
599
600
601 if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
602 {
603 Status = STATUS_INVALID_PARAMETER;
604 goto ByeBye;
605 }
606
607 CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
608 Status = OffsetToCluster(DeviceExt, FirstCluster,
609 Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
610 &CurrentCluster, FALSE);
611 if (!NT_SUCCESS(Status))
612 {
613 goto ByeBye;
614 }
615
616 RetrievalPointers->StartVcn = Vcn.QuadPart;
617 RetrievalPointers->NumberOfPairs = 0;
618 RetrievalPointers->Pair[0].Lcn = CurrentCluster - 2;
619 LastCluster = 0;
620 while (CurrentCluster != 0xffffffff && RetrievalPointers->NumberOfPairs < MaxExtentCount)
621 {
622
623 LastCluster = CurrentCluster;
624 Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
625 Vcn.QuadPart++;
626 if (!NT_SUCCESS(Status))
627 {
628 goto ByeBye;
629 }
630
631 if (LastCluster + 1 != CurrentCluster)
632 {
633 RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Vcn = Vcn.QuadPart;
634 RetrievalPointers->NumberOfPairs++;
635 if (RetrievalPointers->NumberOfPairs < MaxExtentCount)
636 {
637 RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Lcn = CurrentCluster - 2;
638 }
639 }
640 }
641
642 IrpContext->Irp->IoStatus.Information = sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR) * RetrievalPointers->NumberOfPairs;
643 Status = STATUS_SUCCESS;
644
645 ByeBye:
646 ExReleaseResourceLite(&Fcb->MainResource);
647
648 return Status;
649 }
650
651 static NTSTATUS
652 VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
653 {
654 DPRINT("VfatMoveFile(IrpContext %x)\n", IrpContext);
655
656 return STATUS_INVALID_DEVICE_REQUEST;
657 }
658
659 static NTSTATUS
660 VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
661 {
662 PDEVICE_EXTENSION DeviceExt;
663 PROS_QUERY_LCN_MAPPING LcnQuery;
664 PIO_STACK_LOCATION Stack;
665
666 DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
667
668 DeviceExt = IrpContext->DeviceExt;
669 Stack = IrpContext->Stack;
670 if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
671 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
672 {
673 return STATUS_BUFFER_TOO_SMALL;
674 }
675 LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
676 LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
677 IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
678 return(STATUS_SUCCESS);
679 }
680
681 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
682 /*
683 * FUNCTION: File system control
684 */
685 {
686
687 NTSTATUS Status;
688
689 DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
690
691 assert (IrpContext);
692 assert (IrpContext->Irp);
693 assert (IrpContext->Stack);
694
695 IrpContext->Irp->IoStatus.Information = 0;
696
697 switch (IrpContext->MinorFunction)
698 {
699 case IRP_MN_USER_FS_REQUEST:
700 switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
701 {
702 case FSCTL_GET_VOLUME_BITMAP:
703 Status = VfatGetVolumeBitmap(IrpContext);
704 break;
705 case FSCTL_GET_RETRIEVAL_POINTERS:
706 Status = VfatGetRetrievalPointers(IrpContext);
707 break;
708 case FSCTL_MOVE_FILE:
709 Status = VfatMoveFile(IrpContext);
710 break;
711 case FSCTL_ROS_QUERY_LCN_MAPPING:
712 Status = VfatRosQueryLcnMapping(IrpContext);
713 break;
714 default:
715 Status = STATUS_INVALID_DEVICE_REQUEST;
716 }
717 break;
718
719 case IRP_MN_MOUNT_VOLUME:
720 Status = VfatMount(IrpContext);
721 break;
722
723 case IRP_MN_VERIFY_VOLUME:
724 DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n");
725 Status = VfatVerify(IrpContext);
726 break;
727
728 default:
729 DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
730 Status = STATUS_INVALID_DEVICE_REQUEST;
731 break;
732 }
733
734 IrpContext->Irp->IoStatus.Status = Status;
735
736 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
737 VfatFreeIrpContext(IrpContext);
738 return (Status);
739 }
740