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