Implemented CcCopyRead(), CcCopyWrite() and some other functions.

svn path=/trunk/; revision=2274
This commit is contained in:
Hartmut Birr 2001-10-10 21:46:13 +00:00
parent a1d321e7b8
commit 4fd4a97760

312
reactos/ntoskrnl/cc/copy.c Normal file
View file

@ -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;
}