update for HEAD-2003091401
[reactos.git] / drivers / fs / vfat / fsctl.c
index b66a377..67409a9 100644 (file)
@@ -29,6 +29,8 @@
 #include <ddk/ntddk.h>
 #include <wchar.h>
 
+#include <ntos.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -185,13 +187,13 @@ VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
       (DeviceExt->FatInfo.BytesPerCluster % PAGE_SIZE) != 0)
    {
       DbgPrint("(%s:%d) Invalid cluster size\n", __FILE__, __LINE__);
-      KeBugCheck(0);
+      KEBUGCHECK(0);
    }
    else if (DeviceExt->FatInfo.BytesPerCluster < PAGE_SIZE &&
       (PAGE_SIZE % DeviceExt->FatInfo.BytesPerCluster) != 0)
    {
       DbgPrint("(%s:%d) Invalid cluster size2\n", __FILE__, __LINE__);
-      KeBugCheck(0);
+      KEBUGCHECK(0);
    }
 
    return(STATUS_SUCCESS);
@@ -211,7 +213,7 @@ VfatMount (PVFAT_IRP_CONTEXT IrpContext)
    PVFATFCB Fcb = NULL;
    PVFATFCB VolumeFcb = NULL;
    PVFATCCB Ccb = NULL;
-   LARGE_INTEGER timeout;
+   PDEVICE_OBJECT DeviceToMount;
 
    DPRINT("VfatMount(IrpContext %x)\n", IrpContext);
 
@@ -223,7 +225,9 @@ VfatMount (PVFAT_IRP_CONTEXT IrpContext)
       goto ByeBye;
    }
 
-   Status = VfatHasFileSystem (IrpContext->Stack->Parameters.MountVolume.DeviceObject, &RecognizedFS, NULL);
+   DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
+
+   Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, NULL);
    if (!NT_SUCCESS(Status))
    {
       goto ByeBye;
@@ -254,8 +258,8 @@ VfatMount (PVFAT_IRP_CONTEXT IrpContext)
    RtlZeroMemory(DeviceExt, sizeof(DEVICE_EXTENSION));
 
    /* use same vpb as device disk */
-   DeviceObject->Vpb = IrpContext->Stack->Parameters.MountVolume.DeviceObject->Vpb;
-   Status = VfatMountDevice(DeviceExt, IrpContext->Stack->Parameters.MountVolume.DeviceObject);
+   DeviceObject->Vpb = DeviceToMount->Vpb;
+   Status = VfatMountDevice(DeviceExt, DeviceToMount);
    if (!NT_SUCCESS(Status))
    {
       /* FIXME: delete device object */
@@ -275,7 +279,7 @@ VfatMount (PVFAT_IRP_CONTEXT IrpContext)
    }
 #endif
 
-  DeviceExt->StorageDevice = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
+  DeviceExt->StorageDevice = DeviceToMount;
   DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
   DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
   DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
@@ -303,7 +307,7 @@ VfatMount (PVFAT_IRP_CONTEXT IrpContext)
    DeviceExt->FATFileObject->Flags = DeviceExt->FATFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
    DeviceExt->FATFileObject->FsContext = Fcb;
    DeviceExt->FATFileObject->FsContext2 = Ccb;
-   DeviceExt->FATFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
+   DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
    DeviceExt->FATFileObject->PrivateCacheMap = NULL;
    DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
    Fcb->FileObject = DeviceExt->FATFileObject;
@@ -382,16 +386,165 @@ ByeBye:
 static NTSTATUS
 VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
 /*
- * FUNCTION: Mount the filesystem
+ * FUNCTION: Verify the filesystem
  */
 {
+  PDEVICE_OBJECT DeviceToVerify;
+  NTSTATUS Status;
+
   DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);
 
-  assert(IrpContext);
+  DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
+  Status = VfatBlockDeviceIoControl(DeviceToVerify,
+                                   IOCTL_DISK_CHECK_VERIFY,
+                                   NULL,
+                                   0,
+                                   NULL,
+                                   NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
+
+      /* FIXME: Compare volume label */
+
+      DPRINT1("  returning STATUS_WRONG_VOLUME\n");
+
+      return STATUS_WRONG_VOLUME;
+    }
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
+{
+   DPRINT("VfatGetVolumeBitmap (IrpContext %x)\n", IrpContext);
+
+   return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+
+static NTSTATUS 
+VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
+{
+  PIO_STACK_LOCATION Stack;
+   LARGE_INTEGER Vcn;
+   PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
+   PFILE_OBJECT FileObject;
+   ULONG MaxExtentCount;
+   PVFATFCB Fcb;
+   PDEVICE_EXTENSION DeviceExt;
+   ULONG FirstCluster;
+   ULONG CurrentCluster;
+   ULONG LastCluster;
+   NTSTATUS Status;
+
+   DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
+
+   DeviceExt = IrpContext->DeviceExt;
+   FileObject = IrpContext->FileObject;
+   Stack = IrpContext->Stack;
+   if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LARGE_INTEGER) ||
+       Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
+   {
+      return STATUS_INVALID_PARAMETER;
+   }
+   if (IrpContext->Irp->UserBuffer == NULL ||
+       Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR))
+   {
+      return STATUS_BUFFER_TOO_SMALL;
+   }
+
+   Fcb = FileObject->FsContext;
+
+   ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
+   
+   Vcn = *(PLARGE_INTEGER)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
+   RetrievalPointers = IrpContext->Irp->UserBuffer;
+
+   MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(GET_RETRIEVAL_DESCRIPTOR)) / sizeof(MAPPING_PAIR));
+
+
+   if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
+   {
+      Status = STATUS_INVALID_PARAMETER;
+      goto ByeBye;
+   }
+
+   CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
+   Status = OffsetToCluster(DeviceExt, FirstCluster, 
+                            Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster, 
+                           &CurrentCluster, FALSE);
+   if (!NT_SUCCESS(Status))
+   {
+      goto ByeBye;
+   }
+
+   RetrievalPointers->StartVcn = Vcn.QuadPart;
+   RetrievalPointers->NumberOfPairs = 0;
+   RetrievalPointers->Pair[0].Lcn = CurrentCluster - 2;
+   LastCluster = 0;
+   while (CurrentCluster != 0xffffffff && RetrievalPointers->NumberOfPairs < MaxExtentCount)
+   {
+
+      LastCluster = CurrentCluster;
+      Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
+      Vcn.QuadPart++;
+      if (!NT_SUCCESS(Status))
+      {
+         goto ByeBye;
+      }
+      
+      if (LastCluster + 1 != CurrentCluster)
+      {
+        RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Vcn = Vcn.QuadPart;
+        RetrievalPointers->NumberOfPairs++;
+        if (RetrievalPointers->NumberOfPairs < MaxExtentCount)
+        {
+           RetrievalPointers->Pair[RetrievalPointers->NumberOfPairs].Lcn = CurrentCluster - 2;
+        }
+      }
+   }
+   
+   IrpContext->Irp->IoStatus.Information = sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR) * RetrievalPointers->NumberOfPairs;
+   Status = STATUS_SUCCESS;
+
+ByeBye:
+   ExReleaseResourceLite(&Fcb->MainResource);
+
+   return Status;
+}
 
-  return(STATUS_INVALID_DEVICE_REQUEST);
+static NTSTATUS
+VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
+{
+   DPRINT("VfatMoveFile(IrpContext %x)\n", IrpContext);
+
+   return STATUS_INVALID_DEVICE_REQUEST;
 }
 
+static NTSTATUS
+VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
+{
+   PDEVICE_EXTENSION DeviceExt;
+   PROS_QUERY_LCN_MAPPING LcnQuery;
+   PIO_STACK_LOCATION Stack;
+
+   DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);
+
+   DeviceExt = IrpContext->DeviceExt;
+   Stack = IrpContext->Stack;
+   if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
+       Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
+   {
+      return STATUS_BUFFER_TOO_SMALL;
+   }
+   LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
+   LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
+   IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
+   return(STATUS_SUCCESS);
+}
 
 NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
 /*
@@ -404,12 +557,31 @@ NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
    DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);
 
    assert (IrpContext);
+   assert (IrpContext->Irp);
+   assert (IrpContext->Stack);
+
+   IrpContext->Irp->IoStatus.Information = 0;
 
    switch (IrpContext->MinorFunction)
    {
       case IRP_MN_USER_FS_REQUEST:
-         DPRINT("VFAT FSC: IRP_MN_USER_FS_REQUEST\n");
-        Status = STATUS_INVALID_DEVICE_REQUEST;
+         switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
+        {
+           case FSCTL_GET_VOLUME_BITMAP:
+               Status = VfatGetVolumeBitmap(IrpContext);
+              break;
+           case FSCTL_GET_RETRIEVAL_POINTERS:
+               Status = VfatGetRetrievalPointers(IrpContext);
+              break;
+           case FSCTL_MOVE_FILE:
+              Status = VfatMoveFile(IrpContext);
+              break;
+           case FSCTL_ROS_QUERY_LCN_MAPPING:
+              Status = VfatRosQueryLcnMapping(IrpContext);
+              break;
+           default:
+              Status = STATUS_INVALID_DEVICE_REQUEST;
+        }
         break;
 
       case IRP_MN_MOUNT_VOLUME:
@@ -427,7 +599,6 @@ NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
    }
 
    IrpContext->Irp->IoStatus.Status = Status;
-   IrpContext->Irp->IoStatus.Information = 0;
 
    IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
    VfatFreeIrpContext(IrpContext);