Implemented CcCopyRead(), CcCopyWrite() and some other functions.
authorHartmut Birr <osexpert@googlemail.com>
Wed, 10 Oct 2001 21:46:13 +0000 (21:46 +0000)
committerHartmut Birr <osexpert@googlemail.com>
Wed, 10 Oct 2001 21:46:13 +0000 (21:46 +0000)
svn path=/trunk/; revision=2274

reactos/ntoskrnl/cc/copy.c [new file with mode: 0644]

diff --git a/reactos/ntoskrnl/cc/copy.c b/reactos/ntoskrnl/cc/copy.c
new file mode 100644 (file)
index 0000000..37c435c
--- /dev/null
@@ -0,0 +1,312 @@
+/* $Id: copy.c,v 1.1 2001/10/10 21:46:13 hbirr Exp $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/cc/copy.c
+ * PURPOSE:         Implements cache managers copy interface
+ * PROGRAMMER:      Hartmut Birr
+ * UPDATE HISTORY:
+ *                  Created 05.10.2001
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ddk/ntddk.h>
+#include <ddk/ntifs.h>
+#include <internal/mm.h>
+#include <internal/cc.h>
+#include <internal/pool.h>
+#include <internal/io.h>
+#include <ntos/minmax.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
+{
+  ULONG Size;
+  PMDL Mdl;
+  NTSTATUS Status;
+  LARGE_INTEGER SegOffset;
+  IO_STATUS_BLOCK IoStatus;
+
+  SegOffset.QuadPart = CacheSeg->FileOffset;
+  Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
+  if (Size > CacheSeg->Bcb->CacheSegmentSize)
+  {
+    Size = CacheSeg->Bcb->CacheSegmentSize;
+  }
+  Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
+  MmBuildMdlForNonPagedPool(Mdl);
+  Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
+  if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+  {
+    CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE);
+    DPRINT1("IoPageRead failed, Status %x\n", Status);
+       return Status;
+  }
+  if (CacheSeg->Bcb->CacheSegmentSize > Size)
+  {
+    memset (CacheSeg->BaseAddress + Size, 0, CacheSeg->Bcb->CacheSegmentSize - Size);
+  }
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
+{
+  ULONG Size;
+  PMDL Mdl;
+  NTSTATUS Status;
+  IO_STATUS_BLOCK IoStatus;
+  LARGE_INTEGER SegOffset;
+
+  SegOffset.QuadPart = CacheSeg->FileOffset;
+  Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
+  if (Size > CacheSeg->Bcb->CacheSegmentSize)
+  {
+    Size = CacheSeg->Bcb->CacheSegmentSize;
+  }
+  Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
+  MmBuildMdlForNonPagedPool(Mdl);
+  Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
+  if (!NT_SUCCESS(Status))
+  {
+    DPRINT1("IoPageWrite failed, Status %x\n", Status);
+  }
+  return Status;
+}
+
+BOOLEAN STDCALL
+CcCopyRead (
+   IN PFILE_OBJECT FileObject,
+   IN PLARGE_INTEGER FileOffset,
+   IN ULONG Length,
+   IN BOOLEAN Wait,
+   OUT PVOID Buffer,
+   OUT PIO_STATUS_BLOCK IoStatus)
+{
+   ULONG ReadOffset;
+   ULONG TempLength;
+   NTSTATUS Status = STATUS_SUCCESS;
+   PVOID BaseAddress;
+   PCACHE_SEGMENT CacheSeg;
+   BOOLEAN Valid;
+   ULONG ReadLength = 0;
+   PBCB Bcb;
+   KIRQL oldirql;
+   PLIST_ENTRY current_entry;
+   PCACHE_SEGMENT current;
+
+   DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
+             "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
+          FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
+          Buffer, IoStatus);
+
+   Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
+   ReadOffset = FileOffset->QuadPart;
+
+   DPRINT("AllocationSize %d, FileSize %d\n",
+         (ULONG)Bcb->AllocationSize.QuadPart,
+         (ULONG)Bcb->FileSize.QuadPart);
+
+   if (!Wait)
+   {
+     KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+     current_entry = Bcb->CacheSegmentListHead.Flink;
+     while (current_entry != &Bcb->CacheSegmentListHead)
+     {
+       current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
+       if (!current->Valid && current->FileOffset < ReadOffset + Length
+         && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
+       {
+         KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+         IoStatus->Status = STATUS_UNSUCCESSFUL;
+         IoStatus->Information = 0;
+         return FALSE;
+       }
+       current_entry = current_entry->Flink;
+     }
+     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+   }
+
+   TempLength = ReadOffset % Bcb->CacheSegmentSize;
+   if (TempLength != 0)
+   {
+     TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
+     Status = CcRosRequestCacheSegment(Bcb,
+                ROUND_DOWN(ReadOffset, Bcb->CacheSegmentSize),
+                &BaseAddress, &Valid, &CacheSeg);
+     if (!NT_SUCCESS(Status))
+     {
+       IoStatus->Information = 0;
+       IoStatus->Status = Status;
+       DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
+       return FALSE;
+     }
+     if (!Valid)
+     {
+       Status = ReadCacheSegment(CacheSeg);
+       if (!NT_SUCCESS(Status))
+       {
+         IoStatus->Information = 0;
+         IoStatus->Status = Status;
+         return FALSE;
+       }
+     }
+     memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize, TempLength);
+     CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
+     ReadLength += TempLength;
+     Length -= TempLength;
+     ReadOffset += TempLength;
+     Buffer += TempLength;
+   }
+
+   while (Length > 0)
+   {
+     TempLength = min (Bcb->CacheSegmentSize, Length);
+     Status = CcRosRequestCacheSegment(Bcb, ReadOffset,
+                &BaseAddress, &Valid, &CacheSeg);
+     if (!NT_SUCCESS(Status))
+     {
+       IoStatus->Information = 0;
+       IoStatus->Status = Status;
+       DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
+       return FALSE;
+     }
+     if (!Valid)
+     {
+       Status = ReadCacheSegment(CacheSeg);
+       if (!NT_SUCCESS(Status))
+       {
+         IoStatus->Information = 0;
+         IoStatus->Status = Status;
+         return FALSE;
+       }
+     }
+     memcpy (Buffer, BaseAddress, TempLength);
+     CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
+     ReadLength += TempLength;
+     Length -= TempLength;
+     ReadOffset += TempLength;
+     Buffer += TempLength;
+   }
+   IoStatus->Status = STATUS_SUCCESS;
+   IoStatus->Information = ReadLength;
+   DPRINT("CcCopyRead O.K.\n");
+   return TRUE;
+}
+
+BOOLEAN STDCALL
+CcCopyWrite (
+   IN PFILE_OBJECT FileObject,
+   IN PLARGE_INTEGER FileOffset,
+   IN ULONG Length,
+   IN BOOLEAN Wait,
+   IN PVOID Buffer)
+{
+   NTSTATUS Status;
+   ULONG WriteOffset;
+   KIRQL oldirql;
+   PBCB Bcb;
+   PLIST_ENTRY current_entry;
+   PCACHE_SEGMENT CacheSeg;
+   ULONG TempLength;
+   PVOID BaseAddress;
+   BOOLEAN Valid;
+
+   DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
+             "Length %d, Wait %d, Buffer %x)\n",
+          FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
+
+   Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
+   WriteOffset = (ULONG)FileOffset->QuadPart;
+
+   if (!Wait)
+   {
+     // testing, if the requested datas are available
+     KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+     current_entry = Bcb->CacheSegmentListHead.Flink;
+     while (current_entry != &Bcb->CacheSegmentListHead)
+     {
+       CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
+       if (!CacheSeg->Valid)
+       {
+         if ((WriteOffset >= CacheSeg->FileOffset && WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
+           || (WriteOffset + Length > CacheSeg->FileOffset && WriteOffset + Length <= CacheSeg->FileOffset + Bcb->CacheSegmentSize))
+         {
+           KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+           // datas not available
+           return FALSE;
+         }
+       }
+       current_entry = current_entry->Flink;
+     }
+     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+   }
+
+   TempLength = WriteOffset % Bcb->CacheSegmentSize;
+   if (TempLength != 0)
+   {
+      TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
+      Status = CcRosRequestCacheSegment(Bcb,
+                 ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize),
+                 &BaseAddress, &Valid, &CacheSeg);
+      if (!NT_SUCCESS(Status))
+      {
+        return FALSE;
+      }
+      if (!Valid)
+      {
+         if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
+         {
+           return FALSE;
+         }
+      }
+      memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize, Buffer, TempLength);
+      if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
+      {
+        return FALSE;
+      }
+      CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
+
+      Length -= TempLength;
+      WriteOffset += TempLength;
+      Buffer += TempLength;
+   }
+
+   while (Length > 0)
+   {
+      TempLength = min (Bcb->CacheSegmentSize, Length);
+      Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
+                 &BaseAddress, &Valid, &CacheSeg);
+      if (!NT_SUCCESS(Status))
+      {
+         return FALSE;
+      }
+      if (!Valid && TempLength < Bcb->CacheSegmentSize)
+      {
+        if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
+        {
+          return FALSE;
+        }
+      }
+      memcpy (BaseAddress, Buffer, TempLength);
+      if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
+      {
+        return FALSE;
+      }
+      CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
+      Length -= TempLength;
+      WriteOffset += TempLength;
+      Buffer += TempLength;
+   }
+   return TRUE;
+}
+
+