- Improved the reading and writing of fragmented files.
authorHartmut Birr <osexpert@googlemail.com>
Sat, 15 May 2004 23:00:02 +0000 (23:00 +0000)
committerHartmut Birr <osexpert@googlemail.com>
Sat, 15 May 2004 23:00:02 +0000 (23:00 +0000)
svn path=/trunk/; revision=9412

reactos/drivers/fs/vfat/blockdev.c
reactos/drivers/fs/vfat/misc.c
reactos/drivers/fs/vfat/rw.c
reactos/drivers/fs/vfat/vfat.h

index 529f857..44fea0e 100644 (file)
@@ -38,12 +38,53 @@ VfatReadWriteCompletion (IN PDEVICE_OBJECT DeviceObject,
      }
 
    *Irp->UserIosb = Irp->IoStatus;
-   KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
+   if (Irp->PendingReturned)
+     {
+       KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
+     }
+
    IoFreeIrp(Irp);
 
    return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
+NTSTATUS STDCALL
+VfatReadWritePartialCompletion (IN PDEVICE_OBJECT DeviceObject,
+                               IN PIRP Irp,
+                               IN PVOID Context)
+{
+  PVFAT_IRP_CONTEXT IrpContext;
+  PMDL Mdl;
+
+  DPRINT("VfatReadWritePartialCompletion() called\n");
+
+  IrpContext = (PVFAT_IRP_CONTEXT)Context;
+
+  while ((Mdl = Irp->MdlAddress))
+    {
+      Irp->MdlAddress = Mdl->Next;
+      IoFreeMdl(Mdl);
+    }
+  if (Irp->PendingReturned)
+    {
+      IrpContext->Flags |= IRPCONTEXT_PENDINGRETURNED;
+    }
+  if (!NT_SUCCESS(Irp->IoStatus.Status))
+    {
+      IrpContext->Irp->IoStatus.Status = Irp->IoStatus.Status;
+    }
+  if (0 == InterlockedDecrement((PLONG)&IrpContext->RefCount) &&
+      IrpContext->Flags & IRPCONTEXT_PENDINGRETURNED)
+    {
+      KeSetEvent(&IrpContext->Event, IO_NO_INCREMENT, FALSE);
+    }
+  IoFreeIrp(Irp);
+
+  DPRINT("VfatReadWritePartialCompletion() done\n");
+
+  return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
 NTSTATUS
 VfatReadDisk (IN PDEVICE_OBJECT pDeviceObject,
              IN PLARGE_INTEGER ReadOffset,
@@ -113,29 +154,100 @@ VfatReadDisk (IN PDEVICE_OBJECT pDeviceObject,
 }
 
 NTSTATUS
-VfatWriteDisk (IN PDEVICE_OBJECT pDeviceObject,
-              IN PLARGE_INTEGER WriteOffset,
-              IN ULONG WriteLength,
-              IN PUCHAR Buffer)
+VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
+                    IN PLARGE_INTEGER ReadOffset,
+                    IN ULONG ReadLength,
+                    ULONG BufferOffset,
+                    IN BOOLEAN Wait)
 {
   PIRP Irp;
-  IO_STATUS_BLOCK IoStatus;
-  KEVENT event;
   NTSTATUS Status;
+  PVOID Buffer;
 
-  DPRINT ("VfatWriteSectors(pDeviceObject %x, Offset %I64x, Size %d, Buffer %x)\n",
-         pDeviceObject, WriteOffset->QuadPart, WriteLength, Buffer);
+  DPRINT ("VfatReadDiskPartial(IrpContext %x, ReadOffset %I64x, ReadLength %d, BufferOffset %x, Wait %d)\n",
+         IrpContext, ReadOffset->QuadPart, ReadLength, BufferOffset, Wait);
 
-  KeInitializeEvent (&event, NotificationEvent, FALSE);
+  DPRINT ("Building synchronous FSD Request...\n");
+
+  Buffer = MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;
+
+  Irp = IoBuildSynchronousFsdRequest (IRP_MJ_READ,
+                                      IrpContext->DeviceExt->StorageDevice,
+                                     NULL,
+                                     ReadLength,
+                                     ReadOffset,
+                                     NULL,
+                                      NULL);
+  if (Irp == NULL)
+    {
+      DPRINT("IoBuildSynchronousFsdRequest failed\n");
+      return(STATUS_UNSUCCESSFUL);
+    }
+
+  if (!IoAllocateMdl(Buffer, ReadLength, FALSE, FALSE, Irp))
+    {
+      DPRINT("IoAllocateMdl failed\n");
+      IoFreeIrp(Irp);
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, ReadLength);
+
+  IoSetCompletionRoutine(Irp,
+                         VfatReadWritePartialCompletion,
+                        IrpContext,
+                        TRUE,
+                        TRUE,
+                        TRUE);
+
+  if (Wait)
+    {
+      KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
+      IrpContext->RefCount = 1;
+    }
+  else
+    {
+      InterlockedIncrement((PLONG)&IrpContext->RefCount);
+    }
+
+  DPRINT ("Calling IO Driver... with irp %x\n", Irp);
+  Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp);
+
+  if (Wait && Status == STATUS_PENDING)
+    {
+      KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
+      Status = IrpContext->Irp->IoStatus.Status;
+    }
+
+  DPRINT("%x\n", Status);
+  return Status;
+}
+
+
+NTSTATUS
+VfatWriteDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
+                     IN PLARGE_INTEGER WriteOffset,
+                     IN ULONG WriteLength,
+                     IN ULONG BufferOffset,
+                     IN BOOLEAN Wait)
+{
+  PIRP Irp;
+  NTSTATUS Status;
+  PVOID Buffer;
+
+  DPRINT ("VfatWriteDiskPartial(IrpContext %x, WriteOffset %I64x, WriteLength %d, BufferOffset %x, Wait %d)\n",
+         IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait);
+
+  Buffer = MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;
 
   DPRINT ("Building synchronous FSD Request...\n");
   Irp = IoBuildSynchronousFsdRequest (IRP_MJ_WRITE,
-                                     pDeviceObject,
-                                     Buffer,
+                                     IrpContext->DeviceExt->StorageDevice,
+                                     NULL,
                                      WriteLength,
                                      WriteOffset, 
-                                     &event
-                                     &IoStatus);
+                                     NULL
+                                     NULL);
 
   if (!Irp)
     {
@@ -143,32 +255,41 @@ VfatWriteDisk (IN PDEVICE_OBJECT pDeviceObject,
       return (STATUS_UNSUCCESSFUL);
     }
 
+  if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp))
+    {
+      DPRINT("IoAllocateMdl failed\n");
+      IoFreeIrp(Irp);
+      return STATUS_UNSUCCESSFUL;
+    }
+  IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength);
+
   IoSetCompletionRoutine(Irp,
-                        VfatReadWriteCompletion,
-                        NULL,
+                         VfatReadWritePartialCompletion,
+                        IrpContext,
                         TRUE,
                         TRUE,
                         TRUE);
 
-  DPRINT ("Calling IO Driver...\n");
-  Status = IoCallDriver (pDeviceObject, Irp);
-
-  DPRINT ("Waiting for IO Operation...\n");
-  if (Status == STATUS_PENDING)
+  if (Wait)
     {
-      KeWaitForSingleObject (&event, Suspended, KernelMode, FALSE, NULL);
-      DPRINT ("Getting IO Status...\n");
-      Status = IoStatus.Status;
+      KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
+      IrpContext->RefCount = 1;
+    }
+  else
+    {
+      InterlockedIncrement((PLONG)&IrpContext->RefCount);
     }
 
-  if (!NT_SUCCESS (Status))
+
+  DPRINT ("Calling IO Driver...\n");
+  Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp);
+  if (Wait && Status == STATUS_PENDING)
     {
-      DPRINT ("IO failed!!! VfatWriteSectors : Error code: %x\n", Status);
-      return (Status);
+      KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
+      Status = IrpContext->Irp->IoStatus.Status;
     }
 
-  DPRINT ("Block request succeeded\n");
-  return (STATUS_SUCCESS);
+  return Status;
 }
 
 NTSTATUS
@@ -188,9 +309,9 @@ VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject,
 
   DPRINT("VfatBlockDeviceIoControl(DeviceObject %x, CtlCode %x, "
          "InputBuffer %x, InputBufferSize %x, OutputBuffer %x, "
-         "POutputBufferSize %x (%x)\n", DeviceObject, CtlCode,
-         InputBuffer, InputBufferSize, OutputBuffer, pOutputBufferSize,
-         pOutputBufferSize ? *pOutputBufferSize : 0);
+         "OutputBufferSize %x (%x)\n", DeviceObject, CtlCode,
+         InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize,
+         OutputBufferSize ? *OutputBufferSize : 0);
 
   KeInitializeEvent (&Event, NotificationEvent, FALSE);
 
index 2226132..fe2eb8f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.12 2004/03/04 01:29:24 gdalsnes Exp $
+/* $Id: misc.c,v 1.13 2004/05/15 23:00:02 hbirr Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -164,7 +164,7 @@ PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
    IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
    if (IrpContext)
    {
-      RtlZeroMemory(IrpContext, sizeof(IrpContext));
+      RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
       IrpContext->Irp = Irp;
       IrpContext->DeviceObject = DeviceObject;
       IrpContext->DeviceExt = DeviceObject->DeviceExtension;
@@ -173,6 +173,7 @@ PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
       MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
       IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
       IrpContext->FileObject = IrpContext->Stack->FileObject;
+      IrpContext->Flags = 0;
       if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
           MajorFunction == IRP_MJ_DEVICE_CONTROL ||
           MajorFunction == IRP_MJ_SHUTDOWN)
@@ -185,6 +186,8 @@ PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
       {
          IrpContext->Flags |= IRPCONTEXT_CANWAIT;
       }
+      KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
+      IrpContext->RefCount = 0;
    }
    return IrpContext;
 }
index 9c5f55e..9facfb4 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $Id: rw.c,v 1.65 2004/03/31 03:30:36 jimtabor Exp $
+/* $Id: rw.c,v 1.66 2004/05/15 23:00:02 hbirr Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -114,8 +114,10 @@ OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
 }
 
 NTSTATUS
-VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
-                  ULONG Length, LARGE_INTEGER ReadOffset, PULONG LengthRead)
+VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, 
+                  ULONG Length, 
+                 LARGE_INTEGER ReadOffset, 
+                 PULONG LengthRead)
 /*
  * FUNCTION: Reads data from a file
  */
@@ -133,6 +135,7 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
   ULONG BytesDone;
   ULONG BytesPerSector;
   ULONG BytesPerCluster;
+  ULONG Count;
 
   /* PRECONDITION */
   assert (IrpContext);
@@ -142,9 +145,9 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
   assert (IrpContext->FileObject);
   assert (IrpContext->FileObject->FsContext2 != NULL);
 
-  DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, Buffer %x, "
+  DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, "
         "Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
-        IrpContext->FileObject, Buffer, Length, ReadOffset.QuadPart);
+        IrpContext->FileObject, Length, ReadOffset.QuadPart);
 
   *LengthRead = 0;
 
@@ -161,7 +164,7 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
   if (Fcb->Flags & FCB_IS_FAT)
   {
     ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
-    Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer, FALSE);
+    Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
 
     if (NT_SUCCESS(Status))
     {
@@ -176,7 +179,7 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
   /* Is this a read of the Volume ? */
   if (Fcb->Flags & FCB_IS_VOLUME)
   {
-    Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer, FALSE);
+    Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
     if (NT_SUCCESS(Status))
     {
       *LengthRead = Length;
@@ -206,10 +209,10 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
 
     // Fire up the read command
     
-    Status = VfatReadDisk (DeviceExt->StorageDevice, &ReadOffset, Length, Buffer, FALSE);
+    Status = VfatReadDiskPartial (IrpContext, &ReadOffset, Length, 0, TRUE);
     if (NT_SUCCESS(Status))
     {
-      *LengthRead += Length;
+      *LengthRead = Length;
     }
     return Status;
   }
@@ -231,7 +234,11 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
   Ccb->LastCluster = CurrentCluster;
   Ccb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
 
-  while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+  KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
+  IrpContext->RefCount = 1;
+  Count = 0;
+
+  while (Length > 0 && CurrentCluster != 0xffffffff)
   {
     StartCluster = CurrentCluster;
     StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
@@ -267,32 +274,40 @@ VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
     Ccb->LastCluster = StartCluster + (ClusterCount - 1);
     Ccb->LastOffset = ReadOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
 
-    // Fire up the read command
-    Status = VfatReadDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer, FALSE);
+    Count++;
 
-    if (NT_SUCCESS(Status))
-    {
-      *LengthRead += BytesDone;
-/* GCC allows arithmetics on the void type. Conforming compilers do not. */
-#ifdef __GNUC__
-      Buffer += BytesDone;
-#else
+    // Fire up the read command
+    Status = VfatReadDiskPartial (IrpContext, &StartOffset, BytesDone, *LengthRead, FALSE);
+    if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
       {
-        char* pBuf = (char*)Buffer + BytesDone;
-        Buffer = (PVOID)pBuf;
+        break;
       }
-#endif
-      Length -= BytesDone;
-      ReadOffset.u.LowPart += BytesDone;
-    }
+    *LengthRead += BytesDone;
+    Length -= BytesDone;
+    ReadOffset.u.LowPart += BytesDone;
   }
+  if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
+    {
+      KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
+    }
+  if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
+    {
+      if (Length > 0)
+        {
+         Status = STATUS_UNSUCCESSFUL;
+       }
+      else
+        {
+          Status = IrpContext->Irp->IoStatus.Status;
+       }
+    }
   return Status;
 }
 
-NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
-                           PVOID Buffer,
-                           ULONG Length,
-                           LARGE_INTEGER WriteOffset)
+NTSTATUS 
+VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
+                 ULONG Length,
+                 LARGE_INTEGER WriteOffset)
 {
    PDEVICE_EXTENSION DeviceExt;
    PVFATFCB Fcb;
@@ -308,6 +323,7 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
    ULONG BytesPerSector;
    ULONG BytesPerCluster;
    LARGE_INTEGER StartOffset;
+   ULONG BufferOffset;
 
    /* PRECONDITION */
    assert (IrpContext);
@@ -322,9 +338,9 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
    BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
    BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
 
-   DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, Buffer %x, "
+   DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, "
          "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt,
-         IrpContext->FileObject, Buffer, Length, WriteOffset,
+         IrpContext->FileObject, Length, WriteOffset,
          &Fcb->PathNameU);
 
    assert(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
@@ -334,7 +350,7 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
    // Is this a write of the volume ?
    if (Fcb->Flags & FCB_IS_VOLUME)
    {
-      Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
+      Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE);
       if (!NT_SUCCESS(Status))
       {
          DPRINT1("Volume writing failed, Status %x\n", Status);
@@ -346,15 +362,25 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
    if (Fcb->Flags & FCB_IS_FAT)
    {
       WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
+      IrpContext->RefCount = 1;
       for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
       {
-         Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
-         if (!NT_SUCCESS(Status))
+         Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE);
+         if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
          {
             DPRINT1("FAT writing failed, Status %x\n", Status);
+           break;
          }
         WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
       }
+      if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
+        {
+         KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
+       }
+      if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
+        {
+         Status = IrpContext->Irp->IoStatus.Status;
+       }
       return Status;
    }
 
@@ -370,7 +396,7 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
       // Directory of FAT12/16 needs a special handling
       WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
       // Fire up the write command
-      Status = VfatWriteDisk (DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
+      Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE);
       return Status;
    }
 
@@ -394,7 +420,11 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
    Ccb->LastCluster = CurrentCluster;
    Ccb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
 
-   while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+   IrpContext->RefCount = 1;
+   Count = 0;
+   BufferOffset = 0;
+
+   while (Length > 0 && CurrentCluster != 0xffffffff)
    {
       StartCluster = CurrentCluster;
       StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
@@ -431,22 +461,31 @@ NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
       Ccb->LastOffset = WriteOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
 
       // Fire up the write command
-      Status = VfatWriteDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
-      if (NT_SUCCESS(Status))
-      {
-/* GCC allows arithmetics on the void type. Conforming compilers do not. */
-#ifdef __GNUC__
-         Buffer += BytesDone;
-#else
-         {
-            char* pBuf = (char*)Buffer + BytesDone;
-            Buffer = (PVOID)pBuf;
-         }
-#endif
-         Length -= BytesDone;
-         WriteOffset.u.LowPart += BytesDone;
-      }
+      Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE);
+      Count++;
+      if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
+        {
+         break;
+       }
+      BufferOffset += BytesDone;
+      Length -= BytesDone;
+      WriteOffset.u.LowPart += BytesDone;
    }
+   if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
+     {
+       KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
+     }
+   if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
+     {
+       if (Length > 0)
+         {
+          Status = STATUS_UNSUCCESSFUL;
+        }
+       else
+         {
+          Status = IrpContext->Irp->IoStatus.Status;
+        }
+     }
    return Status;
 }
 
@@ -486,12 +525,10 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
 
    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
-      PIO_STACK_LOCATION Stack;
       PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
-      IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
-      Stack = IoGetNextIrpStackLocation(IrpContext->Irp);
-      Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
-      DPRINT("Read from page file, disk offset %I64x\n", Stack->Parameters.Read.ByteOffset.QuadPart);
+      IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
+      IoSkipCurrentIrpStackLocation(IrpContext->Irp);
+      DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart);
       Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
       VfatFreeIrpContext(IrpContext);
       return Status;
@@ -527,7 +564,7 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
       if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
       {
          DPRINT("%d %d\n", ByteOffset.u.LowPart, Length);
-         // non chached read must be sector aligned
+         // non cached read must be sector aligned
          Status = STATUS_INVALID_PARAMETER;
          goto ByeBye;
       }
@@ -569,6 +606,13 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
       }
    }
 
+   Buffer = VfatGetUserBuffer(IrpContext->Irp);
+   if (!Buffer)
+     {
+       Status = STATUS_INVALID_USER_BUFFER;
+       goto ByeBye;
+     }
+
    if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
      !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
    {
@@ -581,13 +625,6 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
          Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
       }
 
-      Buffer = VfatGetUserBuffer(IrpContext->Irp);
-      if (!Buffer)
-      {
-         Status = STATUS_INVALID_USER_BUFFER;
-         goto ByeBye;
-      }
-
       CHECKPOINT;
       if (IrpContext->FileObject->PrivateCacheMap == NULL)
       {
@@ -621,14 +658,13 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
          Length = (ULONG)(ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart);
       }
 
-      Buffer = VfatGetUserBuffer(IrpContext->Irp);
-      if (!Buffer)
-      {
-         Status = STATUS_INVALID_USER_BUFFER;
-         goto ByeBye;
-      }
+      Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
+      if (!NT_SUCCESS(Status))
+        {
+          goto ByeBye;
+        }
 
-      Status = VfatReadFileData(IrpContext, Buffer, Length, ByteOffset, &ReturnedLength);
+      Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength);
 /**/
       if (Status == STATUS_VERIFY_REQUIRED)
       {
@@ -639,7 +675,7 @@ VfatRead(PVFAT_IRP_CONTEXT IrpContext)
 
          if (NT_SUCCESS(Status))
          {
-            Status = VfatReadFileData(IrpContext, Buffer, Length,
+            Status = VfatReadFileData(IrpContext, Length,
                                       ByteOffset, &ReturnedLength);
          }
 
@@ -725,12 +761,10 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
 
    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
-      PIO_STACK_LOCATION Stack;
       PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
-      IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
-      Stack = IoGetNextIrpStackLocation(IrpContext->Irp);
-      Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
-      DPRINT("Write to page file, disk offset %I64x\n", Stack->Parameters.Write.ByteOffset.QuadPart);
+      IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
+      IoSkipCurrentIrpStackLocation(IrpContext->Irp);
+      DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart);
       Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
       VfatFreeIrpContext(IrpContext);
       return Status;
@@ -768,7 +802,7 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
    {
       if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
       {
-         // non chached write must be sector aligned
+         // non cached write must be sector aligned
          Status = STATUS_INVALID_PARAMETER;
          goto ByeBye;
       }
@@ -776,6 +810,9 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
 
    if (Length == 0)
    {
+      /* FIXME:
+       *   Update last write time
+       */
       IrpContext->Irp->IoStatus.Information = 0;
       Status = STATUS_SUCCESS;
       goto ByeBye;
@@ -850,6 +887,14 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
    OldFileSize = Fcb->RFCB.FileSize;
    OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
 
+   Buffer = VfatGetUserBuffer(IrpContext->Irp);
+   if (!Buffer)
+     {
+       Status = STATUS_INVALID_USER_BUFFER;
+       goto ByeBye;
+     }
+
+
    if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) && 
        !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
@@ -872,13 +917,6 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
       // cached write
       CHECKPOINT;
 
-      Buffer = VfatGetUserBuffer(IrpContext->Irp);
-      if (!Buffer)
-      {
-         Status = STATUS_INVALID_USER_BUFFER;
-         goto ByeBye;
-      }
-      CHECKPOINT;
       if (IrpContext->FileObject->PrivateCacheMap == NULL)
       {
          ULONG CacheSize;
@@ -914,14 +952,14 @@ NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
       {
          CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
       }
-      Buffer = VfatGetUserBuffer(IrpContext->Irp);
-      if (!Buffer)
-      {
-         Status = STATUS_INVALID_USER_BUFFER;
-         goto ByeBye;
-      }
 
-      Status = VfatWriteFileData(IrpContext, Buffer, Length, ByteOffset);
+      Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
+      if (!NT_SUCCESS(Status))
+        {
+         goto ByeBye;
+       }
+
+      Status = VfatWriteFileData(IrpContext, Length, ByteOffset);
       if (NT_SUCCESS(Status))
       {
          IrpContext->Irp->IoStatus.Information = Length;
index 9d0606c..63a19ef 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vfat.h,v 1.62 2004/05/02 20:16:46 hbirr Exp $ */
+/* $Id: vfat.h,v 1.63 2004/05/15 23:00:02 hbirr Exp $ */
 
 #include <ddk/ntifs.h>
 
@@ -288,7 +288,8 @@ typedef struct __DOSDATE
 }
 DOSDATE, *PDOSDATE;
 
-#define IRPCONTEXT_CANWAIT  0x0001
+#define IRPCONTEXT_CANWAIT         0x0001
+#define IRPCONTEXT_PENDINGRETURNED  0x0002
 
 typedef struct
 {
@@ -301,6 +302,8 @@ typedef struct
    UCHAR MajorFunction;
    UCHAR MinorFunction;
    PFILE_OBJECT FileObject;
+   ULONG RefCount;
+   KEVENT Event;
 } VFAT_IRP_CONTEXT, *PVFAT_IRP_CONTEXT;
 
 typedef struct _VFAT_DIRENTRY_CONTEXT
@@ -332,10 +335,17 @@ NTSTATUS VfatReadDisk(IN PDEVICE_OBJECT pDeviceObject,
                       IN PUCHAR Buffer,
                       IN BOOLEAN Override);
 
-NTSTATUS VfatWriteDisk(IN PDEVICE_OBJECT pDeviceObject,
-                       IN PLARGE_INTEGER WriteOffset,
-                       IN ULONG WriteLength,
-                       IN PUCHAR Buffer);
+NTSTATUS VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
+                             IN PLARGE_INTEGER ReadOffset,
+                             IN ULONG ReadLength,
+                             IN ULONG BufferOffset,
+                             IN BOOLEAN Wait);
+
+NTSTATUS VfatWriteDiskPartial(IN PVFAT_IRP_CONTEXT IrpContext,
+                             IN PLARGE_INTEGER WriteOffset,
+                             IN ULONG WriteLength,
+                             IN ULONG BufferOffset,
+                             IN BOOLEAN Wait);
 
 NTSTATUS VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject,
                                   IN ULONG CtlCode,