update for HEAD-2003091401
[reactos.git] / 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$
20  *
21  * COPYRIGHT:        See COPYING in the top level directory
22  * PROJECT:          ReactOS kernel
23  * FILE:             services/fs/vfat/fsctl.c
24  * PURPOSE:          VFAT Filesystem
25  */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <ddk/ntddk.h>
30 #include <wchar.h>
31
32 #include <ntos.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
59    *RecognizedFS = FALSE;
60
61    Size = sizeof(DISK_GEOMETRY);
62    Status = VfatBlockDeviceIoControl(DeviceToMount,
63                                      IOCTL_DISK_GET_DRIVE_GEOMETRY,
64                                      NULL,
65                                      0,
66                                      &DiskGeometry,
67                                      &Size);
68    if (!NT_SUCCESS(Status))
69    {
70       DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
71       return Status;
72    }
73    if (DiskGeometry.MediaType == FixedMedia)
74    {
75       // We have found a hard disk
76       Size = sizeof(PARTITION_INFORMATION);
77       Status = VfatBlockDeviceIoControl(DeviceToMount,
78                                         IOCTL_DISK_GET_PARTITION_INFO,
79                                         NULL,
80                                         0,
81                                         &PartitionInfo,
82                                         &Size);
83       if (!NT_SUCCESS(Status))
84       {
85          DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
86          return Status;
87       }
88 #ifndef NDEBUG
89       DbgPrint("Partition Information:\n");
90       DbgPrint("StartingOffset      %u\n", PartitionInfo.StartingOffset.QuadPart  / 512);
91       DbgPrint("PartitionLength     %u\n", PartitionInfo.PartitionLength.QuadPart / 512);
92       DbgPrint("HiddenSectors       %u\n", PartitionInfo.HiddenSectors);
93       DbgPrint("PartitionNumber     %u\n", PartitionInfo.PartitionNumber);
94       DbgPrint("PartitionType       %u\n", PartitionInfo.PartitionType);
95       DbgPrint("BootIndicator       %u\n", PartitionInfo.BootIndicator);
96       DbgPrint("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
97       DbgPrint("RewritePartition    %u\n", PartitionInfo.RewritePartition);
98 #endif
99       if (PartitionInfo.PartitionType == PARTITION_FAT_12       ||
100           PartitionInfo.PartitionType == PARTITION_FAT_16       ||
101           PartitionInfo.PartitionType == PARTITION_HUGE         ||
102           PartitionInfo.PartitionType == PARTITION_FAT32        ||
103           PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
104           PartitionInfo.PartitionType == PARTITION_XINT13)
105       {
106          *RecognizedFS = TRUE;
107       }
108    }
109    else if (DiskGeometry.MediaType > Unknown && DiskGeometry.MediaType <= RemovableMedia)
110    {
111       *RecognizedFS = TRUE;
112    }
113    if (*RecognizedFS == FALSE)
114    {
115       return STATUS_SUCCESS;
116    }
117
118    Boot = ExAllocatePool(NonPagedPool, DiskGeometry.BytesPerSector);
119    if (Boot == NULL)
120    {
121       *RecognizedFS=FALSE;
122       return STATUS_INSUFFICIENT_RESOURCES;
123    }
124    Offset.QuadPart = 0;
125    Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot);
126    if (NT_SUCCESS(Status))
127    {
128       FatInfo.VolumeID = Boot->VolumeID;
129       FatInfo.FATStart = Boot->ReservedSectors;
130       FatInfo.FATCount = Boot->FATCount;
131       FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
132       FatInfo.BytesPerSector = Boot->BytesPerSector;
133       FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
134       FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
135       FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
136       FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
137       FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
138       FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
139       Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
140       FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
141       if (FatInfo.NumberOfClusters < 4085)
142       {
143          DPRINT("FAT12\n");
144          FatInfo.FatType = FAT12;
145       }
146       else if (FatInfo.NumberOfClusters >= 65525)
147       {
148          DPRINT("FAT32\n");
149          FatInfo.FatType = FAT32;
150          FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
151          FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
152          FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
153       }
154       else
155       {
156          DPRINT("FAT16\n");
157          FatInfo.FatType = FAT16;
158       }
159       if (pFatInfo)
160       {
161          *pFatInfo = FatInfo;
162       }
163    }
164    ExFreePool(Boot);
165    return Status;
166 }
167
168 static NTSTATUS
169 VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
170                 PDEVICE_OBJECT DeviceToMount)
171 /*
172  * FUNCTION: Mounts the device
173  */
174 {
175    NTSTATUS Status;
176    BOOLEAN RecognizedFS;
177
178    DPRINT("Mounting VFAT device...\n");
179
180    Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
181    if (!NT_SUCCESS(Status))
182    {
183       return(Status);
184    }
185
186    if (DeviceExt->FatInfo.BytesPerCluster >= PAGE_SIZE &&
187       (DeviceExt->FatInfo.BytesPerCluster % PAGE_SIZE) != 0)
188    {
189       DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__, __LINE__);
190       KEBUGCHECK(0);
191    }
192    else if (DeviceExt->FatInfo.BytesPerCluster < PAGE_SIZE &&
193       (PAGE_SIZE % DeviceExt->FatInfo.BytesPerCluster) != 0)
194    {
195       DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__, __LINE__);
196       KEBUGCHECK(0);
197    }
198
199    return(STATUS_SUCCESS);
200 }
201
202
203 static NTSTATUS
204 VfatMount (PVFAT_IRP_CONTEXT IrpContext)
205 /*
206  * FUNCTION: Mount the filesystem
207  */
208 {
209    PDEVICE_OBJECT DeviceObject = NULL;
210    PDEVICE_EXTENSION DeviceExt = NULL;
211    BOOLEAN RecognizedFS;
212    NTSTATUS Status;
213    PVFATFCB Fcb = NULL;
214    PVFATFCB VolumeFcb = NULL;
215    PVFATCCB Ccb = NULL;
216    PDEVICE_OBJECT DeviceToMount;
217
218    DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
219
220    assert (IrpContext);
221
222    if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
223    {
224       Status = STATUS_INVALID_DEVICE_REQUEST;
225       goto ByeBye;
226    }
227
228    DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
229
230    Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, NULL);
231    if (!NT_SUCCESS(Status))
232    {
233       goto ByeBye;
234    }
235
236    if (RecognizedFS == FALSE)
237    {
238       DPRINT("VFAT: Unrecognized Volume\n");
239       Status = STATUS_UNRECOGNIZED_VOLUME;
240       goto ByeBye;
241    }
242
243    DPRINT("VFAT: Recognized volume\n");
244    Status = IoCreateDevice(VfatGlobalData->DriverObject,
245                            sizeof (DEVICE_EXTENSION),
246                            NULL,
247                            FILE_DEVICE_FILE_SYSTEM,
248                            0,
249                            FALSE,
250                            &DeviceObject);
251    if (!NT_SUCCESS(Status))
252    {
253       goto ByeBye;
254    }
255
256    DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
257    DeviceExt = (PVOID) DeviceObject->DeviceExtension;
258    RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
259
260    /* use same vpb as device disk */
261    DeviceObject->Vpb = DeviceToMount->Vpb;
262    Status = VfatMountDevice(DeviceExt, DeviceToMount);
263    if (!NT_SUCCESS(Status))
264    {
265       /* FIXME: delete device object */
266       goto ByeBye;
267    }
268
269 #ifndef NDEBUG
270    DbgPrint("BytesPerSector:     %d\n", DeviceExt->FatInfo.BytesPerSector);
271    DbgPrint("SectorsPerCluster:  %d\n", DeviceExt->FatInfo.SectorsPerCluster);
272    DbgPrint("FATCount:           %d\n", DeviceExt->FatInfo.FATCount);
273    DbgPrint("FATSectors:         %d\n", DeviceExt->FatInfo.FATSectors);
274    DbgPrint("RootStart:          %d\n", DeviceExt->FatInfo.rootStart);
275    DbgPrint("DataStart:          %d\n", DeviceExt->FatInfo.dataStart);
276    if (DeviceExt->FatInfo.FatType == FAT32)
277    {
278       DbgPrint("RootCluster:        %d\n", DeviceExt->FatInfo.RootCluster);
279    }
280 #endif
281
282   DeviceExt->StorageDevice = DeviceToMount;
283   DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
284   DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
285   DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
286   DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
287   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
288
289   DPRINT("FsDeviceObject %lx\n", DeviceObject);
290
291    DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
292    Fcb = vfatNewFCB(NULL);
293    if (Fcb == NULL)
294    {
295       Status = STATUS_INSUFFICIENT_RESOURCES;
296       goto ByeBye;
297    }
298    Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
299    if (Ccb == NULL)
300    {
301       Status =  STATUS_INSUFFICIENT_RESOURCES;
302       goto ByeBye;
303    }
304    memset(Ccb, 0, sizeof (VFATCCB));
305    wcscpy(Fcb->PathName, L"$$Fat$$");
306    Fcb->ObjectName = Fcb->PathName;
307    DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
308    DeviceExt->FATFileObject->FsContext = Fcb;
309    DeviceExt->FATFileObject->FsContext2 = Ccb;
310    DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
311    DeviceExt->FATFileObject->PrivateCacheMap = NULL;
312    DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
313    Fcb->FileObject = DeviceExt->FATFileObject;
314
315    Fcb->Flags = FCB_IS_FAT;
316
317    Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
318    Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
319    Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
320
321    if (DeviceExt->FatInfo.FatType != FAT12)
322    {
323       Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, CACHEPAGESIZE(DeviceExt));
324    }
325    else
326    {
327       Status = CcRosInitializeFileCache(DeviceExt->FATFileObject, 2 * PAGE_SIZE);
328    }
329    if (!NT_SUCCESS (Status))
330    {
331       DbgPrint ("CcRosInitializeFileCache failed\n");
332       goto ByeBye;
333    }
334    DeviceExt->LastAvailableCluster = 2;
335    ExInitializeResourceLite(&DeviceExt->DirResource);
336    ExInitializeResourceLite(&DeviceExt->FatResource);
337
338    KeInitializeSpinLock(&DeviceExt->FcbListLock);
339    InitializeListHead(&DeviceExt->FcbListHead);
340
341    VolumeFcb = vfatNewFCB(NULL);
342    if (VolumeFcb == NULL)
343    {
344       Status = STATUS_INSUFFICIENT_RESOURCES;
345       goto ByeBye;
346    }
347    wcscpy(VolumeFcb->PathName, L"$$Volume$$");
348    VolumeFcb->ObjectName = VolumeFcb->PathName;
349    VolumeFcb->Flags = FCB_IS_VOLUME;
350    VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
351    VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
352    VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
353    DeviceExt->VolumeFcb = VolumeFcb;
354
355    ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
356    InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
357    ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
358
359    /* read serial number */
360    DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
361
362    /* read volume label */
363    ReadVolumeLabel(DeviceExt,  DeviceObject->Vpb);
364
365    Status = STATUS_SUCCESS;
366 ByeBye:
367
368   if (!NT_SUCCESS(Status))
369   {
370      // cleanup
371      if (DeviceExt && DeviceExt->FATFileObject)
372         ObDereferenceObject (DeviceExt->FATFileObject);
373      if (Fcb)
374         vfatDestroyFCB(Fcb);
375      if (Ccb)
376         vfatDestroyCCB(Ccb);
377      if (DeviceObject)
378        IoDeleteDevice(DeviceObject);
379      if (VolumeFcb)
380         vfatDestroyFCB(VolumeFcb);
381   }
382   return Status;
383 }
384
385
386 static NTSTATUS
387 VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
388 /*
389  * FUNCTION: Verify the filesystem
390  */
391 {
392   PDEVICE_OBJECT DeviceToVerify;
393   NTSTATUS Status;
394
395   DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);
396
397   DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
398   Status = VfatBlockDeviceIoControl(DeviceToVerify,
399                                     IOCTL_DISK_CHECK_VERIFY,
400                                     NULL,
401                                     0,
402                                     NULL,
403                                     NULL);
404   if (!NT_SUCCESS(Status))
405     {
406       DPRINT1("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
407
408       /* FIXME: Compare volume label */
409
410       DPRINT1("  returning STATUS_WRONG_VOLUME\n");
411
412       return STATUS_WRONG_VOLUME;
413     }
414
415   return STATUS_SUCCESS;
416 }
417
418
419 static NTSTATUS
420 VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
421 {
422    DPRINT("VfatGetVolumeBitmap (IrpContext %x)\n", IrpContext);
423
424    return STATUS_INVALID_DEVICE_REQUEST;
425 }
426
427
428 static NTSTATUS 
429 VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
430 {
431   PIO_STACK_LOCATION Stack;
432    LARGE_INTEGER Vcn;
433    PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
434    PFILE_OBJECT FileObject;
435    ULONG MaxExtentCount;
436    PVFATFCB Fcb;
437    PDEVICE_EXTENSION DeviceExt;
438    ULONG FirstCluster;
439    ULONG CurrentCluster;
440    ULONG LastCluster;
441    NTSTATUS Status;
442
443    DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
444
445    DeviceExt = IrpContext->DeviceExt;
446    FileObject = IrpContext->FileObject;
447    Stack = IrpContext->Stack;
448    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LARGE_INTEGER) ||
449        Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
450    {
451       return STATUS_INVALID_PARAMETER;
452    }
453    if (IrpContext->Irp->UserBuffer == NULL ||
454        Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR))
455    {
456       return STATUS_BUFFER_TOO_SMALL;
457    }
458
459    Fcb = FileObject->FsContext;
460
461    ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
462    
463    Vcn = *(PLARGE_INTEGER)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
464    RetrievalPointers = IrpContext->Irp->UserBuffer;
465
466    MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(GET_RETRIEVAL_DESCRIPTOR)) / sizeof(MAPPING_PAIR));
467
468
469    if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
470    {
471       Status = STATUS_INVALID_PARAMETER;
472       goto ByeBye;
473    }
474
475    CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
476    Status = OffsetToCluster(DeviceExt, FirstCluster, 
477                             Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster, 
478                             &CurrentCluster, FALSE);
479    if (!NT_SUCCESS(Status))
480    {
481       goto ByeBye;
482    }
483
484    RetrievalPointers->StartVcn = Vcn.QuadPart;
485    RetrievalPointers->NumberOfPairs = 0;
486    RetrievalPointers->Pair[0].Lcn = CurrentCluster - 2;
487    LastCluster = 0;
488    while (CurrentCluster != 0xffffffff && RetrievalPointers->NumberOfPairs < MaxExtentCount)
489    {
490
491       LastCluster = CurrentCluster;
492       Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
493       Vcn.QuadPart++;
494       if (!NT_SUCCESS(Status))
495       {
496          goto ByeBye;
497       }
498       
499       if (LastCluster + 1 != CurrentCluster)
500       {
501          RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Vcn = Vcn.QuadPart;
502          RetrievalPointers->NumberOfPairs++;
503          if (RetrievalPointers->NumberOfPairs < MaxExtentCount)
504          {
505             RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Lcn = CurrentCluster - 2;
506          }
507       }
508    }
509    
510    IrpContext->Irp->IoStatus.Information = sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR) * RetrievalPointers->NumberOfPairs;
511    Status = STATUS_SUCCESS;
512
513 ByeBye:
514    ExReleaseResourceLite(&Fcb->MainResource);
515
516    return Status;
517 }
518
519 static NTSTATUS
520 VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
521 {
522    DPRINT("VfatMoveFile(IrpContext %x)\n", IrpContext);
523
524    return STATUS_INVALID_DEVICE_REQUEST;
525 }
526
527 static NTSTATUS
528 VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
529 {
530    PDEVICE_EXTENSION DeviceExt;
531    PROS_QUERY_LCN_MAPPING LcnQuery;
532    PIO_STACK_LOCATION Stack;
533
534    DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
535
536    DeviceExt = IrpContext->DeviceExt;
537    Stack = IrpContext->Stack;
538    if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
539        Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
540    {
541       return STATUS_BUFFER_TOO_SMALL;
542    }
543    LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
544    LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
545    IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
546    return(STATUS_SUCCESS);
547 }
548
549 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
550 /*
551  * FUNCTION: File system control
552  */
553 {
554
555    NTSTATUS Status;
556
557    DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
558
559    assert (IrpContext);
560    assert (IrpContext->Irp);
561    assert (IrpContext->Stack);
562
563    IrpContext->Irp->IoStatus.Information = 0;
564
565    switch (IrpContext->MinorFunction)
566    {
567       case IRP_MN_USER_FS_REQUEST:
568          switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
569          {
570             case FSCTL_GET_VOLUME_BITMAP:
571                Status = VfatGetVolumeBitmap(IrpContext);
572                break;
573             case FSCTL_GET_RETRIEVAL_POINTERS:
574                Status = VfatGetRetrievalPointers(IrpContext);
575                break;
576             case FSCTL_MOVE_FILE:
577                Status = VfatMoveFile(IrpContext);
578                break;
579             case FSCTL_ROS_QUERY_LCN_MAPPING:
580                Status = VfatRosQueryLcnMapping(IrpContext);
581                break;
582             default:
583                Status = STATUS_INVALID_DEVICE_REQUEST;
584          }
585          break;
586
587       case IRP_MN_MOUNT_VOLUME:
588          Status = VfatMount(IrpContext);
589          break;
590
591       case IRP_MN_VERIFY_VOLUME:
592          Status = VfatVerify(IrpContext);
593          break;
594
595       default:
596            DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
597            Status = STATUS_INVALID_DEVICE_REQUEST;
598            break;
599    }
600
601    IrpContext->Irp->IoStatus.Status = Status;
602
603    IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
604    VfatFreeIrpContext(IrpContext);
605    return (Status);
606 }
607