reactos/sdk/lib/drivers/copysup/copysup.c

693 lines
22 KiB
C
Raw Normal View History

[RDBSS] - Implement RxCloseAssociatedSrvOpen(), RxFastIoRead(), RxPurgeNetFcb(), RxRemoveShareAccess(), RxRemoveShareAccessPerSrvOpens() - Continue implementation of RxCommonCleanup() to handle allocated SRV_OPEN - Halfplement RxFastIoCheckIfPossible() so that it handles read operations - Stub RxCancelNotifyChangeDirectoryRequestsForFobx() [RXCE] - Implement RxChangeBufferingState(), RxFinalizeSrvOpen(), RxFreeFcbObject(), RxGatherRequestsForSrvOpen(), RxGetDeviceObjectOfInstance(), RxInitializeRxTimer(), RxMarkFobxOnCleanup(), RxMarkFobxOnClose(), RxpDiscardChangeBufferingStateRequests(), RxpDispatchChangeBufferingStateRequests(), RxpLookupSrvOpenForRequestLite(), RxpMarkInstanceForScavengedFinalization(), RxPostOneShotTimerRequest(), RxPrepareRequestForReuse(), RxProcessChangeBufferingStateRequestsForSrvOpen(), RxpUndoScavengerFinalizationMarking(), RxPurgeChangeBufferingStateRequestsForSrvOpen(), RxPurgeFobxFromCache(), RxRemoveNameNetFcb(), RxScavengerTimerRoutine(), RxTimerDispatch() - Finish implementation of RxDereference() to handle scavenger - Finish implementation of RxLowIoCompletionTail() to handle blocked operations resume - Fix a bug in RxFinalizeNetFcb() where it was dereferencing its NET_ROOT instead of its V_NET_ROOT - Fix bugs in __RxAcquireFcb() where it improperly handled the lack of RX_CONTEXT - Halfplement RxResumeBlockedOperations_ALL() to extract blocked operations from RX_CONTEXT (and drop them...) - Stub RxDispatchChangeBufferingStateRequests(), RxScavengerFinalizeEntries() [COPYSUP] - Implement FsRtlCopyRead2() This library is basically what you can find in FsRtl with an extended support of Top Level IRP. It is used by RDBSS for FastIO. Next to come in it will be FsRtlCopyWrite2(). This commit brings several improvements to current work on RBDSS/RXCE. First of all, both libraries will leak less (again!). It also brings the scavenger infrastructure (not fully fonctionnal though). Our NFS driver doesn't make use of it though. Finally, this brings support of FastIO (for read operations ;-)) to our NFS driver! Regarding CORE-13484, with copy + FastIO I could copy a file without troubles. But that seems to be still problematic with xcopy without FastIO... CORE-13484 CORE-11327 svn path=/trunk/; revision=75265
2017-07-02 17:00:11 +00:00
/*
* ReactOS kernel
* Copyright (C) 2017 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: sdk/lib/drivers/copysup/copysup.c
* PURPOSE: CopySup library
* PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include "copysup.h"
#include <pseh/pseh2.h>
#define NDEBUG
#include <debug.h>
[RDBSS] - Implement RxCloseAssociatedSrvOpen(), RxFastIoRead(), RxPurgeNetFcb(), RxRemoveShareAccess(), RxRemoveShareAccessPerSrvOpens() - Continue implementation of RxCommonCleanup() to handle allocated SRV_OPEN - Halfplement RxFastIoCheckIfPossible() so that it handles read operations - Stub RxCancelNotifyChangeDirectoryRequestsForFobx() [RXCE] - Implement RxChangeBufferingState(), RxFinalizeSrvOpen(), RxFreeFcbObject(), RxGatherRequestsForSrvOpen(), RxGetDeviceObjectOfInstance(), RxInitializeRxTimer(), RxMarkFobxOnCleanup(), RxMarkFobxOnClose(), RxpDiscardChangeBufferingStateRequests(), RxpDispatchChangeBufferingStateRequests(), RxpLookupSrvOpenForRequestLite(), RxpMarkInstanceForScavengedFinalization(), RxPostOneShotTimerRequest(), RxPrepareRequestForReuse(), RxProcessChangeBufferingStateRequestsForSrvOpen(), RxpUndoScavengerFinalizationMarking(), RxPurgeChangeBufferingStateRequestsForSrvOpen(), RxPurgeFobxFromCache(), RxRemoveNameNetFcb(), RxScavengerTimerRoutine(), RxTimerDispatch() - Finish implementation of RxDereference() to handle scavenger - Finish implementation of RxLowIoCompletionTail() to handle blocked operations resume - Fix a bug in RxFinalizeNetFcb() where it was dereferencing its NET_ROOT instead of its V_NET_ROOT - Fix bugs in __RxAcquireFcb() where it improperly handled the lack of RX_CONTEXT - Halfplement RxResumeBlockedOperations_ALL() to extract blocked operations from RX_CONTEXT (and drop them...) - Stub RxDispatchChangeBufferingStateRequests(), RxScavengerFinalizeEntries() [COPYSUP] - Implement FsRtlCopyRead2() This library is basically what you can find in FsRtl with an extended support of Top Level IRP. It is used by RDBSS for FastIO. Next to come in it will be FsRtlCopyWrite2(). This commit brings several improvements to current work on RBDSS/RXCE. First of all, both libraries will leak less (again!). It also brings the scavenger infrastructure (not fully fonctionnal though). Our NFS driver doesn't make use of it though. Finally, this brings support of FastIO (for read operations ;-)) to our NFS driver! Regarding CORE-13484, with copy + FastIO I could copy a file without troubles. But that seems to be still problematic with xcopy without FastIO... CORE-13484 CORE-11327 svn path=/trunk/; revision=75265
2017-07-02 17:00:11 +00:00
/* FUNCTIONS ****************************************************************/
/*
* @implemented
*/
BOOLEAN
FsRtlCopyRead2(
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,
IN PVOID TopLevelContext)
{
BOOLEAN Ret;
ULONG PageCount;
LARGE_INTEGER FinalOffset;
PFSRTL_COMMON_FCB_HEADER Fcb;
PFAST_IO_DISPATCH FastIoDispatch;
PDEVICE_OBJECT RelatedDeviceObject;
PAGED_CODE();
Ret = TRUE;
PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset, Length);
/* Null-length read is always OK */
if (Length == 0)
{
IoStatus->Information = 0;
IoStatus->Status = STATUS_SUCCESS;
return TRUE;
}
/* Check we don't overflow */
FinalOffset.QuadPart = FileOffset->QuadPart + Length;
if (FinalOffset.QuadPart <= 0)
{
return FALSE;
}
/* Get the FCB (at least, its header) */
Fcb = FileObject->FsContext;
FsRtlEnterFileSystem();
/* Acquire its resource (shared) */
if (Wait)
{
ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
}
else
{
if (!ExAcquireResourceSharedLite(Fcb->Resource, FALSE))
{
Ret = FALSE;
goto CriticalSection;
}
}
/* If cache wasn't initialized, or FastIO isn't possible, fail */
if (FileObject->PrivateCacheMap == NULL || Fcb->IsFastIoPossible == FastIoIsNotPossible)
{
Ret = FALSE;
goto Resource;
}
/* If FastIO is questionable, then, question! */
if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
{
RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
ASSERT(FastIoDispatch != NULL);
ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
/* If it's not possible, then fail */
if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, FileOffset, Length,
Wait, LockKey, TRUE, IoStatus, RelatedDeviceObject))
{
Ret = FALSE;
goto Resource;
}
}
/* If we get beyond file end... */
if (FinalOffset.QuadPart > Fcb->FileSize.QuadPart)
{
/* Fail if the offset was already beyond file end */
if (FileOffset->QuadPart >= Fcb->FileSize.QuadPart)
{
IoStatus->Information = 0;
IoStatus->Status = STATUS_END_OF_FILE;
goto Resource;
}
/* Otherwise, just fix read length */
Length = (ULONG)(Fcb->FileSize.QuadPart - FileOffset->QuadPart);
}
/* Set caller provided context as TLI */
IoSetTopLevelIrp(TopLevelContext);
_SEH2_TRY
{
/* If we cannot wait, or if file is bigger than 4GB */
if (!Wait || (FinalOffset.HighPart | Fcb->FileSize.HighPart) != 0)
{
/* Forward to Cc */
Ret = CcCopyRead(FileObject, FileOffset, Length, Wait, Buffer, IoStatus);
SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
/* Validate output */
ASSERT(!Ret || (IoStatus->Status == STATUS_END_OF_FILE) || (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= (ULONGLONG)Fcb->FileSize.QuadPart));
}
else
{
/* Forward to Cc */
CcFastCopyRead(FileObject, FileOffset->LowPart, Length, PageCount, Buffer, IoStatus);
SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
/* Validate output */
ASSERT((IoStatus->Status == STATUS_END_OF_FILE) || ((FileOffset->LowPart + IoStatus->Information) <= Fcb->FileSize.LowPart));
}
/* If read was successful, update the byte offset in the FO */
if (Ret)
{
FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
}
}
_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
Ret = FALSE;
}
_SEH2_END;
/* Reset TLI */
IoSetTopLevelIrp(NULL);
Resource:
ExReleaseResourceLite(Fcb->Resource);
CriticalSection:
FsRtlExitFileSystem();
return Ret;
}
/*
* @implemented
*/
BOOLEAN
FsRtlCopyWrite2(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject,
IN PVOID TopLevelContext)
{
IO_STATUS_BLOCK LocalIoStatus;
PFSRTL_ADVANCED_FCB_HEADER Fcb;
BOOLEAN WriteToEof, AcquiredShared, FileSizeChanged, Ret;
LARGE_INTEGER WriteOffset, LastOffset, InitialFileSize, InitialValidDataLength;
PAGED_CODE();
/* First, check whether we're writing to EOF */
WriteToEof = ((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
(FileOffset->HighPart == -1));
/* If Cc says we cannot write, fail now */
if (!CcCanIWrite(FileObject, Length, Wait, FALSE))
{
return FALSE;
}
/* Write through means no cache */
if (BooleanFlagOn(FileObject->Flags, FO_WRITE_THROUGH))
{
return FALSE;
}
/* If write is > 64Kb, don't use FastIO */
if (!CcCopyWriteWontFlush(FileObject, FileOffset, Length))
{
return FALSE;
}
/* Initialize the IO_STATUS_BLOCK */
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = Length;
/* No length, it's already written! */
if (Length == 0)
{
return TRUE;
}
AcquiredShared = FALSE;
FileSizeChanged = FALSE;
Fcb = FileObject->FsContext;
FsRtlEnterFileSystem();
/* If we cannot wait, or deal with files bigger then 4GB */
if (!Wait || (Fcb->AllocationSize.HighPart != 0))
{
/* If we're to extend the file, then, acquire exclusively */
if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
{
if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
{
FsRtlExitFileSystem();
return FALSE;
}
}
/* Otherwise, a shared lock is enough */
else
{
if (!ExAcquireResourceSharedLite(Fcb->Resource, Wait))
{
FsRtlExitFileSystem();
return FALSE;
}
AcquiredShared = TRUE;
}
/* Get first write offset, and last */
if (WriteToEof)
{
WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
LastOffset.QuadPart = WriteOffset.QuadPart + Length;
}
else
{
WriteOffset.QuadPart = FileOffset->QuadPart;
LastOffset.QuadPart = WriteOffset.QuadPart + Length;
}
/* If cache wasn't initialized, fail */
if (FileObject->PrivateCacheMap == NULL ||
Fcb->IsFastIoPossible == FastIoIsNotPossible)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* If we're to write beyond allocation size, it's no go,
* same is we create a hole bigger than 8kb
*/
if ((Fcb->ValidDataLength.QuadPart + 0x2000 <= WriteOffset.QuadPart) ||
(Length > MAXLONGLONG - WriteOffset.QuadPart) ||
(Fcb->AllocationSize.QuadPart < LastOffset.QuadPart))
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* If we have to extend the VDL, shared lock isn't enough */
if (AcquiredShared && LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
{
/* So release, and attempt to acquire exclusively */
ExReleaseResourceLite(Fcb->Resource);
if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
{
FsRtlExitFileSystem();
return FALSE;
}
/* Get again EOF, in case file size changed in between */
if (WriteToEof)
{
WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
LastOffset.QuadPart = WriteOffset.QuadPart + Length;
}
/* Make sure caching is still enabled */
if (FileObject->PrivateCacheMap == NULL ||
Fcb->IsFastIoPossible == FastIoIsNotPossible)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* And that we're not writting beyond allocation size */
if (Fcb->AllocationSize.QuadPart < LastOffset.QuadPart)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
}
/* If FastIO is questionable, then question */
if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
{
PFAST_IO_DISPATCH FastIoDispatch;
PDEVICE_OBJECT RelatedDeviceObject;
RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
ASSERT(FastIoDispatch != NULL);
ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
&WriteOffset,
Length, Wait, LockKey,
FALSE, &LocalIoStatus,
RelatedDeviceObject))
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
}
/* If we write beyond EOF, then, save previous sizes (in case of failure)
* and update file size, to allow writing
*/
if (LastOffset.QuadPart > Fcb->FileSize.QuadPart)
{
FileSizeChanged = TRUE;
InitialFileSize.QuadPart = Fcb->FileSize.QuadPart;
InitialValidDataLength.QuadPart = Fcb->ValidDataLength.QuadPart;
if (LastOffset.HighPart != Fcb->FileSize.HighPart &&
Fcb->PagingIoResource != NULL)
{
ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
Fcb->FileSize.QuadPart = LastOffset.QuadPart;
ExReleaseResourceLite(Fcb->PagingIoResource);
}
else
{
Fcb->FileSize.QuadPart = LastOffset.QuadPart;
}
}
/* Set caller provided context as top level IRP */
IoSetTopLevelIrp(TopLevelContext);
Ret = TRUE;
/* And perform the writing */
_SEH2_TRY
{
/* Check whether we've to create a hole first */
if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
{
Ret = CcZeroData(FileObject, &Fcb->ValidDataLength,
&WriteOffset, Wait);
}
/* If not needed, or if it worked, write data */
if (Ret)
{
Ret = CcCopyWrite(FileObject, &WriteOffset,
Length, Wait, Buffer);
}
}
_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
Ret = FALSE;
}
_SEH2_END;
/* Restore top level IRP */
IoSetTopLevelIrp(NULL);
/* If writing succeed */
if (Ret)
{
/* If we wrote beyond VDL, update it */
if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
{
if (LastOffset.HighPart != Fcb->ValidDataLength.HighPart &&
Fcb->PagingIoResource != NULL)
{
ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
ExReleaseResourceLite(Fcb->PagingIoResource);
}
else
{
Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
}
}
/* File was obviously modified */
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
/* And if we increased it, modify size in Cc and update FO */
if (FileSizeChanged)
{
(*CcGetFileSizePointer(FileObject)).QuadPart = LastOffset.QuadPart;
SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
}
/* Update offset */
FileObject->CurrentByteOffset.QuadPart = WriteOffset.QuadPart + Length;
}
else
{
/* We failed, we need to restore previous sizes */
if (FileSizeChanged)
{
if (Fcb->PagingIoResource != NULL)
{
ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
ExReleaseResourceLite(Fcb->PagingIoResource);
}
else
{
Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
}
}
}
}
else
{
BOOLEAN AboveFour;
WriteOffset.HighPart = 0;
LastOffset.HighPart = 0;
/* If we're to extend the file, then, acquire exclusively
* Here, easy stuff, we know we can wait, no return to check!
*/
if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
{
ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
}
/* Otherwise, a shared lock is enough */
else
{
ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
AcquiredShared = TRUE;
}
/* Get first write offset, and last
* Also check whether our writing will bring us
* beyond the 4GB
*/
if (WriteToEof)
{
WriteOffset.LowPart = Fcb->FileSize.LowPart;
LastOffset.LowPart = WriteOffset.LowPart + Length;
AboveFour = (LastOffset.LowPart < Fcb->FileSize.LowPart);
}
else
{
WriteOffset.LowPart = FileOffset->LowPart;
LastOffset.LowPart = WriteOffset.LowPart + Length;
AboveFour = (LastOffset.LowPart < FileOffset->LowPart) ||
(FileOffset->HighPart != 0);
}
/* If cache wasn't initialized, fail */
if (FileObject->PrivateCacheMap == NULL ||
Fcb->IsFastIoPossible == FastIoIsNotPossible)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* If we're to write beyond allocation size, it's no go,
* same is we create a hole bigger than 8kb
* same if we end writing beyond 4GB
*/
if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
(WriteOffset.LowPart >= Fcb->ValidDataLength.LowPart + 0x2000) ||
AboveFour)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* If we have to extend the VDL, shared lock isn't enough */
if (AcquiredShared && LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
{
/* So release, and acquire exclusively */
ExReleaseResourceLite(Fcb->Resource);
ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
/* Get again EOF, in case file size changed in between and
* recheck we won't go beyond 4GB
*/
if (WriteToEof)
{
WriteOffset.LowPart = Fcb->FileSize.LowPart;
LastOffset.LowPart = WriteOffset.LowPart + Length;
AboveFour = (LastOffset.LowPart < Fcb->FileSize.LowPart);
}
/* Make sure caching is still enabled */
if (FileObject->PrivateCacheMap == NULL ||
Fcb->IsFastIoPossible == FastIoIsNotPossible)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
/* And that we're not writting beyond allocation size
* and that we're not going above 4GB
*/
if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
(Fcb->AllocationSize.HighPart != 0) || AboveFour)
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
}
/* If FastIO is questionable, then question */
if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
{
PFAST_IO_DISPATCH FastIoDispatch;
PDEVICE_OBJECT RelatedDeviceObject;
RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
ASSERT(FastIoDispatch != NULL);
ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
&WriteOffset,
Length, Wait, LockKey,
FALSE, &LocalIoStatus,
RelatedDeviceObject))
{
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return FALSE;
}
}
/* If we write beyond EOF, then, save previous sizes (in case of failure)
* and update file size, to allow writing
*/
if (LastOffset.LowPart > Fcb->FileSize.LowPart)
{
FileSizeChanged = TRUE;
InitialFileSize.LowPart = Fcb->FileSize.LowPart;
InitialValidDataLength.LowPart = Fcb->ValidDataLength.LowPart;
Fcb->FileSize.LowPart = LastOffset.LowPart;
}
/* Set caller provided context as top level IRP */
IoSetTopLevelIrp(TopLevelContext);
Ret = TRUE;
/* And perform the writing */
_SEH2_TRY
{
/* Check whether we've to create a hole first -
* it cannot fail, we can wait
*/
if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
{
CcZeroData(FileObject, &Fcb->ValidDataLength, &WriteOffset, TRUE);
}
/* Write data */
CcFastCopyWrite(FileObject, WriteOffset.LowPart, Length, Buffer);
}
_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
Ret = FALSE;
}
_SEH2_END;
/* Restore top level IRP */
IoSetTopLevelIrp(NULL);
/* If writing succeed */
if (Ret)
{
/* If we wrote beyond VDL, update it */
if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
{
Fcb->ValidDataLength.LowPart = LastOffset.LowPart;
}
/* File was obviously modified */
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
/* And if we increased it, modify size in Cc and update FO */
if (FileSizeChanged)
{
(*CcGetFileSizePointer(FileObject)).LowPart = LastOffset.LowPart;
SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
}
/* Update offset - we're still below 4GB, so high part must be 0 */
FileObject->CurrentByteOffset.LowPart = WriteOffset.LowPart + Length;
FileObject->CurrentByteOffset.HighPart = 0;
}
else
{
/* We failed, we need to restore previous sizes */
if (FileSizeChanged)
{
if (Fcb->PagingIoResource != NULL)
{
ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
Fcb->FileSize.LowPart = InitialFileSize.LowPart;
Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
ExReleaseResourceLite(Fcb->PagingIoResource);
}
else
{
Fcb->FileSize.LowPart = InitialFileSize.LowPart;
Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
}
}
}
}
/* Release our resource and leave */
ExReleaseResourceLite(Fcb->Resource);
FsRtlExitFileSystem();
return Ret;
}