2003-02-18 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / cc / copy.c
index 5cfa30c..8a21939 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: copy.c,v 1.3 2001/12/29 14:32:21 dwelch Exp $
+/* $Id: copy.c,v 1.15 2003/02/18 22:06:53 chorns Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
 
 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
 
+static PHYSICAL_ADDRESS CcZeroPage = (PHYSICAL_ADDRESS)0LL;
+
 /* FUNCTIONS *****************************************************************/
 
-NTSTATUS ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
+VOID 
+CcInitCacheZeroPage(VOID)
+{
+   NTSTATUS Status;
+
+   Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &CcZeroPage);
+   if (!NT_SUCCESS(Status))
+   {
+       DbgPrint("Can't allocate CcZeroPage.\n");
+       KeBugCheck(0);
+   }
+   Status = MiZeroPage(CcZeroPage);
+   if (!NT_SUCCESS(Status))
+   {
+       DbgPrint("Can't zero out CcZeroPage.\n");
+       KeBugCheck(0);
+   }
+}
+
+NTSTATUS
+ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
+                     PVOID Buffer)
+{
+  PCACHE_SEGMENT head;
+  PCACHE_SEGMENT current;
+  PCACHE_SEGMENT previous;
+  IO_STATUS_BLOCK Iosb;
+  LARGE_INTEGER SegOffset;
+  NTSTATUS Status;
+  ULONG TempLength;
+  KEVENT Event;
+
+  Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+  current = head;
+  while (current != NULL)
+    {
+      /*
+       * If the current segment is valid then copy it into the
+       * user buffer.
+       */
+      if (current->Valid)
+       {
+         TempLength = min(Bcb->CacheSegmentSize, Length);
+         memcpy(Buffer, current->BaseAddress, TempLength);
+         Buffer += TempLength;
+         Length = Length - TempLength; 
+         previous = current;
+         current = current->NextInChain;
+         CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+       }
+      /*
+       * Otherwise read in as much as we can.
+       */
+      else
+       {
+         PCACHE_SEGMENT current2;
+         ULONG current_size;
+         PMDL Mdl;
+         ULONG i;
+         ULONG offset;
+
+         /*
+          * Count the maximum number of bytes we could read starting
+          * from the current segment.
+          */
+         current2 = current;
+         current_size = 0;
+         while (current2 != NULL && !current2->Valid)
+           {
+             current2 = current2->NextInChain;
+             current_size += Bcb->CacheSegmentSize;
+           }
+         
+         /*
+          * Create an MDL which contains all their pages.
+          */
+         Mdl = MmCreateMdl(NULL, NULL, current_size);
+         Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+         current2 = current;
+         offset = 0;
+         while (current2 != NULL && !current2->Valid)
+           {
+             for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
+               {
+                 PVOID address;
+                 PHYSICAL_ADDRESS page;
+                 address = current2->BaseAddress + (i * PAGE_SIZE);
+                 page = MmGetPhysicalAddressForProcess(NULL, address);
+                 ((PULONG)(Mdl + 1))[offset] = page.u.LowPart;
+                 offset++;
+               }
+             current2 = current2->NextInChain;
+           }
+
+         /*
+          * Read in the information.
+          */
+         SegOffset.QuadPart = current->FileOffset;
+         KeInitializeEvent(&Event, NotificationEvent, FALSE);
+         Status = IoPageRead(Bcb->FileObject,
+                             Mdl,
+                             &SegOffset,
+                             &Event,
+                             &Iosb);
+         if (Status == STATUS_PENDING)
+         {
+            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+            Status = Iosb.Status;
+         }
+         if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+           {
+             while (current != NULL)
+               {
+                 previous = current;
+                 current = current->NextInChain;
+                 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
+               }
+             return(Status);
+           }
+         while (current != NULL && !current->Valid)
+           {
+             previous = current;
+             current = current->NextInChain;
+             TempLength = min(Bcb->CacheSegmentSize, Length);
+             memcpy(Buffer, previous->BaseAddress, TempLength);
+             Buffer += TempLength;
+             Length = Length - TempLength; 
+             CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+           }
+       }
+    }
+  return(STATUS_SUCCESS);
+}
+
+NTSTATUS 
+ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
 {
   ULONG Size;
   PMDL Mdl;
   NTSTATUS Status;
   LARGE_INTEGER SegOffset;
   IO_STATUS_BLOCK IoStatus;
+  KEVENT Event;
 
   SegOffset.QuadPart = CacheSeg->FileOffset;
   Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
   if (Size > CacheSeg->Bcb->CacheSegmentSize)
-  {
-    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)
+  KeInitializeEvent(&Event, NotificationEvent, FALSE);
+  Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus); 
+  if (Status == STATUS_PENDING)
   {
-    CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE, FALSE, FALSE);
-    DPRINT1("IoPageRead failed, Status %x\n", Status);
-       return Status;
+     KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+     Status = IoStatus.Status;
   }
+
+  if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+    {
+      CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE, FALSE, FALSE);
+      DPRINT1("IoPageRead failed, Status %x\n", Status);
+      return Status;
+    }
   if (CacheSeg->Bcb->CacheSegmentSize > Size)
-  {
-    memset (CacheSeg->BaseAddress + Size, 0, CacheSeg->Bcb->CacheSegmentSize - Size);
-  }
+    {
+      memset (CacheSeg->BaseAddress + Size, 0, 
+             CacheSeg->Bcb->CacheSegmentSize - Size);
+    }
   return STATUS_SUCCESS;
 }
 
-NTSTATUS WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
+NTSTATUS 
+WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
 {
   ULONG Size;
   PMDL Mdl;
   NTSTATUS Status;
   IO_STATUS_BLOCK IoStatus;
   LARGE_INTEGER SegOffset;
+  KEVENT Event;
 
+  CacheSeg->Dirty = FALSE;
   SegOffset.QuadPart = CacheSeg->FileOffset;
   Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
   if (Size > CacheSeg->Bcb->CacheSegmentSize)
-  {
-    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))
+  KeInitializeEvent(&Event, NotificationEvent, FALSE);
+  Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
+  if (Status == STATUS_PENDING)
   {
-    DPRINT1("IoPageWrite failed, Status %x\n", Status);
+     KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+     Status = IoStatus.Status;
   }
-  return Status;
+  if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
+    {
+      DPRINT1("IoPageWrite failed, Status %x\n", Status);
+      CacheSeg->Dirty = TRUE;
+      return(Status);
+    }
+  return(STATUS_SUCCESS);
 }
 
 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)
+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;
+  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);
 
-   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",
+  Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
+  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->BcbSegmentListHead.Flink;
-     while (current_entry != &Bcb->BcbSegmentListHead)
-     {
-       current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-       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);
-   }
+  /*
+   * Check for the nowait case that all the cache segments that would
+   * cover this read are in memory.
+   */
+  if (!Wait)
+    {
+      KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+      current_entry = Bcb->BcbSegmentListHead.Flink;
+      while (current_entry != &Bcb->BcbSegmentListHead)
+       {
+         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
+                                     BcbSegmentListEntry);
+         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, FALSE, FALSE);
-     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, FALSE, FALSE);
-     ReadLength += TempLength;
-     Length -= TempLength;
-     ReadOffset += TempLength;
-     Buffer += TempLength;
-   }
-   IoStatus->Status = STATUS_SUCCESS;
-   IoStatus->Information = ReadLength;
-   DPRINT("CcCopyRead O.K.\n");
-   return TRUE;
+  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, FALSE, FALSE);
+      ReadLength += TempLength;
+      Length -= TempLength;
+      ReadOffset += TempLength;
+      Buffer += TempLength;
+    }  
+  while (Length > 0)
+    {
+      TempLength = min(max(Bcb->CacheSegmentSize, 65536), Length);
+      ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
+      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)
+CcCopyWrite (IN PFILE_OBJECT FileObject,
+            IN PLARGE_INTEGER FileOffset,
+            IN ULONG Length,
+            IN BOOLEAN Wait,
+            IN PVOID Buffer)
 {
    NTSTATUS Status;
    ULONG WriteOffset;
@@ -221,92 +366,303 @@ CcCopyWrite (
    BOOLEAN Valid;
 
    DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
-             "Length %d, Wait %d, Buffer %x)\n",
+         "Length %d, Wait %d, Buffer %x)\n",
           FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
 
-   Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
+   Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
    WriteOffset = (ULONG)FileOffset->QuadPart;
 
    if (!Wait)
-   {
-     // testing, if the requested datas are available
-     KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-     current_entry = Bcb->BcbSegmentListHead.Flink;
-     while (current_entry != &Bcb->BcbSegmentListHead)
      {
-       CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-       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;
+       /* testing, if the requested datas are available */
+       KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+       current_entry = Bcb->BcbSegmentListHead.Flink;
+       while (current_entry != &Bcb->BcbSegmentListHead)
+        {
+          CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
+                                       BcbSegmentListEntry);
+          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);
      }
-     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, FALSE, FALSE);
-
-      Length -= TempLength;
-      WriteOffset += TempLength;
-      Buffer += TempLength;
-   }
-
+     {
+       ULONG ROffset;
+       ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
+       TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
+       Status = CcRosRequestCacheSegment(Bcb, ROffset,
+                                        &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);
+       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+       
+       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, FALSE, FALSE);
-      Length -= TempLength;
-      WriteOffset += TempLength;
-      Buffer += TempLength;
-   }
-   return TRUE;
+     {
+       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);
+       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+       Length -= TempLength;
+       WriteOffset += TempLength;
+       Buffer += TempLength;
+     }
+   return(TRUE);
 }
 
+BOOLEAN STDCALL
+CcZeroData (IN PFILE_OBJECT     FileObject,
+           IN PLARGE_INTEGER   StartOffset,
+           IN PLARGE_INTEGER   EndOffset,
+           IN BOOLEAN          Wait)
+{
+  NTSTATUS Status;
+  LARGE_INTEGER WriteOffset;
+  ULONG Length;
+  PMDL Mdl;
+  ULONG i;
+  IO_STATUS_BLOCK Iosb;
+  KEVENT Event;
+  
+  DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
+        "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart, 
+        Wait);
+  
+  Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
+
+  if (FileObject->SectionObjectPointers->SharedCacheMap == NULL)
+    {
+      /* File is not cached */
+      WriteOffset.QuadPart = StartOffset->QuadPart;
+      
+      while (Length > 0)
+       {
+         if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
+           {
+             Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
+                               262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+             WriteOffset.QuadPart += 
+               (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+             Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+           }
+         else
+           {
+             Mdl = 
+               MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
+                           Length - WriteOffset.u.LowPart % PAGE_SIZE);
+             WriteOffset.QuadPart += 
+               (Length - WriteOffset.u.LowPart % PAGE_SIZE);
+             Length = 0;
+           }
+         if (Mdl == NULL)
+           {
+             return(FALSE);
+           }
+         Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+         for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
+           {
+             ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
+           }
+          KeInitializeEvent(&Event, NotificationEvent, FALSE);
+         Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
+          if (Status == STATUS_PENDING)
+         {
+             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+             Status = Iosb.Status;
+         }
+         if (!NT_SUCCESS(Status))
+           {
+             return(FALSE);
+           }
+       }
+    }
+  else
+    {
+      /* File is cached */
+      KIRQL oldirql;
+      PBCB Bcb;
+      PLIST_ENTRY current_entry;
+      PCACHE_SEGMENT CacheSeg, current, previous;
+      ULONG TempLength;
+      ULONG Start;
+      ULONG count;
+      ULONG size;
+      PHYSICAL_ADDRESS page;
+
+      Start = StartOffset->u.LowPart;
+      Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
+      if (Wait)
+       {
+          /* testing, if the requested datas are available */
+         KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+         current_entry = Bcb->BcbSegmentListHead.Flink;
+         while (current_entry != &Bcb->BcbSegmentListHead)
+           {
+             CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
+                                          BcbSegmentListEntry);
+             if (!CacheSeg->Valid)
+               {
+                 if ((Start >= CacheSeg->FileOffset && 
+                      Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
+                     || (Start + Length > CacheSeg->FileOffset && 
+                         Start + Length <= 
+                         CacheSeg->FileOffset + Bcb->CacheSegmentSize))
+                   {
+                     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+                     /* datas not available */
+                     return(FALSE);
+                   }
+               }
+             current_entry = current_entry->Flink;
+           }
+         KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+       }
+      
+      while (Length > 0)
+       {
+         ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
+         WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
+         if (Start % Bcb->CacheSegmentSize + Length > 262144)
+           {
+             Mdl = MmCreateMdl(NULL, NULL, 262144);
+             if (Mdl == NULL)
+               {
+                 return FALSE;
+               }
+             Status = CcRosGetCacheSegmentChain (Bcb, RStart,
+                                                 262144, &CacheSeg);
+             if (!NT_SUCCESS(Status))
+               {
+                 ExFreePool(Mdl);
+                 return(FALSE);
+               }
+           }
+         else
+           {
+             ULONG RLength;
+             RLength = Start % Bcb->CacheSegmentSize + Length;
+             RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
+             Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
+             if (Mdl == NULL)
+               {
+                 return(FALSE);
+               }
+             Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
+                                                 &CacheSeg);
+             if (!NT_SUCCESS(Status))
+               {
+                 ExFreePool(Mdl);
+                 return(FALSE);
+               }
+           }
+         Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
+         current = CacheSeg;
+         count = 0;
+         while (current != NULL)
+           {
+             if ((Start % Bcb->CacheSegmentSize) != 0 || 
+                 Start % Bcb->CacheSegmentSize + Length < 
+                 Bcb->CacheSegmentSize)
+               {
+                 if (!current->Valid)
+                   {
+                     /* Segment lesen */
+                     Status = ReadCacheSegment(current);
+                     if (!NT_SUCCESS(Status))
+                       {
+                         DPRINT1("ReadCacheSegment failed, status %x\n", 
+                                 Status);
+                       }
+                   }
+                 TempLength = min (Length, Bcb->CacheSegmentSize - 
+                                   Start % Bcb->CacheSegmentSize);
+                 memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
+                         0, TempLength);
+               }
+             else
+               {
+                 TempLength = Bcb->CacheSegmentSize;
+                 memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
+               }
+             Start += TempLength;
+             Length -= TempLength;
+             
+             size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
+             for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) && 
+                    count < size; i++)
+               {
+                 PVOID Address;
+                 Address = current->BaseAddress + (i * PAGE_SIZE);
+                 page = 
+                   MmGetPhysicalAddressForProcess(NULL, Address);
+                 ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
+               }
+             current = current->NextInChain;
+           }
+         
+         /* Write the Segment */
+          KeInitializeEvent(&Event, NotificationEvent, FALSE);
+         Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
+          if (Status == STATUS_PENDING)
+         {
+             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+             Status = Iosb.Status;
+         }
+         if (!NT_SUCCESS(Status))
+           {
+             DPRINT1("IoPageWrite failed, status %x\n", Status);
+           }
+         current = CacheSeg;
+         while (current != NULL)
+           {
+             previous = current;
+             current = current->NextInChain;
+             CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+           }
+       }
+    }
+  return(TRUE);
+}