From 4fd4a977601dc23e90aa9be9160fbfdd5346b2c4 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Wed, 10 Oct 2001 21:46:13 +0000 Subject: [PATCH] Implemented CcCopyRead(), CcCopyWrite() and some other functions. svn path=/trunk/; revision=2274 --- reactos/ntoskrnl/cc/copy.c | 312 +++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 reactos/ntoskrnl/cc/copy.c diff --git a/reactos/ntoskrnl/cc/copy.c b/reactos/ntoskrnl/cc/copy.c new file mode 100644 index 00000000000..37c435c34b4 --- /dev/null +++ b/reactos/ntoskrnl/cc/copy.c @@ -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 +#include +#include +#include +#include +#include +#include + +#define NDEBUG +#include + +/* 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; +} + +