From 667636f08a4b88758e4dc7fb77258cc68cd7e564 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Sun, 18 Jan 2009 10:23:15 +0000 Subject: [PATCH] - SVN maintenance. svn path=/trunk/; revision=38881 --- reactos/ntoskrnl/fsrtl/fastio.c | 2852 +++++++++++++++---------------- 1 file changed, 1426 insertions(+), 1426 deletions(-) diff --git a/reactos/ntoskrnl/fsrtl/fastio.c b/reactos/ntoskrnl/fsrtl/fastio.c index 76f5ff8c763..c5ee9139ac7 100644 --- a/reactos/ntoskrnl/fsrtl/fastio.c +++ b/reactos/ntoskrnl/fsrtl/fastio.c @@ -1,1426 +1,1426 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/fsrtl/fastio.c - * PURPOSE: Provides Fast I/O entrypoints to the Cache Manager - * PROGRAMMERS: buzdelabuz2@gmail.com,alex.ionescu@reactos.org - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -/* PUBLIC FUNCTIONS **********************************************************/ - -/* - * @implemented - */ -VOID -NTAPI -FsRtlIncrementCcFastReadResourceMiss(VOID) -{ - CcFastReadResourceMiss++; -} - -/* - * @implemented - */ -VOID -NTAPI -FsRtlIncrementCcFastReadNotPossible(VOID) -{ - CcFastReadNotPossible++; -} - -/* - * @implemented - */ -VOID -NTAPI -FsRtlIncrementCcFastReadWait(VOID) -{ - CcFastReadWait++; -} - -/* - * @implemented - */ -VOID -NTAPI -FsRtlIncrementCcFastReadNoWait(VOID) -{ - CcFastReadNoWait++; -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlCopyRead(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, - OUT PVOID Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - - PFSRTL_COMMON_FCB_HEADER FcbHeader; - LARGE_INTEGER Offset; - PFAST_IO_DISPATCH FastIoDispatch; - PDEVICE_OBJECT Device; - BOOLEAN Result = TRUE; - ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset,Length); - - PAGED_CODE(); - ASSERT(FileObject); - ASSERT(FileObject->FsContext); - - /* No actual read */ - if (!Length) - { - /* Return success */ - IoStatus->Status = STATUS_SUCCESS; - IoStatus->Information = 0; - return TRUE; - } - - if (MAXLONGLONG < (LONGLONG) FileOffset->QuadPart + Length) { - IoStatus->Status = STATUS_INVALID_PARAMETER; - IoStatus->Information = 0; - return FALSE; - } - - /* Get the offset and FCB header */ - Offset.QuadPart = FileOffset->QuadPart + Length; - FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; - - - if (Wait) { - /* Use a Resource Acquire */ - FsRtlEnterFileSystem(); - CcFastReadWait++; - ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); - } else { - /* Acquire the resource without blocking */ - /* Return false and the I/O manager will retry using the standard IRP method. */ - /* Use a Resource Acquire */ - FsRtlEnterFileSystem(); - if (!ExAcquireResourceSharedLite(FcbHeader->Resource, FALSE)) { - FsRtlExitFileSystem(); - FsRtlIncrementCcFastReadResourceMiss(); - return FALSE; - } - } - - - /* Check if this is a fast I/O cached file */ - if (!(FileObject->PrivateCacheMap) || - (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) { - /* It's not, so fail */ - Result = FALSE; - goto Cleanup; - } - - /* Check if we need to find out if fast I/O is available */ - if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) - { - /* Sanity check */ - ASSERT(!KeIsExecutingDpc()); - - /* Get the Fast I/O table */ - Device = IoGetRelatedDeviceObject(FileObject); - FastIoDispatch = Device->DriverObject->FastIoDispatch; - - /* Sanity check */ - ASSERT(FastIoDispatch != NULL); - ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); - - /* Ask the driver if we can do it */ - if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, - FileOffset, - Length, - TRUE, - LockKey, - TRUE, - IoStatus, - Device)) - { - /* It's not, fail */ - Result = FALSE; - goto Cleanup; - } - } - - /* Check if we read too much */ - if (Offset.QuadPart > FcbHeader->FileSize.QuadPart){ - /* We did, check if the file offset is past the end */ - if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart){ - /* Set end of file */ - IoStatus->Status = STATUS_END_OF_FILE; - IoStatus->Information = 0; - goto Cleanup; - } - - /* Otherwise, just normalize the length */ - Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); - } - - /* Set this as top-level IRP */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - - _SEH2_TRY - { - /* Make sure the IO and file size is below 4GB */ - if (Wait && !(Offset.HighPart | FcbHeader->FileSize.HighPart )) { - - /* Call the cache controller */ - CcFastCopyRead (FileObject,FileOffset->LowPart,Length,PageCount,Buffer,IoStatus); - /* File was accessed */ - FileObject->Flags |= FO_FILE_FAST_IO_READ; - if (IoStatus->Status != STATUS_END_OF_FILE) { - ASSERT(( FcbHeader->FileSize.QuadPart) >= (FileOffset->QuadPart + IoStatus->Information)); - } - - } else { - - /* Call the cache controller */ - Result = CcCopyRead(FileObject, FileOffset, Length, Wait,Buffer, IoStatus); - /* File was accessed */ - FileObject->Flags |= FO_FILE_FAST_IO_READ; - if (Result == TRUE) { - ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) || - ((LONGLONG)(FileOffset->QuadPart + IoStatus->Information) <= FcbHeader->FileSize.QuadPart) - ); - } - } - - /* Update the current file offset */ - if (Result == TRUE) { - FileObject->CurrentByteOffset.QuadPart += IoStatus->Information; - } - } - _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - Result = FALSE; - } _SEH2_END; - - PsGetCurrentThread()->TopLevelIrp = 0; - - /* Return to caller */ -Cleanup: - - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - - if (Result == FALSE) { - CcFastReadNotPossible += 1; - } - - return Result; - -} - - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlCopyWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, - OUT PVOID Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - - BOOLEAN Result = TRUE; - PFAST_IO_DISPATCH FastIoDispatch; - PDEVICE_OBJECT Device; - PFSRTL_COMMON_FCB_HEADER FcbHeader; - - /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */ - BOOLEAN FileOffsetAppend = ((FileOffset->HighPart == (LONG)0xffffffff) && (FileOffset->LowPart == 0xffffffff)); - BOOLEAN ResourceAquiredShared = FALSE; - - BOOLEAN b_4GB = FALSE; - - BOOLEAN FileSizeModified = FALSE; - LARGE_INTEGER OldFileSize; - LARGE_INTEGER OldValidDataLength; - - LARGE_INTEGER NewSize; - LARGE_INTEGER Offset; - - PAGED_CODE(); - - ASSERT(FileObject); - ASSERT(FileObject->FsContext); - - /* Initialize some of the vars and pointers */ - NewSize.QuadPart = 0; - Offset.QuadPart = FileOffset->QuadPart + Length; - FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; - - /* Nagar p.544 -- Check with Cc if we can write and check if the IO > 64kB (WDK macro) */ - if ( (CcCanIWrite(FileObject, Length,Wait, FALSE) == FALSE) || - (CcCopyWriteWontFlush(FileObject,FileOffset,Length) == FALSE) || - ((FileObject->Flags & FO_WRITE_THROUGH )== TRUE) - ) - { - return FALSE; - } - - /* No actual read */ - if (!Length) - { - IoStatus->Status = STATUS_SUCCESS; - IoStatus->Information = Length; - return TRUE; - } - - FsRtlEnterFileSystem(); - - /* Nagar p.544/545 -- The CcFastCopyWrite doesn't deal with filesize beyond 4GB*/ - if (Wait && (FcbHeader->AllocationSize.HighPart == 0)) - { - /* If the file offset is not past the file size, then we can acquire the lock shared */ - if ((FileOffsetAppend == FALSE) && (Offset.LowPart <= FcbHeader->ValidDataLength.LowPart)){ - ExAcquireResourceSharedLite(FcbHeader->Resource,TRUE); - ResourceAquiredShared = TRUE; - } else { - ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); - } - - /* Nagar p.544/545 -- If we append, use the file size as offset. Also, check that we aren't crossing the 4GB boundary */ - if ((FileOffsetAppend == TRUE)) { - Offset.LowPart = FcbHeader->FileSize.LowPart; - NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; - b_4GB = (NewSize.LowPart < FcbHeader->FileSize.LowPart); - - } else { - Offset.LowPart = FileOffset->LowPart; - NewSize.LowPart = FileOffset->LowPart + Length; - b_4GB = ((NewSize.LowPart < FileOffset->LowPart) || (FileOffset->HighPart != 0)); - } - - /* Nagar p.544/545 - Make sure that caching is initated. - That fast are allowed for this file stream. - That we are not extending past the allocated size - That we are not creating a hole bigger than 8k - That we are not crossing the 4GB boundary - */ - if ( (FileObject->PrivateCacheMap != NULL) && - (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && - (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && - (Offset.LowPart < (FcbHeader->ValidDataLength.LowPart + 0x2000) ) && - !b_4GB - ) - { - /* If we are extending past the file size, we need to release the lock and acquire it - exclusively, because we are going to need to update the FcbHeader */ - if (ResourceAquiredShared && (NewSize.LowPart > (FcbHeader->ValidDataLength.LowPart + 0x2000))) { - /* Then we need to acquire the resource exclusive */ - ExReleaseResourceLite(FcbHeader->Resource); - ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); - if (FileOffsetAppend == TRUE) { - Offset.LowPart = FcbHeader->FileSize.LowPart; // ?? - NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; - /* Make sure we don't cross the 4GB boundary */ - b_4GB = (NewSize.LowPart < Offset.LowPart); - } - - /* Recheck some of the conditions since we let the lock go */ - if ( (FileObject->PrivateCacheMap != NULL) && - (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && - (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && - (FcbHeader->AllocationSize.HighPart == 0) && - !b_4GB - ) - { - } else - { - goto FailAndCleanup; - } - } - - }else - { - goto FailAndCleanup; - } - - /* Check if we need to find out if fast I/O is available */ - if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) - { - IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; - - /* Sanity check */ - ASSERT(!KeIsExecutingDpc()); - - /* Get the Fast I/O table */ - Device = IoGetRelatedDeviceObject(FileObject); - FastIoDispatch = Device->DriverObject->FastIoDispatch; - - /* Sanity check */ - ASSERT(FastIoDispatch != NULL); - ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); - - /* Ask the driver if we can do it */ - if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, - FileOffsetAppend? &FcbHeader->FileSize:FileOffset, - Length, - TRUE, - LockKey, - FALSE, - &FastIoCheckIfPossibleStatus, - Device)) - { - /* It's not, fail */ - goto FailAndCleanup; - } - } - - /* If we are going to extend the file then save the old file size - in case the operation fails - */ - if (NewSize.LowPart > FcbHeader->FileSize.LowPart) { - FileSizeModified = TRUE; - OldFileSize.LowPart = FcbHeader->FileSize.LowPart; - OldValidDataLength.LowPart = FcbHeader->ValidDataLength.LowPart; - FcbHeader->FileSize.LowPart = NewSize.LowPart; - } - - /* Set this as top-level IRP */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - - _SEH2_TRY - { - if (Offset.LowPart > FcbHeader->ValidDataLength.LowPart) { - LARGE_INTEGER OffsetVar; - OffsetVar.LowPart = Offset.LowPart; - OffsetVar.HighPart = 0; - CcZeroData(FileObject,&FcbHeader->ValidDataLength,&OffsetVar,TRUE); - } - - /* Call the cache manager */ - CcFastCopyWrite(FileObject,Offset.LowPart,Length,Buffer); - } - _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - Result = FALSE; - } _SEH2_END; - - /* Remove ourselves at the top level component after the IO is done */ - PsGetCurrentThread()->TopLevelIrp = 0; - - /* Did the operation succeed ? */ - if (Result == TRUE) { - /* Update the valid file size if necessary */ - if (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart){ - FcbHeader->ValidDataLength.LowPart = NewSize.LowPart ; - } - - /* Flag the file as modified */ - FileObject->Flags |= FO_FILE_MODIFIED; - - /* Update the strucutres if the file size changed */ - if (FileSizeModified) { - ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.LowPart = NewSize.LowPart; - FileObject->Flags |= FO_FILE_SIZE_CHANGED; - } - - /* Update the file object current file offset */ - FileObject->CurrentByteOffset.QuadPart = NewSize.LowPart; - - } else { - - /* Result == FALSE if we get here. */ - if (FileSizeModified) { - /* If the file size was modified then restore the old file size */ - if(FcbHeader->PagingIoResource != NULL) { - // Nagar P.544 Restore the old file size if operation didn't succeed. - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource,TRUE); - FcbHeader->FileSize.LowPart = OldFileSize.LowPart; - FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - } else { - /* If there is no lock and do it without */ - FcbHeader->FileSize.LowPart = OldFileSize.LowPart; - FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; - } - } else { - } - } - - goto Cleanup; - - } else { - - LARGE_INTEGER OldFileSize; - - /* Sanity check */ - ASSERT(!KeIsExecutingDpc()); - - // Nagar P.544 - /* Check if we need to acquire the resource exclusive */ - if ( (FileOffsetAppend == FALSE) && - ( (FileOffset->QuadPart + Length) <= FcbHeader->ValidDataLength.QuadPart ) - ) - { - /* Acquire the resource shared */ - if (!ExAcquireResourceSharedLite(FcbHeader->Resource,Wait)) { - goto LeaveCriticalAndFail; - } - ResourceAquiredShared =TRUE; - } else { - /* Acquire the resource exclusive */ - if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource,Wait)) { - goto LeaveCriticalAndFail; - } - } - - /* Check if we are appending */ - if (FileOffsetAppend == TRUE) { - Offset.QuadPart = FcbHeader->FileSize.QuadPart; - NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; - } else { - Offset.QuadPart = FileOffset->QuadPart; - NewSize.QuadPart += FileOffset->QuadPart + Length; - } - - /* Nagar p.544/545 - Make sure that caching is initated. - That fast are allowed for this file stream. - That we are not extending past the allocated size - That we are not creating a hole bigger than 8k - */ - if ( (FileObject->PrivateCacheMap != NULL) && - (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && - ((FcbHeader->ValidDataLength.QuadPart + 0x2000) > Offset.QuadPart) && - (MAXLONGLONG > (Offset.QuadPart + Length)) && - (FcbHeader->AllocationSize.QuadPart >= NewSize.QuadPart) - ) - { - /* Check if we can keep the lock shared */ - if (ResourceAquiredShared && (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) ) { - ExReleaseResourceLite(FcbHeader->Resource); - if(!ExAcquireResourceExclusiveLite(FcbHeader->Resource,Wait)) - { - goto LeaveCriticalAndFail; - } - - /* Compute the offset and the new filesize */ - if (FileOffsetAppend) { - Offset.QuadPart = FcbHeader->FileSize.QuadPart; - NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; - } - - /* Recheck the above points since we released and reacquire the lock */ - if ( (FileObject->PrivateCacheMap != NULL) && - (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && - (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart) - ) - { - /* Do nothing */ - } else { - goto FailAndCleanup; - } - } - - /* Check if we need to find out if fast I/O is available */ - if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) - { - IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; - - /* Sanity check */ - ASSERT(!KeIsExecutingDpc()); - - /* Get the Fast I/O table */ - Device = IoGetRelatedDeviceObject(FileObject); - FastIoDispatch = Device->DriverObject->FastIoDispatch; - - /* Sanity check */ - ASSERT(FastIoDispatch != NULL); - ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); - - /* Ask the driver if we can do it */ - if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, - FileOffsetAppend? &FcbHeader->FileSize:FileOffset, - Length, - TRUE, - LockKey, - FALSE, - &FastIoCheckIfPossibleStatus, - Device)) - { - /* It's not, fail */ - goto FailAndCleanup; - } - } - - - /* If we are going to modify the filesize, save the old fs in case the operation fails */ - if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) { - FileSizeModified = TRUE; - OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; - OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; - - /* If the high part of the filesize is going to change, grab the Paging IoResouce */ - if (NewSize.HighPart != FcbHeader->FileSize.HighPart && FcbHeader->PagingIoResource) { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->FileSize.QuadPart = NewSize.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - } else { - FcbHeader->FileSize.QuadPart = NewSize.QuadPart; - } - } - - /* Nagar p.544 */ - /* Set ourselves as top component */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - _SEH2_TRY - { - BOOLEAN CallCc = TRUE; - /* Check if there is a gap between the end of the file and the offset - If yes, then we have to zero the data - */ - if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) { - if (!(Result = CcZeroData(FileObject,&FcbHeader->ValidDataLength,&Offset,Wait))) { - /* If this operation fails, then we have to exit - We can jump outside the SEH, so I a using a variable to exit - normally - */ - CallCc = FALSE; - } - } - - /* Unless the CcZeroData failed, call the cache manager */ - if (CallCc) { - Result = CcCopyWrite(FileObject,&Offset,Length, Wait, Buffer); - } - }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - Result = FALSE; - } _SEH2_END; - - /* Reset the top component */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - - /* Did the operation suceeded */ - if (Result) { - /* Check if we need to update the filesize */ - if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) { - if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && FcbHeader->PagingIoResource) { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - } else { - FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; - } - } - - /* Flag the file as modified */ - FileObject->Flags |= FO_FILE_MODIFIED; - /* Check if the filesize has changed */ - if (FileSizeModified) { - /* Update the file sizes */ - ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.QuadPart = NewSize.QuadPart; - FileObject->Flags |= FO_FILE_SIZE_CHANGED; - } - /* Update the current FO byte offset */ - FileObject->CurrentByteOffset.QuadPart = NewSize.QuadPart; - } - else - { - /* The operation did not succeed - Reset the file size to what it should be - */ - if (FileSizeModified) { - if (FcbHeader->PagingIoResource) { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; - FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - }else{ - FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; - FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; - } - } - } - goto Cleanup; - } else { - goto FailAndCleanup; - } - - ASSERT(0); - } - -LeaveCriticalAndFail: - FsRtlExitFileSystem(); - return FALSE; - - -FailAndCleanup: - - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - return FALSE; - -Cleanup: - - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - return Result; -} - -/* - * @implemented - */ -NTSTATUS -NTAPI -FsRtlGetFileSize(IN PFILE_OBJECT FileObject, - IN OUT PLARGE_INTEGER FileSize) -{ - FILE_STANDARD_INFORMATION Info; - NTSTATUS Status; - IO_STATUS_BLOCK IoStatus; - PDEVICE_OBJECT DeviceObject; - PFAST_IO_DISPATCH FastDispatch; - KEVENT Event; - PIO_STACK_LOCATION IoStackLocation; - PIRP Irp; - BOOLEAN OldHardError; - - - PAGED_CODE(); - - /* Get Device Object and Fast Calls */ - DeviceObject = IoGetRelatedDeviceObject(FileObject); - FastDispatch = DeviceObject->DriverObject->FastIoDispatch; - - /* Check if we support Fast Calls, and check FastIoQueryStandardInfo */ - /* Call the function and see if it succeeds */ - if ( !FastDispatch || - !FastDispatch->FastIoQueryStandardInfo || - !FastDispatch->FastIoQueryStandardInfo(FileObject,TRUE, - &Info,&IoStatus,DeviceObject)) - { - /* If any of the above failed, then we are going to send an IRP to the device object */ - /* Initialize the even for the IO */ - KeInitializeEvent(&Event,NotificationEvent,FALSE); - /* Allocate the IRP */ - Irp = IoAllocateIrp(DeviceObject->StackSize,FALSE); - if (Irp == NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - - /* Don't process hard error */ - OldHardError = IoSetThreadHardErrorMode(FALSE); - - /* Setup the IRP */ - Irp->UserIosb = &IoStatus; - Irp->UserEvent = &Event; - Irp->Tail.Overlay.Thread = PsGetCurrentThread(); - Irp->Flags = IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO; - Irp->RequestorMode = KernelMode; - Irp->Tail.Overlay.OriginalFileObject = FileObject; - Irp->AssociatedIrp.SystemBuffer = &Info; - - /* Setup out stack location */ - IoStackLocation = Irp->Tail.Overlay.CurrentStackLocation; - IoStackLocation--; - IoStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION; - IoStackLocation->FileObject = FileObject; - IoStackLocation->DeviceObject = DeviceObject; - IoStackLocation->Parameters.QueryFile.Length = ALIGN_UP(sizeof(FILE_INFORMATION_CLASS),ULONG); - IoStackLocation->Parameters.QueryFile.FileInformationClass = FileStandardInformation; - - /* Send the IRP to the related device object */ - Status = IofCallDriver(DeviceObject,Irp); - - /* Standard DDK IRP result processing */ - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL); - } - - /* If there was a synchronous error, signal it */ - if (!NT_SUCCESS(Status)) - { - IoStatus.Status = Status; - } - - IoSetThreadHardErrorMode(OldHardError); - } - - /* Check the sync/async IO result */ - if (NT_SUCCESS(IoStatus.Status)) - { - /* Was the request for a directory ? */ - if (Info.Directory) - { - IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY; - } - else - { - FileSize->QuadPart = Info.EndOfFile.QuadPart; - } - } - - return IoStatus.Status; -} - - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlMdlRead(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL *MdlChain, - OUT PIO_STATUS_BLOCK IoStatus) -{ - PDEVICE_OBJECT DeviceObject, BaseDeviceObject; - PFAST_IO_DISPATCH FastDispatch; - - /* Get Device Object and Fast Calls */ - DeviceObject = IoGetRelatedDeviceObject(FileObject); - FastDispatch = DeviceObject->DriverObject->FastIoDispatch; - - /* Check if we support Fast Calls, and check this one */ - if (FastDispatch && FastDispatch->MdlRead) - { - /* Use the fast path */ - return FastDispatch->MdlRead(FileObject, - FileOffset, - Length, - LockKey, - MdlChain, - IoStatus, - DeviceObject); - } - - /* Get the Base File System (Volume) and Fast Calls */ - BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; - - /* If the Base Device Object has its own FastDispatch Routine, fail */ - if (FastDispatch && FastDispatch->MdlRead && - BaseDeviceObject != DeviceObject) - { - return FALSE; - } - - /* No fast path, use slow path */ - return FsRtlMdlReadDev(FileObject, - FileOffset, - Length, - LockKey, - MdlChain, - IoStatus, - DeviceObject); -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject, - IN OUT PMDL MdlChain) -{ - PDEVICE_OBJECT DeviceObject, BaseDeviceObject; - PFAST_IO_DISPATCH FastDispatch; - - /* Get Device Object and Fast Calls */ - DeviceObject = IoGetRelatedDeviceObject(FileObject); - FastDispatch = DeviceObject->DriverObject->FastIoDispatch; - - /* Check if we support Fast Calls, and check this one */ - if (FastDispatch && FastDispatch->MdlReadComplete) - { - /* Use the fast path */ - return FastDispatch->MdlReadComplete(FileObject, - MdlChain, - DeviceObject); - } - - /* Get the Base File System (Volume) and Fast Calls */ - BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; - - /* If the Base Device Object has its own FastDispatch Routine, fail */ - if ((BaseDeviceObject != DeviceObject) && FastDispatch - && FastDispatch->MdlReadComplete) - { - return FALSE; - } - - /* No fast path, use slow path */ - return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject); -} - -/* - * @implemented - */ - BOOLEAN - NTAPI -FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject, - IN PMDL MemoryDescriptorList, - IN PDEVICE_OBJECT DeviceObject) -{ - /* Call the Cache Manager */ - CcMdlReadComplete2(MemoryDescriptorList, FileObject); - return TRUE; -} - - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlMdlReadDev(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL *MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - PFSRTL_COMMON_FCB_HEADER FcbHeader; - BOOLEAN Result = TRUE; - LARGE_INTEGER Offset; - PFAST_IO_DISPATCH FastIoDispatch; - PDEVICE_OBJECT Device; - PAGED_CODE(); - - /* No actual read */ - if (!Length) - { - /* Return success */ - IoStatus->Status = STATUS_SUCCESS; - IoStatus->Information = 0; - return TRUE; - } - - /* Sanity check */ - ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length); - - /* Get the offset and FCB header */ - Offset.QuadPart = FileOffset->QuadPart + Length; - FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; - - /* Enter the FS */ - FsRtlEnterFileSystem(); - CcFastMdlReadWait++; - - /* Lock the FCB */ - ExAcquireResourceShared(FcbHeader->Resource, TRUE); - - /* Check if this is a fast I/O cached file */ - if (!(FileObject->PrivateCacheMap) || - (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) - { - /* It's not, so fail */ - CcFastMdlReadNotPossible += 1; - Result = FALSE; - goto Cleanup; - } - - /* Check if we need to find out if fast I/O is available */ - if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) - { - /* Get the Fast I/O table */ - Device = IoGetRelatedDeviceObject(FileObject); - FastIoDispatch = Device->DriverObject->FastIoDispatch; - - /* Sanity check */ - ASSERT(!KeIsExecutingDpc()); - ASSERT(FastIoDispatch != NULL); - ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); - - /* Ask the driver if we can do it */ - if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, - FileOffset, - Length, - TRUE, - LockKey, - TRUE, - IoStatus, - Device)) - { - /* It's not, fail */ - CcFastMdlReadNotPossible += 1; - Result = FALSE; - goto Cleanup; - } - } - - /* Check if we read too much */ - if (Offset.QuadPart > FcbHeader->FileSize.QuadPart) - { - /* We did, check if the file offset is past the end */ - if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart) - { - /* Set end of file */ - IoStatus->Status = STATUS_END_OF_FILE; - IoStatus->Information = 0; - goto Cleanup; - } - - /* Otherwise, just normalize the length */ - Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); - } - - /* Set this as top-level IRP */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - - _SEH2_TRY - { - /* Attempt a read */ - CcMdlRead(FileObject, FileOffset, Length, MdlChain, IoStatus); - FileObject->Flags |= FO_FILE_FAST_IO_READ; - } - _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - Result = FALSE; - } _SEH2_END; - - - /* Remove the top-level IRP flag */ - PsGetCurrentThread()->TopLevelIrp = 0; - - /* Return to caller */ -Cleanup: - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - return Result; -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PMDL MdlChain) -{ - PDEVICE_OBJECT DeviceObject, BaseDeviceObject; - PFAST_IO_DISPATCH FastDispatch; - - /* Get Device Object and Fast Calls */ - DeviceObject = IoGetRelatedDeviceObject(FileObject); - FastDispatch = DeviceObject->DriverObject->FastIoDispatch; - - /* Check if we support Fast Calls, and check this one */ - if (FastDispatch && FastDispatch->MdlWriteComplete) - { - /* Use the fast path */ - return FastDispatch->MdlWriteComplete(FileObject, - FileOffset, - MdlChain, - DeviceObject); - } - - /* Get the Base File System (Volume) and Fast Calls */ - BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; - - /* If the Base Device Object has its own FastDispatch Routine, fail */ - if (FastDispatch && FastDispatch->MdlWriteComplete && - BaseDeviceObject != DeviceObject) - { - return FALSE; - } - - /* No fast path, use slow path */ - return FsRtlMdlWriteCompleteDev(FileObject, - FileOffset, - MdlChain, - DeviceObject); -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PMDL MdlChain, - IN PDEVICE_OBJECT DeviceObject) -{ - if (FileObject->Flags & FO_WRITE_THROUGH) - { - return FALSE; - } - - - /* Call the Cache Manager */ - CcMdlWriteComplete2(FileObject,FileOffset,MdlChain); - return TRUE; -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL *MdlChain, - OUT PIO_STATUS_BLOCK IoStatus) -{ - PDEVICE_OBJECT DeviceObject, BaseDeviceObject; - PFAST_IO_DISPATCH FastDispatch; - - /* Get Device Object and Fast Calls */ - DeviceObject = IoGetRelatedDeviceObject(FileObject); - FastDispatch = DeviceObject->DriverObject->FastIoDispatch; - - /* Check if we support Fast Calls, and check this one */ - if (FastDispatch && FastDispatch->PrepareMdlWrite) - { - /* Use the fast path */ - return FastDispatch->PrepareMdlWrite(FileObject, - FileOffset, - Length, - LockKey, - MdlChain, - IoStatus, - DeviceObject); - } - - /* Get the Base File System (Volume) and Fast Calls */ - BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; - - /* If the Base Device Object has its own FastDispatch Routine, fail */ - if (FastDispatch && FastDispatch->PrepareMdlWrite && - BaseDeviceObject != DeviceObject) - { - return FALSE; - } - - /* No fast path, use slow path */ - return FsRtlPrepareMdlWriteDev(FileObject, - FileOffset, - Length, - LockKey, - MdlChain, - IoStatus, - DeviceObject); -} - -/* - * @implemented - */ -BOOLEAN -NTAPI -FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL *MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - BOOLEAN Result = TRUE; - PFAST_IO_DISPATCH FastIoDispatch; - PDEVICE_OBJECT Device; - PFSRTL_COMMON_FCB_HEADER FcbHeader; - - LARGE_INTEGER OldFileSize; - LARGE_INTEGER OldValidDataLength; - LARGE_INTEGER NewSize; - LARGE_INTEGER Offset; - - /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */ - BOOLEAN FileOffsetAppend = ((FileOffset->HighPart == (LONG)0xffffffff) && (FileOffset->LowPart == 0xffffffff)); - BOOLEAN FileSizeModified = FALSE; - BOOLEAN ResourceAquiredShared = FALSE; - - /* Initialize some of the vars and pointers */ - OldFileSize.QuadPart = 0; - OldValidDataLength.QuadPart = 0; - - PAGED_CODE(); - - Offset.QuadPart = FileOffset->QuadPart + Length; - - /* Nagar p.544 -- Check with Cc if we can write */ - if ( (!CcCanIWrite(FileObject, Length,TRUE,FALSE))|| - (FileObject->Flags & FO_WRITE_THROUGH)) - { - return FALSE; - } - - IoStatus->Status = STATUS_SUCCESS; - - /* No actual read */ - if (!Length) - { - return TRUE; - } - - FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; - FsRtlEnterFileSystem(); - - /* Check we are going to extend the file */ - if ( (FileOffsetAppend == FALSE) && - ( (FileOffset->QuadPart + Length) <= FcbHeader->ValidDataLength.QuadPart ) - ) - { - /* Acquire the resource shared */ - ExAcquireResourceSharedLite(FcbHeader->Resource,TRUE); - ResourceAquiredShared =TRUE; - } else - { - /* Acquire the resource exclusive */ - ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); - } - - /* Check if we are appending */ - if (FileOffsetAppend == TRUE) { - Offset.QuadPart = FcbHeader->FileSize.QuadPart; - NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; - } else - { - Offset.QuadPart = FileOffset->QuadPart; - NewSize.QuadPart = FileOffset->QuadPart + Length; - } - - if ( (FileObject->PrivateCacheMap) && - (FcbHeader->IsFastIoPossible) && - (MAXLONGLONG >= (LONGLONG) FileOffset->QuadPart + Length) && - (NewSize.QuadPart <= FcbHeader->AllocationSize.QuadPart) ) - { - /* Check if we can keep the lock shared */ - if (ResourceAquiredShared && (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) ) { - ExReleaseResourceLite(FcbHeader->Resource); - ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); - - /* Compute the offset and the new filesize */ - if (FileOffsetAppend) { - Offset.QuadPart = FcbHeader->FileSize.QuadPart; - NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; - } - - /* Recheck the above points since we released and reacquire the lock */ - if ( (FileObject->PrivateCacheMap != NULL) && - (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && - (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart) - ) - { - /* Do nothing */ - } else { - goto FailAndCleanup; - } - } - - /* Check if we need to find out if fast I/O is available */ - if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) - { - /* Sanity check */ - /* ASSERT(!KeIsExecutingDpc()); */ - - /* Get the Fast I/O table */ - Device = IoGetRelatedDeviceObject(FileObject); - FastIoDispatch = Device->DriverObject->FastIoDispatch; - - /* Sanity check */ - ASSERT(FastIoDispatch != NULL); - ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); - - /* Ask the driver if we can do it */ - if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, - FileOffset, - Length, - TRUE, - LockKey, - FALSE, - IoStatus, - Device)) - { - /* It's not, fail */ - goto FailAndCleanup; - } - } - - /* If we are going to modify the filesize, save the old fs in case the operation fails */ - if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) - { - FileSizeModified = TRUE; - OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; - OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; - - /* If the high part of the filesize is going to change, grab the Paging IoResouce */ - if (NewSize.HighPart != FcbHeader->FileSize.HighPart && FcbHeader->PagingIoResource) - { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->FileSize.QuadPart = NewSize.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - } else { - FcbHeader->FileSize.QuadPart = NewSize.QuadPart; - } - } - - - /* Nagar p.544 */ - /* Set ourselves as top component */ - PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; - _SEH2_TRY - { - /* Check if there is a gap between the end of the file and the offset - If yes, then we have to zero the data - */ - if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) { - Result = CcZeroData(FileObject,&FcbHeader->ValidDataLength,&Offset,TRUE); - if (Result) - { - CcPrepareMdlWrite(FileObject,&Offset,Length,MdlChain,IoStatus); - } - } else { - CcPrepareMdlWrite(FileObject,&Offset,Length,MdlChain,IoStatus); - } - - }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - Result = FALSE; - } _SEH2_END; - - /* Reset the top component */ - PsGetCurrentThread()->TopLevelIrp = 0; - - /* Did the operation suceeded */ - if (Result) { - /* Check if we need to update the filesize */ - if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) { - if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && FcbHeader->PagingIoResource) { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - } else { - FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; - } - } - - /* Flag the file as modified */ - FileObject->Flags |= FO_FILE_MODIFIED; - /* Check if the filesize has changed */ - if (FileSizeModified) { - /* Update the file sizes */ - ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.QuadPart = NewSize.QuadPart; - FileObject->Flags |= FO_FILE_SIZE_CHANGED; - } - - } - else - { - /* The operation did not succeed - Reset the file size to what it should be - */ - if (FileSizeModified) { - if (FcbHeader->PagingIoResource) { - ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); - FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; - FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; - ExReleaseResourceLite(FcbHeader->PagingIoResource); - }else{ - FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; - FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; - } - } - } - - goto Cleanup; - - } - else - { - goto FailAndCleanup; - } - - -FailAndCleanup: - - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - return FALSE; - -Cleanup: - - ExReleaseResourceLite(FcbHeader->Resource); - FsRtlExitFileSystem(); - return Result; - -} - -/* -* @implemented -*/ -VOID -NTAPI -FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject) -{ - /* - PAGED_CODE(); - FsRtlAcquireFileExclusiveCommon(FileObject,0,0); - */ - KeBugCheck(FILE_SYSTEM); -} - -/* -* @implemented -*/ -VOID -NTAPI -FsRtlReleaseFile(IN PFILE_OBJECT FileObject) -{ - - KeBugCheck(FILE_SYSTEM); -} - -/*++ - * @name FsRtlRegisterFileSystemFilterCallbacks - * @unimplemented - * - * FILLME - * - * @param FilterDriverObject - * FILLME - * - * @param Callbacks - * FILLME - * - * @return None - * - * @remarks None - * - *--*/ -NTSTATUS -NTAPI -FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject, - IN PFS_FILTER_CALLBACKS Callbacks) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/fsrtl/fastio.c + * PURPOSE: Provides Fast I/O entrypoints to the Cache Manager + * PROGRAMMERS: buzdelabuz2@gmail.com,alex.ionescu@reactos.org + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +VOID +NTAPI +FsRtlIncrementCcFastReadResourceMiss(VOID) +{ + CcFastReadResourceMiss++; +} + +/* + * @implemented + */ +VOID +NTAPI +FsRtlIncrementCcFastReadNotPossible(VOID) +{ + CcFastReadNotPossible++; +} + +/* + * @implemented + */ +VOID +NTAPI +FsRtlIncrementCcFastReadWait(VOID) +{ + CcFastReadWait++; +} + +/* + * @implemented + */ +VOID +NTAPI +FsRtlIncrementCcFastReadNoWait(VOID) +{ + CcFastReadNoWait++; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlCopyRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + + PFSRTL_COMMON_FCB_HEADER FcbHeader; + LARGE_INTEGER Offset; + PFAST_IO_DISPATCH FastIoDispatch; + PDEVICE_OBJECT Device; + BOOLEAN Result = TRUE; + ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset,Length); + + PAGED_CODE(); + ASSERT(FileObject); + ASSERT(FileObject->FsContext); + + /* No actual read */ + if (!Length) + { + /* Return success */ + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = 0; + return TRUE; + } + + if (MAXLONGLONG < (LONGLONG) FileOffset->QuadPart + Length) { + IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; + return FALSE; + } + + /* Get the offset and FCB header */ + Offset.QuadPart = FileOffset->QuadPart + Length; + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + + + if (Wait) { + /* Use a Resource Acquire */ + FsRtlEnterFileSystem(); + CcFastReadWait++; + ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); + } else { + /* Acquire the resource without blocking */ + /* Return false and the I/O manager will retry using the standard IRP method. */ + /* Use a Resource Acquire */ + FsRtlEnterFileSystem(); + if (!ExAcquireResourceSharedLite(FcbHeader->Resource, FALSE)) { + FsRtlExitFileSystem(); + FsRtlIncrementCcFastReadResourceMiss(); + return FALSE; + } + } + + + /* Check if this is a fast I/O cached file */ + if (!(FileObject->PrivateCacheMap) || + (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) { + /* It's not, so fail */ + Result = FALSE; + goto Cleanup; + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffset, + Length, + TRUE, + LockKey, + TRUE, + IoStatus, + Device)) + { + /* It's not, fail */ + Result = FALSE; + goto Cleanup; + } + } + + /* Check if we read too much */ + if (Offset.QuadPart > FcbHeader->FileSize.QuadPart){ + /* We did, check if the file offset is past the end */ + if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart){ + /* Set end of file */ + IoStatus->Status = STATUS_END_OF_FILE; + IoStatus->Information = 0; + goto Cleanup; + } + + /* Otherwise, just normalize the length */ + Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); + } + + /* Set this as top-level IRP */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + + _SEH2_TRY + { + /* Make sure the IO and file size is below 4GB */ + if (Wait && !(Offset.HighPart | FcbHeader->FileSize.HighPart )) { + + /* Call the cache controller */ + CcFastCopyRead (FileObject,FileOffset->LowPart,Length,PageCount,Buffer,IoStatus); + /* File was accessed */ + FileObject->Flags |= FO_FILE_FAST_IO_READ; + if (IoStatus->Status != STATUS_END_OF_FILE) { + ASSERT(( FcbHeader->FileSize.QuadPart) >= (FileOffset->QuadPart + IoStatus->Information)); + } + + } else { + + /* Call the cache controller */ + Result = CcCopyRead(FileObject, FileOffset, Length, Wait,Buffer, IoStatus); + /* File was accessed */ + FileObject->Flags |= FO_FILE_FAST_IO_READ; + if (Result == TRUE) { + ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) || + ((LONGLONG)(FileOffset->QuadPart + IoStatus->Information) <= FcbHeader->FileSize.QuadPart) + ); + } + } + + /* Update the current file offset */ + if (Result == TRUE) { + FileObject->CurrentByteOffset.QuadPart += IoStatus->Information; + } + } + _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + Result = FALSE; + } _SEH2_END; + + PsGetCurrentThread()->TopLevelIrp = 0; + + /* Return to caller */ +Cleanup: + + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + + if (Result == FALSE) { + CcFastReadNotPossible += 1; + } + + return Result; + +} + + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlCopyWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + + BOOLEAN Result = TRUE; + PFAST_IO_DISPATCH FastIoDispatch; + PDEVICE_OBJECT Device; + PFSRTL_COMMON_FCB_HEADER FcbHeader; + + /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */ + BOOLEAN FileOffsetAppend = ((FileOffset->HighPart == (LONG)0xffffffff) && (FileOffset->LowPart == 0xffffffff)); + BOOLEAN ResourceAquiredShared = FALSE; + + BOOLEAN b_4GB = FALSE; + + BOOLEAN FileSizeModified = FALSE; + LARGE_INTEGER OldFileSize; + LARGE_INTEGER OldValidDataLength; + + LARGE_INTEGER NewSize; + LARGE_INTEGER Offset; + + PAGED_CODE(); + + ASSERT(FileObject); + ASSERT(FileObject->FsContext); + + /* Initialize some of the vars and pointers */ + NewSize.QuadPart = 0; + Offset.QuadPart = FileOffset->QuadPart + Length; + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + + /* Nagar p.544 -- Check with Cc if we can write and check if the IO > 64kB (WDK macro) */ + if ( (CcCanIWrite(FileObject, Length,Wait, FALSE) == FALSE) || + (CcCopyWriteWontFlush(FileObject,FileOffset,Length) == FALSE) || + ((FileObject->Flags & FO_WRITE_THROUGH )== TRUE) + ) + { + return FALSE; + } + + /* No actual read */ + if (!Length) + { + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = Length; + return TRUE; + } + + FsRtlEnterFileSystem(); + + /* Nagar p.544/545 -- The CcFastCopyWrite doesn't deal with filesize beyond 4GB*/ + if (Wait && (FcbHeader->AllocationSize.HighPart == 0)) + { + /* If the file offset is not past the file size, then we can acquire the lock shared */ + if ((FileOffsetAppend == FALSE) && (Offset.LowPart <= FcbHeader->ValidDataLength.LowPart)){ + ExAcquireResourceSharedLite(FcbHeader->Resource,TRUE); + ResourceAquiredShared = TRUE; + } else { + ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); + } + + /* Nagar p.544/545 -- If we append, use the file size as offset. Also, check that we aren't crossing the 4GB boundary */ + if ((FileOffsetAppend == TRUE)) { + Offset.LowPart = FcbHeader->FileSize.LowPart; + NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; + b_4GB = (NewSize.LowPart < FcbHeader->FileSize.LowPart); + + } else { + Offset.LowPart = FileOffset->LowPart; + NewSize.LowPart = FileOffset->LowPart + Length; + b_4GB = ((NewSize.LowPart < FileOffset->LowPart) || (FileOffset->HighPart != 0)); + } + + /* Nagar p.544/545 + Make sure that caching is initated. + That fast are allowed for this file stream. + That we are not extending past the allocated size + That we are not creating a hole bigger than 8k + That we are not crossing the 4GB boundary + */ + if ( (FileObject->PrivateCacheMap != NULL) && + (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && + (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && + (Offset.LowPart < (FcbHeader->ValidDataLength.LowPart + 0x2000) ) && + !b_4GB + ) + { + /* If we are extending past the file size, we need to release the lock and acquire it + exclusively, because we are going to need to update the FcbHeader */ + if (ResourceAquiredShared && (NewSize.LowPart > (FcbHeader->ValidDataLength.LowPart + 0x2000))) { + /* Then we need to acquire the resource exclusive */ + ExReleaseResourceLite(FcbHeader->Resource); + ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); + if (FileOffsetAppend == TRUE) { + Offset.LowPart = FcbHeader->FileSize.LowPart; // ?? + NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; + /* Make sure we don't cross the 4GB boundary */ + b_4GB = (NewSize.LowPart < Offset.LowPart); + } + + /* Recheck some of the conditions since we let the lock go */ + if ( (FileObject->PrivateCacheMap != NULL) && + (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && + (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && + (FcbHeader->AllocationSize.HighPart == 0) && + !b_4GB + ) + { + } else + { + goto FailAndCleanup; + } + } + + }else + { + goto FailAndCleanup; + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; + + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffsetAppend? &FcbHeader->FileSize:FileOffset, + Length, + TRUE, + LockKey, + FALSE, + &FastIoCheckIfPossibleStatus, + Device)) + { + /* It's not, fail */ + goto FailAndCleanup; + } + } + + /* If we are going to extend the file then save the old file size + in case the operation fails + */ + if (NewSize.LowPart > FcbHeader->FileSize.LowPart) { + FileSizeModified = TRUE; + OldFileSize.LowPart = FcbHeader->FileSize.LowPart; + OldValidDataLength.LowPart = FcbHeader->ValidDataLength.LowPart; + FcbHeader->FileSize.LowPart = NewSize.LowPart; + } + + /* Set this as top-level IRP */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + + _SEH2_TRY + { + if (Offset.LowPart > FcbHeader->ValidDataLength.LowPart) { + LARGE_INTEGER OffsetVar; + OffsetVar.LowPart = Offset.LowPart; + OffsetVar.HighPart = 0; + CcZeroData(FileObject,&FcbHeader->ValidDataLength,&OffsetVar,TRUE); + } + + /* Call the cache manager */ + CcFastCopyWrite(FileObject,Offset.LowPart,Length,Buffer); + } + _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + Result = FALSE; + } _SEH2_END; + + /* Remove ourselves at the top level component after the IO is done */ + PsGetCurrentThread()->TopLevelIrp = 0; + + /* Did the operation succeed ? */ + if (Result == TRUE) { + /* Update the valid file size if necessary */ + if (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart){ + FcbHeader->ValidDataLength.LowPart = NewSize.LowPart ; + } + + /* Flag the file as modified */ + FileObject->Flags |= FO_FILE_MODIFIED; + + /* Update the strucutres if the file size changed */ + if (FileSizeModified) { + ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.LowPart = NewSize.LowPart; + FileObject->Flags |= FO_FILE_SIZE_CHANGED; + } + + /* Update the file object current file offset */ + FileObject->CurrentByteOffset.QuadPart = NewSize.LowPart; + + } else { + + /* Result == FALSE if we get here. */ + if (FileSizeModified) { + /* If the file size was modified then restore the old file size */ + if(FcbHeader->PagingIoResource != NULL) { + // Nagar P.544 Restore the old file size if operation didn't succeed. + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource,TRUE); + FcbHeader->FileSize.LowPart = OldFileSize.LowPart; + FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + } else { + /* If there is no lock and do it without */ + FcbHeader->FileSize.LowPart = OldFileSize.LowPart; + FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; + } + } else { + } + } + + goto Cleanup; + + } else { + + LARGE_INTEGER OldFileSize; + + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + + // Nagar P.544 + /* Check if we need to acquire the resource exclusive */ + if ( (FileOffsetAppend == FALSE) && + ( (FileOffset->QuadPart + Length) <= FcbHeader->ValidDataLength.QuadPart ) + ) + { + /* Acquire the resource shared */ + if (!ExAcquireResourceSharedLite(FcbHeader->Resource,Wait)) { + goto LeaveCriticalAndFail; + } + ResourceAquiredShared =TRUE; + } else { + /* Acquire the resource exclusive */ + if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource,Wait)) { + goto LeaveCriticalAndFail; + } + } + + /* Check if we are appending */ + if (FileOffsetAppend == TRUE) { + Offset.QuadPart = FcbHeader->FileSize.QuadPart; + NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; + } else { + Offset.QuadPart = FileOffset->QuadPart; + NewSize.QuadPart += FileOffset->QuadPart + Length; + } + + /* Nagar p.544/545 + Make sure that caching is initated. + That fast are allowed for this file stream. + That we are not extending past the allocated size + That we are not creating a hole bigger than 8k + */ + if ( (FileObject->PrivateCacheMap != NULL) && + (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && + ((FcbHeader->ValidDataLength.QuadPart + 0x2000) > Offset.QuadPart) && + (MAXLONGLONG > (Offset.QuadPart + Length)) && + (FcbHeader->AllocationSize.QuadPart >= NewSize.QuadPart) + ) + { + /* Check if we can keep the lock shared */ + if (ResourceAquiredShared && (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) ) { + ExReleaseResourceLite(FcbHeader->Resource); + if(!ExAcquireResourceExclusiveLite(FcbHeader->Resource,Wait)) + { + goto LeaveCriticalAndFail; + } + + /* Compute the offset and the new filesize */ + if (FileOffsetAppend) { + Offset.QuadPart = FcbHeader->FileSize.QuadPart; + NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; + } + + /* Recheck the above points since we released and reacquire the lock */ + if ( (FileObject->PrivateCacheMap != NULL) && + (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && + (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart) + ) + { + /* Do nothing */ + } else { + goto FailAndCleanup; + } + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; + + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffsetAppend? &FcbHeader->FileSize:FileOffset, + Length, + TRUE, + LockKey, + FALSE, + &FastIoCheckIfPossibleStatus, + Device)) + { + /* It's not, fail */ + goto FailAndCleanup; + } + } + + + /* If we are going to modify the filesize, save the old fs in case the operation fails */ + if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) { + FileSizeModified = TRUE; + OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; + OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; + + /* If the high part of the filesize is going to change, grab the Paging IoResouce */ + if (NewSize.HighPart != FcbHeader->FileSize.HighPart && FcbHeader->PagingIoResource) { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->FileSize.QuadPart = NewSize.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + } else { + FcbHeader->FileSize.QuadPart = NewSize.QuadPart; + } + } + + /* Nagar p.544 */ + /* Set ourselves as top component */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + _SEH2_TRY + { + BOOLEAN CallCc = TRUE; + /* Check if there is a gap between the end of the file and the offset + If yes, then we have to zero the data + */ + if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) { + if (!(Result = CcZeroData(FileObject,&FcbHeader->ValidDataLength,&Offset,Wait))) { + /* If this operation fails, then we have to exit + We can jump outside the SEH, so I a using a variable to exit + normally + */ + CallCc = FALSE; + } + } + + /* Unless the CcZeroData failed, call the cache manager */ + if (CallCc) { + Result = CcCopyWrite(FileObject,&Offset,Length, Wait, Buffer); + } + }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + Result = FALSE; + } _SEH2_END; + + /* Reset the top component */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + + /* Did the operation suceeded */ + if (Result) { + /* Check if we need to update the filesize */ + if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) { + if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && FcbHeader->PagingIoResource) { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + } else { + FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; + } + } + + /* Flag the file as modified */ + FileObject->Flags |= FO_FILE_MODIFIED; + /* Check if the filesize has changed */ + if (FileSizeModified) { + /* Update the file sizes */ + ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.QuadPart = NewSize.QuadPart; + FileObject->Flags |= FO_FILE_SIZE_CHANGED; + } + /* Update the current FO byte offset */ + FileObject->CurrentByteOffset.QuadPart = NewSize.QuadPart; + } + else + { + /* The operation did not succeed + Reset the file size to what it should be + */ + if (FileSizeModified) { + if (FcbHeader->PagingIoResource) { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; + FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + }else{ + FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; + FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; + } + } + } + goto Cleanup; + } else { + goto FailAndCleanup; + } + + ASSERT(0); + } + +LeaveCriticalAndFail: + FsRtlExitFileSystem(); + return FALSE; + + +FailAndCleanup: + + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return FALSE; + +Cleanup: + + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return Result; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +FsRtlGetFileSize(IN PFILE_OBJECT FileObject, + IN OUT PLARGE_INTEGER FileSize) +{ + FILE_STANDARD_INFORMATION Info; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + PDEVICE_OBJECT DeviceObject; + PFAST_IO_DISPATCH FastDispatch; + KEVENT Event; + PIO_STACK_LOCATION IoStackLocation; + PIRP Irp; + BOOLEAN OldHardError; + + + PAGED_CODE(); + + /* Get Device Object and Fast Calls */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we support Fast Calls, and check FastIoQueryStandardInfo */ + /* Call the function and see if it succeeds */ + if ( !FastDispatch || + !FastDispatch->FastIoQueryStandardInfo || + !FastDispatch->FastIoQueryStandardInfo(FileObject,TRUE, + &Info,&IoStatus,DeviceObject)) + { + /* If any of the above failed, then we are going to send an IRP to the device object */ + /* Initialize the even for the IO */ + KeInitializeEvent(&Event,NotificationEvent,FALSE); + /* Allocate the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize,FALSE); + if (Irp == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + + /* Don't process hard error */ + OldHardError = IoSetThreadHardErrorMode(FALSE); + + /* Setup the IRP */ + Irp->UserIosb = &IoStatus; + Irp->UserEvent = &Event; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->Flags = IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO; + Irp->RequestorMode = KernelMode; + Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->AssociatedIrp.SystemBuffer = &Info; + + /* Setup out stack location */ + IoStackLocation = Irp->Tail.Overlay.CurrentStackLocation; + IoStackLocation--; + IoStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION; + IoStackLocation->FileObject = FileObject; + IoStackLocation->DeviceObject = DeviceObject; + IoStackLocation->Parameters.QueryFile.Length = ALIGN_UP(sizeof(FILE_INFORMATION_CLASS),ULONG); + IoStackLocation->Parameters.QueryFile.FileInformationClass = FileStandardInformation; + + /* Send the IRP to the related device object */ + Status = IofCallDriver(DeviceObject,Irp); + + /* Standard DDK IRP result processing */ + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL); + } + + /* If there was a synchronous error, signal it */ + if (!NT_SUCCESS(Status)) + { + IoStatus.Status = Status; + } + + IoSetThreadHardErrorMode(OldHardError); + } + + /* Check the sync/async IO result */ + if (NT_SUCCESS(IoStatus.Status)) + { + /* Was the request for a directory ? */ + if (Info.Directory) + { + IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY; + } + else + { + FileSize->QuadPart = Info.EndOfFile.QuadPart; + } + } + + return IoStatus.Status; +} + + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlMdlRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus) +{ + PDEVICE_OBJECT DeviceObject, BaseDeviceObject; + PFAST_IO_DISPATCH FastDispatch; + + /* Get Device Object and Fast Calls */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we support Fast Calls, and check this one */ + if (FastDispatch && FastDispatch->MdlRead) + { + /* Use the fast path */ + return FastDispatch->MdlRead(FileObject, + FileOffset, + Length, + LockKey, + MdlChain, + IoStatus, + DeviceObject); + } + + /* Get the Base File System (Volume) and Fast Calls */ + BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; + + /* If the Base Device Object has its own FastDispatch Routine, fail */ + if (FastDispatch && FastDispatch->MdlRead && + BaseDeviceObject != DeviceObject) + { + return FALSE; + } + + /* No fast path, use slow path */ + return FsRtlMdlReadDev(FileObject, + FileOffset, + Length, + LockKey, + MdlChain, + IoStatus, + DeviceObject); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject, + IN OUT PMDL MdlChain) +{ + PDEVICE_OBJECT DeviceObject, BaseDeviceObject; + PFAST_IO_DISPATCH FastDispatch; + + /* Get Device Object and Fast Calls */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we support Fast Calls, and check this one */ + if (FastDispatch && FastDispatch->MdlReadComplete) + { + /* Use the fast path */ + return FastDispatch->MdlReadComplete(FileObject, + MdlChain, + DeviceObject); + } + + /* Get the Base File System (Volume) and Fast Calls */ + BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; + + /* If the Base Device Object has its own FastDispatch Routine, fail */ + if ((BaseDeviceObject != DeviceObject) && FastDispatch + && FastDispatch->MdlReadComplete) + { + return FALSE; + } + + /* No fast path, use slow path */ + return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject); +} + +/* + * @implemented + */ + BOOLEAN + NTAPI +FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject, + IN PMDL MemoryDescriptorList, + IN PDEVICE_OBJECT DeviceObject) +{ + /* Call the Cache Manager */ + CcMdlReadComplete2(MemoryDescriptorList, FileObject); + return TRUE; +} + + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlMdlReadDev(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + PFSRTL_COMMON_FCB_HEADER FcbHeader; + BOOLEAN Result = TRUE; + LARGE_INTEGER Offset; + PFAST_IO_DISPATCH FastIoDispatch; + PDEVICE_OBJECT Device; + PAGED_CODE(); + + /* No actual read */ + if (!Length) + { + /* Return success */ + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = 0; + return TRUE; + } + + /* Sanity check */ + ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length); + + /* Get the offset and FCB header */ + Offset.QuadPart = FileOffset->QuadPart + Length; + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + + /* Enter the FS */ + FsRtlEnterFileSystem(); + CcFastMdlReadWait++; + + /* Lock the FCB */ + ExAcquireResourceShared(FcbHeader->Resource, TRUE); + + /* Check if this is a fast I/O cached file */ + if (!(FileObject->PrivateCacheMap) || + (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) + { + /* It's not, so fail */ + CcFastMdlReadNotPossible += 1; + Result = FALSE; + goto Cleanup; + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffset, + Length, + TRUE, + LockKey, + TRUE, + IoStatus, + Device)) + { + /* It's not, fail */ + CcFastMdlReadNotPossible += 1; + Result = FALSE; + goto Cleanup; + } + } + + /* Check if we read too much */ + if (Offset.QuadPart > FcbHeader->FileSize.QuadPart) + { + /* We did, check if the file offset is past the end */ + if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart) + { + /* Set end of file */ + IoStatus->Status = STATUS_END_OF_FILE; + IoStatus->Information = 0; + goto Cleanup; + } + + /* Otherwise, just normalize the length */ + Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); + } + + /* Set this as top-level IRP */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + + _SEH2_TRY + { + /* Attempt a read */ + CcMdlRead(FileObject, FileOffset, Length, MdlChain, IoStatus); + FileObject->Flags |= FO_FILE_FAST_IO_READ; + } + _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + Result = FALSE; + } _SEH2_END; + + + /* Remove the top-level IRP flag */ + PsGetCurrentThread()->TopLevelIrp = 0; + + /* Return to caller */ +Cleanup: + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return Result; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain) +{ + PDEVICE_OBJECT DeviceObject, BaseDeviceObject; + PFAST_IO_DISPATCH FastDispatch; + + /* Get Device Object and Fast Calls */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we support Fast Calls, and check this one */ + if (FastDispatch && FastDispatch->MdlWriteComplete) + { + /* Use the fast path */ + return FastDispatch->MdlWriteComplete(FileObject, + FileOffset, + MdlChain, + DeviceObject); + } + + /* Get the Base File System (Volume) and Fast Calls */ + BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; + + /* If the Base Device Object has its own FastDispatch Routine, fail */ + if (FastDispatch && FastDispatch->MdlWriteComplete && + BaseDeviceObject != DeviceObject) + { + return FALSE; + } + + /* No fast path, use slow path */ + return FsRtlMdlWriteCompleteDev(FileObject, + FileOffset, + MdlChain, + DeviceObject); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + if (FileObject->Flags & FO_WRITE_THROUGH) + { + return FALSE; + } + + + /* Call the Cache Manager */ + CcMdlWriteComplete2(FileObject,FileOffset,MdlChain); + return TRUE; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus) +{ + PDEVICE_OBJECT DeviceObject, BaseDeviceObject; + PFAST_IO_DISPATCH FastDispatch; + + /* Get Device Object and Fast Calls */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we support Fast Calls, and check this one */ + if (FastDispatch && FastDispatch->PrepareMdlWrite) + { + /* Use the fast path */ + return FastDispatch->PrepareMdlWrite(FileObject, + FileOffset, + Length, + LockKey, + MdlChain, + IoStatus, + DeviceObject); + } + + /* Get the Base File System (Volume) and Fast Calls */ + BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; + + /* If the Base Device Object has its own FastDispatch Routine, fail */ + if (FastDispatch && FastDispatch->PrepareMdlWrite && + BaseDeviceObject != DeviceObject) + { + return FALSE; + } + + /* No fast path, use slow path */ + return FsRtlPrepareMdlWriteDev(FileObject, + FileOffset, + Length, + LockKey, + MdlChain, + IoStatus, + DeviceObject); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN Result = TRUE; + PFAST_IO_DISPATCH FastIoDispatch; + PDEVICE_OBJECT Device; + PFSRTL_COMMON_FCB_HEADER FcbHeader; + + LARGE_INTEGER OldFileSize; + LARGE_INTEGER OldValidDataLength; + LARGE_INTEGER NewSize; + LARGE_INTEGER Offset; + + /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */ + BOOLEAN FileOffsetAppend = ((FileOffset->HighPart == (LONG)0xffffffff) && (FileOffset->LowPart == 0xffffffff)); + BOOLEAN FileSizeModified = FALSE; + BOOLEAN ResourceAquiredShared = FALSE; + + /* Initialize some of the vars and pointers */ + OldFileSize.QuadPart = 0; + OldValidDataLength.QuadPart = 0; + + PAGED_CODE(); + + Offset.QuadPart = FileOffset->QuadPart + Length; + + /* Nagar p.544 -- Check with Cc if we can write */ + if ( (!CcCanIWrite(FileObject, Length,TRUE,FALSE))|| + (FileObject->Flags & FO_WRITE_THROUGH)) + { + return FALSE; + } + + IoStatus->Status = STATUS_SUCCESS; + + /* No actual read */ + if (!Length) + { + return TRUE; + } + + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + FsRtlEnterFileSystem(); + + /* Check we are going to extend the file */ + if ( (FileOffsetAppend == FALSE) && + ( (FileOffset->QuadPart + Length) <= FcbHeader->ValidDataLength.QuadPart ) + ) + { + /* Acquire the resource shared */ + ExAcquireResourceSharedLite(FcbHeader->Resource,TRUE); + ResourceAquiredShared =TRUE; + } else + { + /* Acquire the resource exclusive */ + ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); + } + + /* Check if we are appending */ + if (FileOffsetAppend == TRUE) { + Offset.QuadPart = FcbHeader->FileSize.QuadPart; + NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; + } else + { + Offset.QuadPart = FileOffset->QuadPart; + NewSize.QuadPart = FileOffset->QuadPart + Length; + } + + if ( (FileObject->PrivateCacheMap) && + (FcbHeader->IsFastIoPossible) && + (MAXLONGLONG >= (LONGLONG) FileOffset->QuadPart + Length) && + (NewSize.QuadPart <= FcbHeader->AllocationSize.QuadPart) ) + { + /* Check if we can keep the lock shared */ + if (ResourceAquiredShared && (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) ) { + ExReleaseResourceLite(FcbHeader->Resource); + ExAcquireResourceExclusiveLite(FcbHeader->Resource,TRUE); + + /* Compute the offset and the new filesize */ + if (FileOffsetAppend) { + Offset.QuadPart = FcbHeader->FileSize.QuadPart; + NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; + } + + /* Recheck the above points since we released and reacquire the lock */ + if ( (FileObject->PrivateCacheMap != NULL) && + (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && + (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart) + ) + { + /* Do nothing */ + } else { + goto FailAndCleanup; + } + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + /* Sanity check */ + /* ASSERT(!KeIsExecutingDpc()); */ + + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffset, + Length, + TRUE, + LockKey, + FALSE, + IoStatus, + Device)) + { + /* It's not, fail */ + goto FailAndCleanup; + } + } + + /* If we are going to modify the filesize, save the old fs in case the operation fails */ + if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) + { + FileSizeModified = TRUE; + OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; + OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; + + /* If the high part of the filesize is going to change, grab the Paging IoResouce */ + if (NewSize.HighPart != FcbHeader->FileSize.HighPart && FcbHeader->PagingIoResource) + { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->FileSize.QuadPart = NewSize.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + } else { + FcbHeader->FileSize.QuadPart = NewSize.QuadPart; + } + } + + + /* Nagar p.544 */ + /* Set ourselves as top component */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + _SEH2_TRY + { + /* Check if there is a gap between the end of the file and the offset + If yes, then we have to zero the data + */ + if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) { + Result = CcZeroData(FileObject,&FcbHeader->ValidDataLength,&Offset,TRUE); + if (Result) + { + CcPrepareMdlWrite(FileObject,&Offset,Length,MdlChain,IoStatus); + } + } else { + CcPrepareMdlWrite(FileObject,&Offset,Length,MdlChain,IoStatus); + } + + }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + Result = FALSE; + } _SEH2_END; + + /* Reset the top component */ + PsGetCurrentThread()->TopLevelIrp = 0; + + /* Did the operation suceeded */ + if (Result) { + /* Check if we need to update the filesize */ + if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) { + if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && FcbHeader->PagingIoResource) { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + } else { + FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; + } + } + + /* Flag the file as modified */ + FileObject->Flags |= FO_FILE_MODIFIED; + /* Check if the filesize has changed */ + if (FileSizeModified) { + /* Update the file sizes */ + ((SHARED_CACHE_MAP*) FileObject->SectionObjectPointer->SharedCacheMap)->FileSize.QuadPart = NewSize.QuadPart; + FileObject->Flags |= FO_FILE_SIZE_CHANGED; + } + + } + else + { + /* The operation did not succeed + Reset the file size to what it should be + */ + if (FileSizeModified) { + if (FcbHeader->PagingIoResource) { + ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); + FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; + FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; + ExReleaseResourceLite(FcbHeader->PagingIoResource); + }else{ + FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; + FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; + } + } + } + + goto Cleanup; + + } + else + { + goto FailAndCleanup; + } + + +FailAndCleanup: + + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return FALSE; + +Cleanup: + + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return Result; + +} + +/* +* @implemented +*/ +VOID +NTAPI +FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject) +{ + /* + PAGED_CODE(); + FsRtlAcquireFileExclusiveCommon(FileObject,0,0); + */ + KeBugCheck(FILE_SYSTEM); +} + +/* +* @implemented +*/ +VOID +NTAPI +FsRtlReleaseFile(IN PFILE_OBJECT FileObject) +{ + + KeBugCheck(FILE_SYSTEM); +} + +/*++ + * @name FsRtlRegisterFileSystemFilterCallbacks + * @unimplemented + * + * FILLME + * + * @param FilterDriverObject + * FILLME + * + * @param Callbacks + * FILLME + * + * @return None + * + * @remarks None + * + *--*/ +NTSTATUS +NTAPI +FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject, + IN PFS_FILTER_CALLBACKS Callbacks) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} +