reactos/sdk/lib/drivers/rdbsslib/rdbss.c

9446 lines
273 KiB
C
Raw Normal View History

/*
* 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/rdbsslib/rdbss.c
* PURPOSE: RDBSS library
* PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <rx.h>
#include <pseh/pseh2.h>
#include <limits.h>
#include <dfs.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
#include <copysup.h>
#define NDEBUG
#include <debug.h>
#define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
typedef
NTSTATUS
(NTAPI *PRX_FSD_DISPATCH) (
PRX_CONTEXT Context);
typedef struct _RX_FSD_DISPATCH_VECTOR
{
PRX_FSD_DISPATCH CommonRoutine;
} RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
VOID
NTAPI
RxAcquireFileForNtCreateSection(
PFILE_OBJECT FileObject);
NTSTATUS
NTAPI
RxAcquireForCcFlush(
PFILE_OBJECT FileObject,
PDEVICE_OBJECT DeviceObject);
VOID
RxAddToTopLevelIrpAllocatedContextsList(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
VOID
RxAssert(
PVOID Assert,
PVOID File,
ULONG Line,
PVOID Message);
NTSTATUS
NTAPI
RxCommonCleanup(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonClose(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonCreate(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDevFCBCleanup(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDevFCBClose(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDevFCBFsCtl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDevFCBIoCtl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDevFCBQueryVolInfo(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDeviceControl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDirectoryControl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonDispatchProblem(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonFileSystemControl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonFlushBuffers(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonLockControl(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonQueryEa(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonQueryInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonQueryQuotaInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonQuerySecurity(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonQueryVolumeInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonRead(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonSetEa(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonSetInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonSetQuotaInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonSetSecurity(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonSetVolumeInformation(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonUnimplemented(
PRX_CONTEXT Context);
NTSTATUS
NTAPI
RxCommonWrite(
PRX_CONTEXT Context);
VOID
RxCopyCreateParameters(
IN PRX_CONTEXT RxContext);
NTSTATUS
RxCreateFromNetRoot(
PRX_CONTEXT Context,
PUNICODE_STRING NetRootName);
NTSTATUS
RxCreateTreeConnect(
IN PRX_CONTEXT RxContext);
BOOLEAN
NTAPI
RxFastIoCheckIfPossible(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length, BOOLEAN Wait,
ULONG LockKey, BOOLEAN CheckForReadOperation,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject);
BOOLEAN
NTAPI
RxFastIoDeviceControl(
PFILE_OBJECT FileObject,
BOOLEAN Wait,
PVOID InputBuffer OPTIONAL,
ULONG InputBufferLength,
PVOID OutputBuffer OPTIONAL,
ULONG OutputBufferLength,
ULONG IoControlCode,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject);
BOOLEAN
NTAPI
RxFastIoRead(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length,
BOOLEAN Wait,
ULONG LockKey,
PVOID Buffer,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject);
BOOLEAN
NTAPI
RxFastIoWrite(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length,
BOOLEAN Wait,
ULONG LockKey,
PVOID Buffer,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject);
NTSTATUS
RxFindOrCreateFcb(
PRX_CONTEXT RxContext,
PUNICODE_STRING NetRootName);
NTSTATUS
RxFirstCanonicalize(
PRX_CONTEXT RxContext,
PUNICODE_STRING FileName,
PUNICODE_STRING CanonicalName,
PNET_ROOT_TYPE NetRootType);
VOID
RxFreeCanonicalNameBuffer(
PRX_CONTEXT Context);
VOID
NTAPI
RxFspDispatch(
IN PVOID Context);
VOID
NTAPI
RxGetRegistryParameters(
IN PUNICODE_STRING RegistryPath);
NTSTATUS
NTAPI
RxGetStringRegistryParameter(
IN HANDLE KeyHandle,
IN PCWSTR KeyName,
OUT PUNICODE_STRING OutString,
IN PUCHAR Buffer,
IN ULONG BufferLength,
IN BOOLEAN LogFailure);
VOID
NTAPI
RxInitializeDebugSupport(
VOID);
VOID
NTAPI
RxInitializeDispatchVectors(
PDRIVER_OBJECT DriverObject);
NTSTATUS
NTAPI
RxInitializeRegistrationStructures(
VOID);
VOID
NTAPI
RxInitializeTopLevelIrpPackage(
VOID);
VOID
NTAPI
RxInitUnwind(
PDRIVER_OBJECT DriverObject,
USHORT State);
BOOLEAN
RxIsThisAnRdbssTopLevelContext(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
NTSTATUS
NTAPI
RxLowIoIoCtlShellCompletion(
PRX_CONTEXT RxContext);
NTSTATUS
RxLowIoReadShell(
PRX_CONTEXT RxContext);
NTSTATUS
NTAPI
RxLowIoReadShellCompletion(
PRX_CONTEXT RxContext);
NTSTATUS
RxLowIoWriteShell(
IN PRX_CONTEXT RxContext);
NTSTATUS
NTAPI
RxLowIoWriteShellCompletion(
PRX_CONTEXT RxContext);
PVOID
RxNewMapUserBuffer(
PRX_CONTEXT RxContext);
NTSTATUS
RxNotifyChangeDirectory(
PRX_CONTEXT RxContext);
NTSTATUS
RxpQueryInfoMiniRdr(
PRX_CONTEXT RxContext,
FILE_INFORMATION_CLASS FileInfoClass,
PVOID Buffer);
[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
VOID
RxPurgeNetFcb(
PFCB Fcb,
PRX_CONTEXT LocalContext);
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
PFILE_NAME_INFORMATION AltNameInfo);
NTSTATUS
RxQueryBasicInfo(
PRX_CONTEXT RxContext,
PFILE_BASIC_INFORMATION BasicInfo);
NTSTATUS
RxQueryCompressedInfo(
PRX_CONTEXT RxContext,
PFILE_COMPRESSION_INFORMATION CompressionInfo);
NTSTATUS
RxQueryDirectory(
PRX_CONTEXT RxContext);
NTSTATUS
RxQueryEaInfo(
PRX_CONTEXT RxContext,
PFILE_EA_INFORMATION EaInfo);
NTSTATUS
RxQueryInternalInfo(
PRX_CONTEXT RxContext,
PFILE_INTERNAL_INFORMATION InternalInfo);
NTSTATUS
RxQueryNameInfo(
PRX_CONTEXT RxContext,
PFILE_NAME_INFORMATION NameInfo);
NTSTATUS
RxQueryPipeInfo(
PRX_CONTEXT RxContext,
PFILE_PIPE_INFORMATION PipeInfo);
NTSTATUS
RxQueryPositionInfo(
PRX_CONTEXT RxContext,
PFILE_POSITION_INFORMATION PositionInfo);
NTSTATUS
RxQueryStandardInfo(
PRX_CONTEXT RxContext,
PFILE_STANDARD_INFORMATION StandardInfo);
VOID
NTAPI
RxReadRegistryParameters(
VOID);
VOID
NTAPI
RxReleaseFileForNtCreateSection(
PFILE_OBJECT FileObject);
NTSTATUS
NTAPI
RxReleaseForCcFlush(
PFILE_OBJECT FileObject,
PDEVICE_OBJECT DeviceObject);
PRX_CONTEXT
RxRemoveOverflowEntry(
PRDBSS_DEVICE_OBJECT DeviceObject,
WORK_QUEUE_TYPE Queue);
NTSTATUS
RxSearchForCollapsibleOpen(
PRX_CONTEXT RxContext,
ACCESS_MASK DesiredAccess,
ULONG ShareAccess);
NTSTATUS
RxSetAllocationInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetBasicInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetDispositionInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetEndOfFileInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetPipeInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetPositionInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetRenameInfo(
PRX_CONTEXT RxContext);
NTSTATUS
RxSetSimpleInfo(
PRX_CONTEXT RxContext);
VOID
RxSetupNetFileObject(
PRX_CONTEXT RxContext);
NTSTATUS
RxSystemControl(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN PIRP Irp);
VOID
RxUninitializeCacheMap(
PRX_CONTEXT RxContext,
PFILE_OBJECT FileObject,
PLARGE_INTEGER TruncateSize);
VOID
RxUnstart(
PRX_CONTEXT Context,
PRDBSS_DEVICE_OBJECT DeviceObject);
NTSTATUS
RxXXXControlFileCallthru(
PRX_CONTEXT Context);
PVOID
NTAPI
_RxAllocatePoolWithTag(
_In_ POOL_TYPE PoolType,
_In_ SIZE_T NumberOfBytes,
_In_ ULONG Tag);
VOID
NTAPI
_RxFreePool(
_In_ PVOID Buffer);
VOID
NTAPI
_RxFreePoolWithTag(
_In_ PVOID Buffer,
_In_ ULONG Tag);
WCHAR RxStarForTemplate = '*';
WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
BOOLEAN DisableFlushOnCleanup = FALSE;
ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;
LIST_ENTRY RxActiveContexts;
NPAGED_LOOKASIDE_LIST RxContextLookasideList;
FAST_MUTEX RxContextPerFileSerializationMutex;
RDBSS_DATA RxData;
FCB RxDeviceFCB;
BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
{
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDevFCBClose },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDevFCBQueryVolInfo },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDevFCBFsCtl },
{ RxCommonDevFCBIoCtl },
{ RxCommonDevFCBIoCtl },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDevFCBCleanup },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonDispatchProblem },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
};
RDBSS_EXPORTS RxExports;
FAST_IO_DISPATCH RxFastIoDispatch;
PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
{
{ RxCommonCreate },
{ RxCommonUnimplemented },
{ RxCommonClose },
{ RxCommonRead },
{ RxCommonWrite },
{ RxCommonQueryInformation },
{ RxCommonSetInformation },
{ RxCommonQueryEa },
{ RxCommonSetEa },
{ RxCommonFlushBuffers },
{ RxCommonQueryVolumeInformation },
{ RxCommonSetVolumeInformation },
{ RxCommonDirectoryControl },
{ RxCommonFileSystemControl },
{ RxCommonDeviceControl },
{ RxCommonDeviceControl },
{ RxCommonUnimplemented },
{ RxCommonLockControl },
{ RxCommonCleanup },
{ RxCommonUnimplemented },
{ RxCommonQuerySecurity },
{ RxCommonSetSecurity },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonUnimplemented },
{ RxCommonQueryQuotaInformation },
{ RxCommonSetQuotaInformation },
{ RxCommonUnimplemented },
};
ULONG RxFsdEntryCount;
LIST_ENTRY RxIrpsList;
KSPIN_LOCK RxIrpsListSpinLock;
KMUTEX RxScavengerMutex;
KMUTEX RxSerializationMutex;
UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
KSPIN_LOCK TopLevelIrpSpinLock;
LIST_ENTRY TopLevelIrpAllocatedContextsList;
BOOLEAN RxForceQFIPassThrough = FALSE;
BOOLEAN RxNoAsync = FALSE;
DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
#if RDBSS_ASSERTS
#ifdef ASSERT
#undef ASSERT
#endif
#define ASSERT(exp) \
if (!(exp)) \
{ \
RxAssert(#exp, __FILE__, __LINE__, NULL); \
}
#endif
#if RX_POOL_WRAPPER
#undef RxAllocatePool
#undef RxAllocatePoolWithTag
#undef RxFreePool
#define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
#define RxAllocatePoolWithTag _RxAllocatePoolWithTag
#define RxFreePool _RxFreePool
#define RxFreePoolWithTag _RxFreePoolWithTag
#endif
/* FUNCTIONS ****************************************************************/
/*
* @implemented
*/
VOID
CheckForLoudOperations(
PRX_CONTEXT RxContext)
{
RxCaptureFcb;
PAGED_CODE();
#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
/* Are loud operations enabled? */
if (RxLoudLowIoOpsEnabled)
{
/* If so, the operation will be loud only if filename ends with all.scr */
if (RtlCompareMemory(Add2Ptr(capFcb->PrivateAlreadyPrefixedName.Buffer,
(capFcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
{
SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
}
}
#undef ALLSCR_LENGTH
}
/*
* @implemented
*/
VOID
__RxInitializeTopLevelIrpContext(
IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
IN PIRP Irp,
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN ULONG Flags)
{
DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
TopLevelContext->Irp = Irp;
TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
TopLevelContext->RxDeviceObject = RxDeviceObject;
TopLevelContext->Previous = IoGetTopLevelIrp();
TopLevelContext->Thread = PsGetCurrentThread();
/* We cannot add to list something that'd come from stack */
if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
{
RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext);
}
}
/*
* @implemented
*/
VOID
__RxWriteReleaseResources(
PRX_CONTEXT RxContext,
BOOLEAN ResourceOwnerSet,
ULONG LineNumber,
PCSTR FileName,
ULONG SerialNumber)
{
RxCaptureFcb;
PAGED_CODE();
ASSERT(RxContext != NULL);
ASSERT(capFcb != NULL);
/* If FCB resource was acquired, release it */
if (RxContext->FcbResourceAcquired)
{
/* Taking care of owner */
if (ResourceOwnerSet)
{
RxReleaseFcbForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId);
}
else
{
RxReleaseFcb(RxContext, capFcb);
}
RxContext->FcbResourceAcquired = FALSE;
}
/* If FCB paging resource was acquired, release it */
if (RxContext->FcbPagingIoResourceAcquired)
{
/* Taking care of owner */
if (ResourceOwnerSet)
{
RxReleasePagingIoResourceForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId);
}
else
{
RxReleasePagingIoResource(RxContext, capFcb);
}
/* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
}
}
/*
* @implemented
*/
VOID
RxAddToTopLevelIrpAllocatedContextsList(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
{
KIRQL OldIrql;
DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
}
/*
* @implemented
*/
VOID
NTAPI
RxAddToWorkque(
IN PRX_CONTEXT RxContext,
IN PIRP Irp)
{
ULONG Queued;
KIRQL OldIrql;
WORK_QUEUE_TYPE Queue;
2017-11-01 14:12:08 +00:00
RxCaptureParamBlock;
RxContext->PostRequest = FALSE;
/* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
capPARAMS->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
{
Queue = DelayedWorkQueue;
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
}
else
{
Queue = CriticalWorkQueue;
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
}
/* Check for overflow */
if (capPARAMS->FileObject != NULL)
{
KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
/* In case of an overflow, add the new queued call to the overflow list */
if (Queued > 1)
{
InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
return;
}
KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
}
ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
}
/*
* @implemented
*/
VOID
RxAdjustFileTimesAndSize(
PRX_CONTEXT RxContext)
{
NTSTATUS Status;
LARGE_INTEGER CurrentTime;
FILE_BASIC_INFORMATION FileBasicInfo;
FILE_END_OF_FILE_INFORMATION FileEOFInfo;
BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
RxCaptureFcb;
RxCaptureFobx;
RxCaptureParamBlock;
RxCaptureFileObject;
PAGED_CODE();
/* If Cc isn't initialized, the file was not read nor written, nothing to do */
if (capFileObject->PrivateCacheMap == NULL)
{
return;
}
/* Get now */
KeQuerySystemTime(&CurrentTime);
/* Was the file modified? */
FileModified = BooleanFlagOn(capFileObject->Flags, FO_FILE_MODIFIED);
/* We'll set last write if it was modified and user didn't update yet */
SetLastWrite = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
/* File was accessed if: written or read (fastio), we'll update last access if user didn't */
SetLastAccess = SetLastWrite ||
(BooleanFlagOn(capFileObject->Flags, FO_FILE_FAST_IO_READ) &&
!BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
/* We'll set last change if it was modified and user didn't update yet */
SetLastChange = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
/* Nothing to update? Job done */
if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
{
return;
}
/* By default, we won't issue any MRxSetFileInfoAtCleanup call */
NeedUpdate = FALSE;
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
/* Update lastwrite time if required */
if (SetLastWrite)
{
NeedUpdate = TRUE;
capFcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
}
/* Update lastaccess time if required */
if (SetLastAccess)
{
NeedUpdate = TRUE;
capFcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
}
/* Update lastchange time if required */
if (SetLastChange)
{
NeedUpdate = TRUE;
capFcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
}
/* If one of the date was modified, issue a call to mini-rdr */
if (NeedUpdate)
{
RxContext->Info.FileInformationClass = FileBasicInformation;
RxContext->Info.Buffer = &FileBasicInfo;
RxContext->Info.Length = sizeof(FileBasicInfo);
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
(void)Status;
}
/* If the file was modified, update its EOF */
if (FileModified)
{
FileEOFInfo.EndOfFile.QuadPart = capFcb->Header.FileSize.QuadPart;
RxContext->Info.FileInformationClass = FileEndOfFileInformation;
RxContext->Info.Buffer = &FileEOFInfo;
RxContext->Info.Length = sizeof(FileEOFInfo);
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
(void)Status;
}
}
/*
* @implemented
*/
NTSTATUS
RxAllocateCanonicalNameBuffer(
PRX_CONTEXT RxContext,
PUNICODE_STRING CanonicalName,
USHORT CanonicalLength)
{
PAGED_CODE();
DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
/* Context must be free of any already allocated name */
ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
/* Validate string length */
if (CanonicalLength > USHRT_MAX - 1)
{
CanonicalName->Buffer = NULL;
return STATUS_OBJECT_PATH_INVALID;
}
CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
if (CanonicalName->Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
CanonicalName->Length = 0;
CanonicalName->MaximumLength = CanonicalLength;
/* Set the two places - they must always be identical */
RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
[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
VOID
RxCancelNotifyChangeDirectoryRequestsForFobx(
PFOBX Fobx)
{
KIRQL OldIrql;
PLIST_ENTRY Entry;
PRX_CONTEXT Context;
LIST_ENTRY ContextsToCancel;
/* Init a list for the contexts to cancel */
InitializeListHead(&ContextsToCancel);
/* Lock our list lock */
KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Now, browse all the active contexts, to find the associated ones */
Entry = RxActiveContexts.Flink;
while (Entry != &RxActiveContexts)
{
Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
Entry = Entry->Flink;
/* Not the IRP we're looking for, ignore */
if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
{
continue;
}
/* Not the FOBX we're looking for, ignore */
if ((PFOBX)Context->pFobx != Fobx)
{
continue;
}
/* No cancel routine (can't be cancel, then), ignore */
if (Context->MRxCancelRoutine == NULL)
{
continue;
}
/* Mark our context as cancelled */
SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
/* Move it to our list */
RemoveEntryList(&Context->ContextListEntry);
InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
InterlockedIncrement((volatile long *)&Context->ReferenceCount);
}
/* Done with the contexts */
KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
/* Now, handle all our "extracted" contexts */
while (!IsListEmpty(&ContextsToCancel))
{
Entry = RemoveHeadList(&ContextsToCancel);
Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
/* If they had an associated IRP (should be always true) */
if (Context->CurrentIrp != NULL)
{
/* Then, call cancel routine */
ASSERT(Context->MRxCancelRoutine != NULL);
DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
Context->MRxCancelRoutine(Context);
}
/* And delete the context */
RxDereferenceAndDeleteRxContext(Context);
}
[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
}
/*
* @implemented
*/
NTSTATUS
RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
PV_NET_ROOT VNetRoot,
BOOLEAN ForceFilesClosed)
{
KIRQL OldIrql;
NTSTATUS Status;
PLIST_ENTRY Entry;
PRX_CONTEXT Context;
LIST_ENTRY ContextsToCancel;
/* Init a list for the contexts to cancel */
InitializeListHead(&ContextsToCancel);
/* Lock our list lock */
KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Assume success */
Status = STATUS_SUCCESS;
/* Now, browse all the active contexts, to find the associated ones */
Entry = RxActiveContexts.Flink;
while (Entry != &RxActiveContexts)
{
Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
Entry = Entry->Flink;
/* Not the IRP we're looking for, ignore */
if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
{
continue;
}
/* Not the VNetRoot we're looking for, ignore */
if (Context->pFcb == NULL ||
(PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
{
continue;
}
/* No cancel routine (can't be cancel, then), ignore */
if (Context->MRxCancelRoutine == NULL)
{
continue;
}
/* At that point, we found a matching context
* If we're not asked to force close, then fail - it's still open
*/
if (!ForceFilesClosed)
{
Status = STATUS_FILES_OPEN;
break;
}
/* Mark our context as cancelled */
SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
/* Move it to our list */
RemoveEntryList(&Context->ContextListEntry);
InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
InterlockedIncrement((volatile long *)&Context->ReferenceCount);
}
/* Done with the contexts */
KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
if (Status != STATUS_SUCCESS)
{
return Status;
}
/* Now, handle all our "extracted" contexts */
while (!IsListEmpty(&ContextsToCancel))
{
Entry = RemoveHeadList(&ContextsToCancel);
Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
/* If they had an associated IRP (should be always true) */
if (Context->CurrentIrp != NULL)
{
/* Then, call cancel routine */
ASSERT(Context->MRxCancelRoutine != NULL);
DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
Context->MRxCancelRoutine(Context);
}
/* And delete the context */
RxDereferenceAndDeleteRxContext(Context);
}
return Status;
}
VOID
NTAPI
RxCancelRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxCanonicalizeFileNameByServerSpecs(
PRX_CONTEXT RxContext,
PUNICODE_STRING NetRootName)
{
USHORT NextChar, CurChar;
USHORT MaxChars;
PAGED_CODE();
/* Validate file name is not empty */
MaxChars = NetRootName->Length / sizeof(WCHAR);
if (MaxChars == 0)
{
return STATUS_MORE_PROCESSING_REQUIRED;
}
/* Validate name is correct */
for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
{
USHORT i;
for (i = NextChar + 1; i < MaxChars; ++i)
{
if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
{
break;
}
}
CurChar = i - 1;
if (CurChar == NextChar)
{
if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
{
continue;
}
if (CurChar != 0)
{
if (CurChar >= MaxChars - 1)
{
continue;
}
if (NetRootName->Buffer[CurChar + 1] != ':')
{
return STATUS_OBJECT_PATH_SYNTAX_BAD;
}
}
else
{
if (NetRootName->Buffer[1] != ':')
{
return STATUS_OBJECT_PATH_SYNTAX_BAD;
}
}
}
else
{
if ((CurChar - NextChar) == 1)
{
if (NetRootName->Buffer[NextChar + 2] != '.')
{
continue;
}
if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
{
return STATUS_OBJECT_PATH_SYNTAX_BAD;
}
}
else
{
if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
|| NetRootName->Buffer[NextChar + 1] != '.')
{
continue;
}
if (NetRootName->Buffer[NextChar + 2] == '.')
{
return STATUS_OBJECT_PATH_SYNTAX_BAD;
}
}
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
RxCanonicalizeNameAndObtainNetRoot(
PRX_CONTEXT RxContext,
PUNICODE_STRING FileName,
PUNICODE_STRING NetRootName)
{
NTSTATUS Status;
NET_ROOT_TYPE NetRootType;
UNICODE_STRING CanonicalName;
2017-11-01 14:12:08 +00:00
RxCaptureParamBlock;
RxCaptureFileObject;
PAGED_CODE();
NetRootType = NET_ROOT_WILD;
RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
/* if not relative opening, just handle the passed name */
2017-11-01 14:12:08 +00:00
if (capFileObject->RelatedFileObject == NULL)
{
Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
else
{
PFCB Fcb;
/* Make sure we have a valid FCB and a FOBX */
2017-11-01 14:12:08 +00:00
Fcb = capFileObject->RelatedFileObject->FsContext;
if (Fcb == NULL || capFileObject->RelatedFileObject->FsContext2 == NULL)
{
return STATUS_INVALID_PARAMETER;
}
if (!NodeTypeIsFcb(Fcb))
{
return STATUS_INVALID_PARAMETER;
}
UNIMPLEMENTED;
}
/* Get/Create the associated VNetRoot for opening */
Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
{
ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
RxFreeCanonicalNameBuffer(RxContext);
Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
if (NT_SUCCESS(Status))
{
Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
}
}
/* Filename cannot contain wildcards */
if (FsRtlDoesNameContainWildCards(NetRootName))
{
Status = STATUS_OBJECT_NAME_INVALID;
}
/* Make sure file name is correct */
if (NT_SUCCESS(Status))
{
Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
}
/* Give the mini-redirector a chance to prepare the name */
if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
{
if (RxContext->Create.pNetRoot != NULL)
{
NTSTATUS IgnoredStatus;
MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
MRxPreparseName, (RxContext, NetRootName));
(void)IgnoredStatus;
}
}
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
RxCheckFcbStructuresForAlignment(
VOID)
{
PAGED_CODE();
}
#if DBG
NTSTATUS
RxCheckShareAccess(
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG DesiredShareAccess,
_Inout_ PFILE_OBJECT FileObject,
_Inout_ PSHARE_ACCESS ShareAccess,
_In_ BOOLEAN Update,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
PAGED_CODE();
RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
}
#endif
/*
* @implemented
*/
NTSTATUS
RxCheckShareAccessPerSrvOpens(
IN PFCB Fcb,
IN ACCESS_MASK DesiredAccess,
IN ULONG DesiredShareAccess)
{
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
PSHARE_ACCESS ShareAccess;
PAGED_CODE();
ShareAccess = &Fcb->ShareAccessPerSrvOpens;
RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
/* Check if any access wanted */
ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
DeleteAccess = (DesiredAccess & DELETE) != 0;
if (ReadAccess || WriteAccess || DeleteAccess)
{
BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
/* Check whether there's a violation */
if ((ReadAccess &&
(ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
(WriteAccess &&
(ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
(DeleteAccess &&
(ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
((ShareAccess->Readers != 0) && !SharedRead) ||
((ShareAccess->Writers != 0) && !SharedWrite) ||
((ShareAccess->Deleters != 0) && !SharedDelete))
{
return STATUS_SHARING_VIOLATION;
}
}
return STATUS_SUCCESS;
}
VOID
RxCleanupPipeQueues(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
}
[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
/*
* @implemented
*/
NTSTATUS
RxCloseAssociatedSrvOpen(
IN PFOBX Fobx,
IN PRX_CONTEXT RxContext OPTIONAL)
{
[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
PFCB Fcb;
NTSTATUS Status;
PSRV_OPEN SrvOpen;
BOOLEAN CloseSrvOpen;
PRX_CONTEXT LocalContext;
PAGED_CODE();
/* Assume SRV_OPEN is already closed */
CloseSrvOpen = FALSE;
/* If we have a FOBX, we'll have to close it */
if (Fobx != NULL)
{
/* If the FOBX isn't closed yet */
if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
{
SrvOpen = Fobx->SrvOpen;
Fcb = (PFCB)SrvOpen->pFcb;
/* Check whether we've to close SRV_OPEN first */
if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
{
CloseSrvOpen = TRUE;
}
else
{
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Not much to do */
SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
if (SrvOpen->OpenCount > 0)
{
--SrvOpen->OpenCount;
}
}
}
/* No need to close SRV_OPEN, so close FOBX */
if (!CloseSrvOpen)
{
RxMarkFobxOnClose(Fobx);
return STATUS_SUCCESS;
}
}
else
{
/* No FOBX? No RX_CONTEXT, ok, job done! */
if (RxContext == NULL)
{
return STATUS_SUCCESS;
}
/* Get the FCB from RX_CONTEXT */
Fcb = (PFCB)RxContext->pFcb;
SrvOpen = NULL;
[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
}
/* If we don't have RX_CONTEXT, allocte one, we'll need it */
if (RxContext == NULL)
{
ASSERT(Fobx != NULL);
LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
if (LocalContext == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
LocalContext->MajorFunction = 2;
LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
LocalContext->pFobx = (PMRX_FOBX)Fobx;
LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
}
else
{
LocalContext = RxContext;
}
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Now, close the FOBX */
if (Fobx != NULL)
{
RxMarkFobxOnClose(Fobx);
}
else
{
InterlockedDecrement((volatile long *)&Fcb->OpenCount);
}
/* If not a "standard" file, SRV_OPEN can be null */
if (SrvOpen == NULL)
{
ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
RxDereferenceNetFcb(Fcb);
if (LocalContext != RxContext)
{
RxDereferenceAndDeleteRxContext(LocalContext);
}
return STATUS_SUCCESS;
}
/* If SRV_OPEN isn't in a good condition, nothing to close */
if (SrvOpen->Condition != Condition_Good)
{
if (LocalContext != RxContext)
{
RxDereferenceAndDeleteRxContext(LocalContext);
}
return STATUS_SUCCESS;
}
/* Decrease open count */
if (SrvOpen->OpenCount > 0)
{
--SrvOpen->OpenCount;
}
/* If we're the only one left, is there a FOBX handled by Scavenger? */
if (SrvOpen->OpenCount == 1)
{
if (!IsListEmpty(&SrvOpen->FobxList))
{
if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
{
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
}
}
}
/* Nothing left, purge FCB */
if (SrvOpen->OpenCount == 0 && RxContext == NULL)
{
RxPurgeNetFcb(Fcb, LocalContext);
}
/* Already closed? Job done! */
SrvOpen = Fobx->SrvOpen;
if (SrvOpen == NULL ||
(SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
{
SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
if (LocalContext != RxContext)
{
RxDereferenceAndDeleteRxContext(LocalContext);
}
return STATUS_SUCCESS;
[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
}
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
/* Inform mini-rdr about closing */
MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
Status, RxContext, Fobx, Fcb, SrvOpen);
/* And mark as such */
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
SrvOpen->Key = (PVOID)-1;
/* If we were delayed, we're not! */
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
{
InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
}
/* Clear access */
RxRemoveShareAccessPerSrvOpens(SrvOpen);
RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
/* Dereference */
RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
/* Mark the FOBX closed as well */
SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
if (LocalContext != RxContext)
{
RxDereferenceAndDeleteRxContext(LocalContext);
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxCollapseOrCreateSrvOpen(
PRX_CONTEXT RxContext)
{
NTSTATUS Status;
ULONG Disposition;
PSRV_OPEN SrvOpen;
USHORT ShareAccess;
ACCESS_MASK DesiredAccess;
RX_BLOCK_CONDITION FcbCondition;
2017-11-01 14:12:08 +00:00
RxCaptureFcb;
RxCaptureParamBlock;
PAGED_CODE();
DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
2017-11-01 14:12:08 +00:00
ASSERT(RxIsFcbAcquiredExclusive(capFcb));
++capFcb->UncleanCount;
2017-11-01 14:12:08 +00:00
DesiredAccess = capPARAMS->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
ShareAccess = capPARAMS->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
Disposition = RxContext->Create.NtCreateParameters.Disposition;
/* Try to find a reusable SRV_OPEN */
Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
if (Status == STATUS_NOT_FOUND)
{
/* If none found, create one */
2017-11-01 14:12:08 +00:00
SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, capFcb);
if (SrvOpen == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
SrvOpen->DesiredAccess = DesiredAccess;
SrvOpen->ShareAccess = ShareAccess;
Status = STATUS_SUCCESS;
}
RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
if (Status != STATUS_SUCCESS)
{
FcbCondition = Condition_Bad;
}
else
{
RxInitiateSrvOpenKeyAssociation(SrvOpen);
/* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
/* Inform the mini-rdr we're handling a create */
2017-11-01 14:12:08 +00:00
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCreate, (RxContext));
ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
DPRINT("MRxCreate returned: %x\n", Status);
if (Status == STATUS_SUCCESS)
{
/* In case of overwrite, reset file size */
if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
{
2017-11-01 14:12:08 +00:00
RxAcquirePagingIoResource(RxContext, capFcb);
capFcb->Header.AllocationSize.QuadPart = 0LL;
capFcb->Header.FileSize.QuadPart = 0LL;
capFcb->Header.ValidDataLength.QuadPart = 0LL;
RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
RxReleasePagingIoResource(RxContext, capFcb);
}
else
{
/* Otherwise, adjust sizes */
2017-11-01 14:12:08 +00:00
RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
{
2017-11-01 14:12:08 +00:00
RxAdjustAllocationSizeforCC(capFcb);
}
2017-11-01 14:12:08 +00:00
CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
}
}
/* Set the IoStatus with information returned by mini-rdr */
RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
SrvOpen->OpenStatus = Status;
/* Set SRV_OPEN state - good or bad - depending on whether create succeed */
RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
2017-11-01 14:12:08 +00:00
ASSERT(RxIsFcbAcquiredExclusive(capFcb));
RxCompleteSrvOpenKeyAssociation(SrvOpen);
if (Status == STATUS_SUCCESS)
{
2017-11-01 14:12:08 +00:00
if (BooleanFlagOn(capPARAMS->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
{
2017-11-01 14:12:08 +00:00
ClearFlag(capFcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
}
SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
FcbCondition = Condition_Good;
}
else
{
FcbCondition = Condition_Bad;
RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
RxContext->pRelevantSrvOpen = NULL;
if (RxContext->pFobx != NULL)
{
RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
RxContext->pFobx = NULL;
}
}
}
/* Set FCB state - good or bad - depending on whether create succeed */
2017-11-01 14:12:08 +00:00
DPRINT("Transitioning FCB %p to condition %lx\n", capFcb, capFcb->Condition);
RxTransitionNetFcb(capFcb, FcbCondition);
}
else if (Status == STATUS_SUCCESS)
{
BOOLEAN IsGood, ExtraOpen;
/* A reusable SRV_OPEN was found */
RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
ExtraOpen = FALSE;
SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
IsGood = (SrvOpen->Condition == Condition_Good);
/* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
if (!StableCondition(SrvOpen->Condition))
{
RxReferenceSrvOpen(SrvOpen);
++SrvOpen->OpenCount;
ExtraOpen = TRUE;
2017-11-01 14:12:08 +00:00
RxReleaseFcb(RxContext, capFcb);
RxContext->Create.FcbAcquired = FALSE;
RxWaitForStableSrvOpen(SrvOpen, RxContext);
2017-11-01 14:12:08 +00:00
if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, capFcb)))
{
RxContext->Create.FcbAcquired = TRUE;
}
IsGood = (SrvOpen->Condition == Condition_Good);
}
/* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
if (IsGood)
{
2017-11-01 14:12:08 +00:00
MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCollapseOpen, (RxContext));
2017-11-01 14:12:08 +00:00
ASSERT(RxIsFcbAcquiredExclusive(capFcb));
}
else
{
Status = SrvOpen->OpenStatus;
}
if (ExtraOpen)
{
--SrvOpen->OpenCount;
RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
}
}
2017-11-01 14:12:08 +00:00
--capFcb->UncleanCount;
DPRINT("Status: %x\n", Status);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonCleanup(
PRX_CONTEXT Context)
{
#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
PFCB Fcb;
PFOBX Fobx;
[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
ULONG OpenCount;
NTSTATUS Status;
[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
PNET_ROOT NetRoot;
PFILE_OBJECT FileObject;
LARGE_INTEGER TruncateSize;
PLARGE_INTEGER TruncateSizePtr;
BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
/* File system closing, it's OK */
if (Fobx == NULL)
{
if (Fcb->UncleanCount > 0)
{
InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
}
return STATUS_SUCCESS;
}
/* Check we have a correct FCB type */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
{
DPRINT1("Invalid Fcb type for %p\n", Fcb);
RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
}
FileObject = Context->CurrentIrpSp->FileObject;
ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
RxMarkFobxOnCleanup(Fobx, &NeedPurge);
Status = RxAcquireExclusiveFcb(Context, Fcb);
if (!NT_SUCCESS(Status))
{
return Status;
}
[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
FcbAcquired = TRUE;
Fobx->AssociatedFileObject = NULL;
/* In case it was already orphaned */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
{
ASSERT(Fcb->UncleanCount != 0);
InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
--Fcb->UncachedUncleanCount;
}
/* Inform mini-rdr */
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
--Fobx->SrvOpen->UncleanFobxCount;
RxUninitializeCacheMap(Context, FileObject, NULL);
RxReleaseFcb(Context, Fcb);
return STATUS_SUCCESS;
}
[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
/* Report the fact that file could be set as delete on close */
if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
{
SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
}
/* Cancel any pending notification */
RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
/* Backup open count before we start playing with it */
OpenCount = Fcb->ShareAccess.OpenCount;
NetRoot = (PNET_ROOT)Fcb->pNetRoot;
FcbTableAcquired = FALSE;
LeftForDelete = FALSE;
OneLeft = (Fcb->UncleanCount == 1);
[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
_SEH2_TRY
{
/* Unclean count and delete on close? Verify whether we're the one */
if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
[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
{
if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
{
FcbTableAcquired = TRUE;
}
else
{
RxReleaseFcb(Context, Fcb);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
Status = RxAcquireExclusiveFcb(Context, Fcb);
if (Status != STATUS_SUCCESS)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
return Status;
}
FcbTableAcquired = TRUE;
}
/* That means we'll perform the delete on close! */
[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
if (Fcb->UncleanCount == 1)
{
LeftForDelete = TRUE;
[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
}
else
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
FcbTableAcquired = FALSE;
}
}
IsFile = FALSE;
TruncateSizePtr = NULL;
[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
/* Handle cleanup for pipes and printers */
if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
{
RxCleanupPipeQueues(Context);
[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
}
/* Handle cleanup for files */
else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
{
Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
[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
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
{
/* First, unlock */
FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
/* If there are still locks to release, proceed */
if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
{
RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
Context->LowIoContext.ParamsFor.Locks.Flags = 0;
Status = RxLowIoLockControlShell(Context);
}
/* Fix times and size */
RxAdjustFileTimesAndSize(Context);
/* If we're the only one left... */
if (OneLeft)
{
/* And if we're supposed to delete on close */
if (LeftForDelete)
{
/* Update the sizes */
RxAcquirePagingIoResource(Context, Fcb);
Fcb->Header.FileSize.QuadPart = 0;
Fcb->Header.ValidDataLength.QuadPart = 0;
RxReleasePagingIoResource(Context, Fcb);
}
/* Otherwise, call the mini-rdr to adjust sizes */
else
{
/* File got grown up, fill with zeroes */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
(Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
{
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
}
/* File was truncated, let mini-rdr proceed */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
{
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
/* Keep track of file change for Cc uninit */
TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
TruncateSizePtr = &TruncateSize;
}
}
}
/* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
if (NeedPurge)
{
if (!OneLeft)
{
NeedPurge = FALSE;
}
}
/* Otherwise, try to see whether we can purge */
else
{
NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
}
[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
IsFile = TRUE;
}
}
/* We have to still be there! */
ASSERT(Fcb->UncleanCount != 0);
InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
--Fcb->UncachedUncleanCount;
}
/* Inform mini-rdr about ongoing cleanup */
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
--Fobx->SrvOpen->UncleanFobxCount;
/* Flush cache */
if (DisableFlushOnCleanup)
{
/* Only if we're the last standing */
if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
Fcb->UncleanCount == Fcb->UncachedUncleanCount)
{
DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
[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
RxFlushFcbInSystemCache(Fcb, TRUE);
}
}
else
{
/* Always */
if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
{
DPRINT("Flushing %p on cleanup\n", Context);
[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
RxFlushFcbInSystemCache(Fcb, TRUE);
}
}
/* If only remaining uncached & unclean, then flush and purge */
if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
if (Fcb->UncachedUncleanCount != 0)
{
if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
{
DPRINT("Flushing FCB in system cache for %p\n", Context);
[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
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
}
}
}
/* If purge required, and not about to delete, flush */
if (!LeftForDelete && NeedPurge)
[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
{
DPRINT("Flushing FCB in system cache for %p\n", Context);
[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
RxFlushFcbInSystemCache(Fcb, TRUE);
}
/* If it was a file, drop cache */
if (IsFile)
{
DPRINT("Uninit cache map for file\n");
RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
[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
}
/* If that's the one left for deletion, or if it needs purge, flush */
if (LeftForDelete || NeedPurge)
[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
{
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
/* If that's for deletion, also remove from FCB table */
if (LeftForDelete)
[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
{
RxRemoveNameNetFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable);
FcbTableAcquired = FALSE;
}
}
/* Remove any share access */
if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
{
RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
}
/* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
[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
{
NTSTATUS InternalStatus;
PRX_CONTEXT InternalContext;
/* If we can properly set EOF, there's no need to drop collapsing, try to do it */
InternalStatus = STATUS_UNSUCCESSFUL;
InternalContext = RxCreateRxContext(Context->CurrentIrp,
Fcb->RxDeviceObject,
RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
if (InternalContext != NULL)
{
FILE_END_OF_FILE_INFORMATION FileEOF;
InternalStatus = STATUS_SUCCESS;
/* Initialize the context for file information set */
InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
InternalContext->pFobx = (PMRX_FOBX)Fobx;
InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
/* Get EOF from the FCB */
FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
InternalContext->Info.Buffer = &FileEOF;
InternalContext->Info.Length = sizeof(FileEOF);
/* Call the mini-rdr */
MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
/* We're done */
RxDereferenceAndDeleteRxContext(InternalContext);
}
/* We tried, so, clean the FOBX flag */
ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
/* If it failed, then, disable collapsing on the FCB */
if (!NT_SUCCESS(InternalStatus))
{
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
}
[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
}
/* We're clean! */
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
FcbAcquired = FALSE;
RxReleaseFcb(Context, Fcb);
}
_SEH2_FINALLY
{
if (FcbAcquired)
{
RxReleaseFcb(Context, Fcb);
}
if (FcbTableAcquired)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
}
}
_SEH2_END;
return Status;
#undef BugCheckFileId
}
NTSTATUS
NTAPI
RxCommonClose(
PRX_CONTEXT Context)
{
#define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PFILE_OBJECT FileObject;
BOOLEAN DereferenceFobx, AcquiredFcb;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
FileObject = Context->CurrentIrpSp->FileObject;
DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
Status = RxAcquireExclusiveFcb(Context, Fcb);
if (!NT_SUCCESS(Status))
{
return Status;
}
AcquiredFcb = TRUE;
_SEH2_TRY
{
BOOLEAN Freed;
/* Check our FCB type is expected */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
(NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
(NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
{
RxBugCheck(NodeType(Fcb), 0, 0);
}
RxReferenceNetFcb(Fcb);
DereferenceFobx = FALSE;
/* If we're not closing FS */
if (Fobx != NULL)
{
PSRV_OPEN SrvOpen;
PSRV_CALL SrvCall;
SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
/* Handle delayed close */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
{
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
{
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
{
DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
{
if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
{
InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
}
else
{
DereferenceFobx = TRUE;
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
}
}
}
}
}
/* If we reach maximum of delayed close/or if there are no delayed close */
if (!DereferenceFobx)
{
PNET_ROOT NetRoot;
NetRoot = (PNET_ROOT)Fcb->pNetRoot;
if (NetRoot->Type != NET_ROOT_PRINT)
{
/* Delete if asked */
if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
{
RxScavengeRelatedFobxs(Fcb);
RxSynchronizeWithScavenger(Context);
RxReleaseFcb(Context, Fcb);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
RxOrphanThisFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable);
Status = RxAcquireExclusiveFcb(Context, Fcb);
ASSERT(NT_SUCCESS(Status));
}
}
}
RxMarkFobxOnClose(Fobx);
}
if (DereferenceFobx)
{
ASSERT(Fobx != NULL);
RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
}
else
{
RxCloseAssociatedSrvOpen(Fobx, Context);
if (Fobx != NULL)
{
RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
}
}
Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
AcquiredFcb = !Freed;
FileObject->FsContext = (PVOID)-1;
if (Freed)
{
RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
}
else
{
RxReleaseFcb(Context, Fcb);
AcquiredFcb = FALSE;
}
}
_SEH2_FINALLY
{
if (_SEH2_AbnormalTermination())
{
if (AcquiredFcb)
{
RxReleaseFcb(Context, Fcb);
}
}
else
{
ASSERT(!AcquiredFcb);
}
}
_SEH2_END;
DPRINT("Status: %x\n", Status);
return Status;
#undef BugCheckFileId
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonCreate(
PRX_CONTEXT Context)
{
PIRP Irp;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
DPRINT("RxCommonCreate(%p)\n", Context);
Irp = Context->CurrentIrp;
Stack = Context->CurrentIrpSp;
FileObject = Stack->FileObject;
/* Check whether that's a device opening */
if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
{
FileObject->FsContext = &RxDeviceFCB;
FileObject->FsContext2 = NULL;
++RxDeviceFCB.NodeReferenceCount;
++RxDeviceFCB.OpenCount;
Irp->IoStatus.Information = FILE_OPENED;
DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
Status = STATUS_SUCCESS;
}
else
{
PFCB RelatedFcb = NULL;
/* Make sure caller is consistent */
if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
(FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
{
DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
return STATUS_INVALID_PARAMETER;
}
DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
DPRINT("FileName: %wZ\n", &FileObject->FileName);
if (FileObject->RelatedFileObject != NULL)
{
RelatedFcb = FileObject->RelatedFileObject->FsContext;
DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
}
/* Going to rename? */
if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
{
DPRINT("TargetDir!\n");
}
/* Copy create parameters to the context */
RxCopyCreateParameters(Context);
/* If the caller wants to establish a connection, go ahead */
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
{
Status = RxCreateTreeConnect(Context);
}
else
{
/* Validate file name */
if (FileObject->FileName.Length > sizeof(WCHAR) &&
FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
{
FileObject->FileName.Length -= sizeof(WCHAR);
RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
FileObject->FileName.Length);
if (FileObject->FileName.Length > sizeof(WCHAR) &&
FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
{
return STATUS_OBJECT_NAME_INVALID;
}
}
/* Attempt to open the file */
do
{
UNICODE_STRING NetRootName;
/* Strip last \ if required */
if (FileObject->FileName.Length != 0 &&
FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
{
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
{
return STATUS_OBJECT_NAME_INVALID;
}
FileObject->FileName.Length -= sizeof(WCHAR);
Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
}
if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
{
FileObject->Flags |= FO_WRITE_THROUGH;
}
/* Get the associated net root to opening */
Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
if (Status != STATUS_MORE_PROCESSING_REQUIRED)
{
break;
}
/* And attempt to open */
Status = RxCreateFromNetRoot(Context, &NetRootName);
if (Status == STATUS_SHARING_VIOLATION)
{
ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
/* If that happens for file creation, fail for real */
if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
{
Status = STATUS_OBJECT_NAME_COLLISION;
}
else
{
/* Otherwise, if possible, attempt to scavenger current FOBX
* to check whether a dormant FOBX is the reason for sharing violation
*/
if (Context->Create.TryForScavengingOnSharingViolation &&
!Context->Create.ScavengingAlreadyTried)
{
/* Only doable with a VNetRoot */
if (Context->Create.pVNetRoot != NULL)
{
PV_NET_ROOT VNetRoot;
NT_CREATE_PARAMETERS SavedParameters;
/* Save create parameters */
RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
/* Reference the VNetRoot for the scavenging time */
VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
RxReferenceVNetRoot(VNetRoot);
/* Prepare the RX_CONTEXT for reuse */
RxpPrepareCreateContextForReuse(Context);
RxReinitializeContext(Context);
/* Copy what we saved */
RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
/* And recopy what can be */
RxCopyCreateParameters(Context);
/* And start purging, then scavenging FOBX */
RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
NULL, TRUE);
/* Ask for a second round */
Status = STATUS_MORE_PROCESSING_REQUIRED;
/* Keep track we already scavenged */
Context->Create.ScavengingAlreadyTried = TRUE;
/* Reference our SRV_CALL for CBS handling */
RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
/* Drop our extra reference */
RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
}
}
}
}
else if (Status == STATUS_REPARSE)
{
Context->CurrentIrp->IoStatus.Information = 0;
}
else
{
ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
}
}
while (Status == STATUS_MORE_PROCESSING_REQUIRED);
}
if (Status == STATUS_RETRY)
{
RxpPrepareCreateContextForReuse(Context);
}
ASSERT(Status != STATUS_PENDING);
}
DPRINT("Status: %lx\n", Status);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonDevFCBCleanup(
PRX_CONTEXT Context)
{
PMRX_FCB Fcb;
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
Fcb = Context->pFcb;
Status = STATUS_SUCCESS;
ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
/* Our FOBX if set, has to be a VNetRoot */
if (Context->pFobx != NULL)
{
RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
}
else
{
--Fcb->UncleanCount;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonDevFCBClose(
PRX_CONTEXT Context)
{
PMRX_FCB Fcb;
NTSTATUS Status;
PMRX_V_NET_ROOT NetRoot;
PAGED_CODE();
DPRINT("RxCommonDevFCBClose(%p)\n", Context);
Fcb = Context->pFcb;
NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
Status = STATUS_SUCCESS;
ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
/* Our FOBX if set, has to be a VNetRoot */
if (NetRoot != NULL)
{
RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
{
--NetRoot->NumberOfOpens;
RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
}
else
{
Status = STATUS_NOT_IMPLEMENTED;
}
RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
}
else
{
--Fcb->OpenCount;
}
return Status;
}
NTSTATUS
NTAPI
RxCommonDevFCBFsCtl(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonDevFCBIoCtl(
PRX_CONTEXT Context)
{
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
if (Context->pFobx != NULL)
{
return STATUS_INVALID_HANDLE;
}
/* Is that a prefix claim from MUP? */
if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
{
return RxPrefixClaim(Context);
}
/* Otherwise, pass through the mini-rdr */
Status = RxXXXControlFileCallthru(Context);
if (Status != STATUS_PENDING)
{
if (Context->PostRequest)
{
Context->ResumeRoutine = RxCommonDevFCBIoCtl;
Status = RxFsdPostRequest(Context);
}
}
DPRINT("Status: %lx\n", Status);
return Status;
}
NTSTATUS
NTAPI
RxCommonDevFCBQueryVolInfo(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonDeviceControl(
PRX_CONTEXT Context)
{
NTSTATUS Status;
PAGED_CODE();
/* Prefix claim is only allowed for device, not files */
if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Submit to mini-rdr */
RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
if (Status == STATUS_PENDING)
{
RxDereferenceAndDeleteRxContext_Real(Context);
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonDirectoryControl(
PRX_CONTEXT Context)
{
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
Stack = Context->CurrentIrpSp;
DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
/* Call the appropriate helper */
if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
{
Status = RxQueryDirectory(Context);
}
else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
{
Status = RxNotifyChangeDirectory(Context);
if (Status == STATUS_PENDING)
{
RxDereferenceAndDeleteRxContext_Real(Context);
}
}
else
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
return Status;
}
NTSTATUS
NTAPI
RxCommonDispatchProblem(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonFileSystemControl(
PRX_CONTEXT Context)
{
PIRP Irp;
ULONG ControlCode;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
Irp = Context->CurrentIrp;
Stack = Context->CurrentIrpSp;
ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonFlushBuffers(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonLockControl(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonQueryEa(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonQueryInformation(
PRX_CONTEXT Context)
{
#define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
PFCB Fcb;
PIRP Irp;
PFOBX Fobx;
BOOLEAN Locked;
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
FILE_INFORMATION_CLASS FileInfoClass;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp;
Stack = Context->CurrentIrpSp;
DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
Context->Info.Length = Stack->Parameters.QueryFile.Length;
FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
Locked = FALSE;
_SEH2_TRY
{
PVOID Buffer;
/* Get a writable buffer */
Buffer = RxMapSystemBuffer(Context);
if (Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
_SEH2_LEAVE;
}
/* Zero it */
RtlZeroMemory(Buffer, Context->Info.Length);
/* Validate file type */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
{
if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
{
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
{
if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
{
Status = STATUS_NOT_IMPLEMENTED;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
_SEH2_LEAVE;
}
}
/* Acquire the right lock */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
FileInfoClass != FileNameInformation)
{
if (FileInfoClass == FileCompressionInformation)
{
Status = RxAcquireExclusiveFcb(Context, Fcb);
}
else
{
Status = RxAcquireSharedFcb(Context, Fcb);
}
if (Status == STATUS_LOCK_NOT_GRANTED)
{
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
else if (!NT_SUCCESS(Status))
{
_SEH2_LEAVE;
}
Locked = TRUE;
}
/* Dispatch to the right helper */
switch (FileInfoClass)
{
case FileBasicInformation:
Status = RxQueryBasicInfo(Context, Buffer);
break;
case FileStandardInformation:
Status = RxQueryStandardInfo(Context, Buffer);
break;
case FileInternalInformation:
Status = RxQueryInternalInfo(Context, Buffer);
break;
case FileEaInformation:
Status = RxQueryEaInfo(Context, Buffer);
break;
case FileNameInformation:
Status = RxQueryNameInfo(Context, Buffer);
break;
case FileAllInformation:
SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
if (!NT_SUCCESS(Status))
{
break;
}
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
if (!NT_SUCCESS(Status))
{
break;
}
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
if (!NT_SUCCESS(Status))
{
break;
}
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
sizeof(FILE_STANDARD_INFORMATION) +
sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
if (!NT_SUCCESS(Status))
{
break;
}
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
sizeof(FILE_STANDARD_INFORMATION) +
sizeof(FILE_INTERNAL_INFORMATION) +
sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
if (!NT_SUCCESS(Status))
{
break;
}
SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
sizeof(FILE_STANDARD_INFORMATION) +
sizeof(FILE_INTERNAL_INFORMATION) +
sizeof(FILE_EA_INFORMATION) +
sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
break;
case FileAlternateNameInformation:
Status = RxQueryAlternateNameInfo(Context, Buffer);
break;
case FilePipeInformation:
case FilePipeLocalInformation:
case FilePipeRemoteInformation:
Status = RxQueryPipeInfo(Context, Buffer);
break;
case FileCompressionInformation:
Status = RxQueryCompressedInfo(Context, Buffer);
break;
default:
Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
Status = Context->IoStatusBlock.Status;
break;
}
if (Context->Info.Length < 0)
{
Status = STATUS_BUFFER_OVERFLOW;
Context->Info.Length = Stack->Parameters.QueryFile.Length;
}
Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
}
_SEH2_FINALLY
{
if (Locked)
{
RxReleaseFcb(Context, Fcb);
}
}
_SEH2_END;
DPRINT("Status: %x\n", Status);
return Status;
#undef SET_SIZE_AND_QUERY
}
NTSTATUS
NTAPI
RxCommonQueryQuotaInformation(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonQuerySecurity(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonQueryVolumeInformation(
PRX_CONTEXT Context)
{
PIRP Irp;
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp;
Stack = Context->CurrentIrpSp;
DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
Context->Info.Length = Stack->Parameters.QueryVolume.Length;
/* Forward to mini-rdr */
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
/* Post request if mini-rdr asked to */
if (Context->PostRequest)
{
Status = RxFsdPostRequest(Context);
}
else
{
Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
}
DPRINT("Status: %x\n", Status);
return Status;
}
NTSTATUS
NTAPI
RxCommonRead(
PRX_CONTEXT RxContext)
{
PFCB Fcb;
PIRP Irp;
PFOBX Fobx;
NTSTATUS Status;
PNET_ROOT NetRoot;
PVOID SystemBuffer;
PFILE_OBJECT FileObject;
LARGE_INTEGER ByteOffset;
PIO_STACK_LOCATION Stack;
PLOWIO_CONTEXT LowIoContext;
PRDBSS_DEVICE_OBJECT RxDeviceObject;
ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
PAGED_CODE();
Fcb = (PFCB)RxContext->pFcb;
Fobx = (PFOBX)RxContext->pFobx;
DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
/* Get some parameters */
Irp = RxContext->CurrentIrp;
Stack = RxContext->CurrentIrpSp;
CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
ReadLength = Stack->Parameters.Read.Length;
ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
(CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
RxItsTheSameContext();
Irp->IoStatus.Information = 0;
/* Should the read be loud - so far, it's just ignored on ReactOS:
* s/DPRINT/DPRINT1/g will make it loud
*/
LowIoContext = &RxContext->LowIoContext;
CheckForLoudOperations(RxContext);
if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
{
DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
ByteOffset, ReadLength,
Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
}
RxDeviceObject = RxContext->RxDeviceObject;
/* Update stats */
if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
{
InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
{
InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
}
Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
if (PagingIo)
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
}
else if (NoCache)
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
}
else
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
}
}
/* A pagefile cannot be a pipe */
IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
if (IsPipe && PagingIo)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Null-length read is no-op */
if (ReadLength == 0)
{
return STATUS_SUCCESS;
}
/* Validate FCB type */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Init the lowio context for possible forward */
RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
PostRequest = FALSE;
ReadCachingDisabled = FALSE;
OwnerSet = FALSE;
ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
FileObject = Stack->FileObject;
NetRoot = (PNET_ROOT)Fcb->pNetRoot;
_SEH2_TRY
{
LONGLONG FileSize;
/* If no caching, make sure current Cc data have been flushed */
if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
{
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostRequest = TRUE;
_SEH2_LEAVE;
}
else if (Status != STATUS_SUCCESS)
{
_SEH2_LEAVE;
}
ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
RxReleasePagingIoResource(RxContext, Fcb);
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
Status = Irp->IoStatus.Status;
_SEH2_LEAVE;
}
RxAcquirePagingIoResource(RxContext, Fcb);
RxReleasePagingIoResource(RxContext, Fcb);
}
/* Acquire the appropriate lock */
if (PagingIo && !ReadCachingEnabled)
{
ASSERT(!IsPipe);
if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
{
PostRequest = TRUE;
_SEH2_LEAVE;
}
if (!CanWait)
{
LowIoContext->Resource = Fcb->Header.PagingIoResource;
}
}
else
{
if (!ReadCachingEnabled)
{
if (!CanWait && NoCache)
{
Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
DPRINT1("RdAsyLNG %x\n", RxContext);
PostRequest = TRUE;
_SEH2_LEAVE;
}
if (Status != STATUS_SUCCESS)
{
DPRINT1("RdAsyOthr %x\n", RxContext);
_SEH2_LEAVE;
}
if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
{
LowIoContext->Resource = Fcb->Header.Resource;
}
else
{
PostRequest = TRUE;
_SEH2_LEAVE;
}
}
else
{
Status = RxAcquireSharedFcb(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostRequest = TRUE;
_SEH2_LEAVE;
}
else if (Status != STATUS_SUCCESS)
{
_SEH2_LEAVE;
}
}
}
}
RxItsTheSameContext();
ReadCachingDisabled = (ReadCachingEnabled == FALSE);
if (IsPipe)
{
UNIMPLEMENTED;
}
RxGetFileSizeWithLock(Fcb, &FileSize);
/* Make sure FLOCK doesn't conflict */
if (!PagingIo)
{
if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
{
Status = STATUS_FILE_LOCK_CONFLICT;
_SEH2_LEAVE;
}
}
/* Validate byteoffset vs length */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
{
if (ByteOffset.QuadPart >= FileSize)
{
Status = STATUS_END_OF_FILE;
_SEH2_LEAVE;
}
if (ReadLength > FileSize - ByteOffset.QuadPart)
{
ReadLength = FileSize - ByteOffset.QuadPart;
}
}
/* Read with Cc! */
if (!PagingIo && !NoCache && ReadCachingEnabled &&
!BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
{
/* File was not cached yet, do it */
if (FileObject->PrivateCacheMap == NULL)
{
if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
{
Status = STATUS_FILE_CLOSED;
_SEH2_LEAVE;
}
RxAdjustAllocationSizeforCC(Fcb);
CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
FALSE, &RxData.CacheManagerCallbacks, Fcb);
if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
{
CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
}
else
{
CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
}
CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
}
/* This should never happen - fix your RDR */
if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
{
ASSERT(FALSE);
ASSERT(CanWait);
CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
Status = Irp->IoStatus.Status;
ASSERT(NT_SUCCESS(Status));
}
else
{
/* Map buffer */
SystemBuffer = RxNewMapUserBuffer(RxContext);
if (SystemBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
_SEH2_LEAVE;
}
SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
RxItsTheSameContext();
/* Perform the read */
if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
{
if (!ReadCachingEnabled)
{
ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
}
RxItsTheSameContext();
PostRequest = TRUE;
_SEH2_LEAVE;
}
if (!ReadCachingEnabled)
{
ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
}
Status = Irp->IoStatus.Status;
ASSERT(NT_SUCCESS(Status));
}
}
else
{
/* Validate the reading */
if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
ByteOffset.QuadPart >= 4096)
{
CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
}
/* If it's consistent, forward to mini-rdr */
if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
{
LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
RxItsTheSameContext();
if (InFsp && ReadCachingDisabled)
{
ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
(PVOID)((ULONG_PTR)RxContext | 3));
OwnerSet = TRUE;
}
Status = RxLowIoReadShell(RxContext);
RxItsTheSameContext();
}
else
{
if (ByteOffset.QuadPart > FileSize)
{
ReadLength = 0;
Irp->IoStatus.Information = ReadLength;
_SEH2_LEAVE;
}
if (ByteOffset.QuadPart + ReadLength > FileSize)
{
ReadLength = FileSize - ByteOffset.QuadPart;
}
SystemBuffer = RxNewMapUserBuffer(RxContext);
RtlZeroMemory(SystemBuffer, ReadLength);
Irp->IoStatus.Information = ReadLength;
}
}
}
_SEH2_FINALLY
{
RxItsTheSameContext();
/* Post if required */
if (PostRequest)
{
InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
Status = RxFsdPostRequest(RxContext);
}
else
{
/* Update FO in case of sync IO */
if (!IsPipe && !PagingIo)
{
if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
{
FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
}
}
}
/* Set FastIo if read was a success */
if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
if (!IsPipe && !PagingIo)
{
SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
}
}
/* In case we're done (not expected any further processing */
if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
{
/* Release everything that can be */
if (ReadCachingDisabled)
{
if (PagingIo)
{
if (OwnerSet)
{
RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
else
{
RxReleasePagingIoResource(RxContext, Fcb);
}
}
else
{
if (OwnerSet)
{
RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
else
{
RxReleaseFcb(RxContext, Fcb);
}
}
}
/* Dereference/Delete context */
if (PostRequest)
{
RxDereferenceAndDeleteRxContext(RxContext);
}
else
{
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
}
}
/* We cannot return more than asked */
if (Status == STATUS_SUCCESS)
{
ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
}
}
else
{
ASSERT(!Sync);
RxDereferenceAndDeleteRxContext(RxContext);
}
}
_SEH2_END;
return Status;
}
NTSTATUS
NTAPI
RxCommonSetEa(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCommonSetInformation(
PRX_CONTEXT Context)
{
PIRP Irp;
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PNET_ROOT NetRoot;
PIO_STACK_LOCATION Stack;
FILE_INFORMATION_CLASS Class;
BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
PAGED_CODE();
Fcb = (PFCB)Context->pFcb;
Fobx = (PFOBX)Context->pFobx;
DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
Irp = Context->CurrentIrp;
Stack = Context->CurrentIrpSp;
Class = Stack->Parameters.SetFile.FileInformationClass;
DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
Class, Stack->Parameters.SetFile.ReplaceIfExists);
Status = STATUS_SUCCESS;
CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
FcbTableAcquired = FALSE;
FcbAcquired = FALSE;
NetRoot = (PNET_ROOT)Fcb->pNetRoot;
#define _SEH2_TRY_RETURN(S) S; goto try_exit
_SEH2_TRY
{
/* Valide the node type first */
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
{
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
{
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
{
Status = STATUS_SUCCESS;
}
}
else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
{
if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
{
_SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
}
else
{
DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
_SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER);
}
}
}
/* We don't autorize advance operation */
if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
{
DPRINT1("Not allowed\n");
_SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
}
/* For these to classes, we'll have to deal with the FCB table (removal)
* We thus need the exclusive FCB table lock
*/
if (Class == FileDispositionInformation || Class == FileRenameInformation)
{
RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
{
Context->PostRequest = TRUE;
_SEH2_TRY_RETURN(Status = STATUS_PENDING);
}
FcbTableAcquired = TRUE;
}
/* Finally, if not paging file, we need exclusive FCB lock */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
{
Status = RxAcquireExclusiveFcb(Context, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
Context->PostRequest = TRUE;
_SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
}
else if (Status != STATUS_SUCCESS)
{
_SEH2_LEAVE;
}
FcbAcquired = TRUE;
}
Status = STATUS_SUCCESS;
/* And now, perform the job! */
switch (Class)
{
case FileBasicInformation:
Status = RxSetBasicInfo(Context);
break;
case FileDispositionInformation:
{
PFILE_DISPOSITION_INFORMATION FDI;
/* Check whether user wants deletion */
FDI = Irp->AssociatedIrp.SystemBuffer;
if (FDI->DeleteFile)
{
/* If so, check whether it's doable */
if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
{
Status = STATUS_CANNOT_DELETE;
}
/* And if doable, already remove from FCB table */
if (Status == STATUS_SUCCESS)
{
ASSERT(FcbAcquired && FcbTableAcquired);
RxRemoveNameNetFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable);
FcbTableAcquired = FALSE;
}
}
/* If it succeed, perform the operation */
if (Status == STATUS_SUCCESS)
{
Status = RxSetDispositionInfo(Context);
}
break;
}
case FilePositionInformation:
Status = RxSetPositionInfo(Context);
break;
case FileAllocationInformation:
Status = RxSetAllocationInfo(Context);
break;
case FileEndOfFileInformation:
Status = RxSetEndOfFileInfo(Context);
break;
case FilePipeInformation:
case FilePipeLocalInformation:
case FilePipeRemoteInformation:
Status = RxSetPipeInfo(Context);
break;
case FileRenameInformation:
case FileLinkInformation:
case FileMoveClusterInformation:
/* If we can wait, try to perform the operation right now */
if (CanWait)
{
/* Of course, collapsing is not doable anymore, file is
* in an inbetween state
*/
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
/* Set the information */
Status = RxSetRenameInfo(Context);
/* If it succeed, drop the current entry from FCB table */
if (Status == STATUS_SUCCESS && Class == FileRenameInformation)
{
ASSERT(FcbAcquired && FcbTableAcquired);
RxRemoveNameNetFcb(Fcb);
}
_SEH2_TRY_RETURN(Status);
}
/* Can't wait? Post for async retry */
else
{
Status = RxFsdPostRequest(Context);
_SEH2_TRY_RETURN(Status);
}
break;
case FileValidDataLengthInformation:
if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL))
{
Status = STATUS_USER_MAPPED_FILE;
}
break;
case FileShortNameInformation:
Status = RxSetSimpleInfo(Context);
break;
default:
DPRINT1("Insupported class: %x\n", Class);
Status = STATUS_INVALID_PARAMETER;
break;
}
try_exit: NOTHING;
/* If mini-rdr was OK and wants a re-post on this, do it */
if (Status == STATUS_SUCCESS)
{
if (Context->PostRequest)
{
Status = RxFsdPostRequest(Context);
}
}
}
_SEH2_FINALLY
{
/* Release any acquired lock */
if (FcbAcquired)
{
RxReleaseFcb(Context, Fcb);
}
if (FcbTableAcquired)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
}
}
_SEH2_END;
#undef _SEH2_TRY_RETURN
return Status;
}
NTSTATUS
NTAPI
RxCommonSetQuotaInformation(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonSetSecurity(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonSetVolumeInformation(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonUnimplemented(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
RxCommonWrite(
PRX_CONTEXT RxContext)
{
PIRP Irp;
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PNET_ROOT NetRoot;
PSRV_OPEN SrvOpen;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
LARGE_INTEGER ByteOffset;
NODE_TYPE_CODE NodeTypeCode;
PLOWIO_CONTEXT LowIoContext;
PRDBSS_DEVICE_OBJECT RxDeviceObject;
ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
PAGED_CODE();
Fcb = (PFCB)RxContext->pFcb;
NodeTypeCode = NodeType(Fcb);
/* Validate FCB type */
if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* We'll write to file, keep track of it */
Fcb->IsFileWritten = TRUE;
Stack = RxContext->CurrentIrpSp;
/* Set write through if asked */
if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
{
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
}
Fobx = (PFOBX)RxContext->pFobx;
DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
/* Get some parameters */
Irp = RxContext->CurrentIrp;
NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
WriteLength = Stack->Parameters.Write.Length;
ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
(CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
RxItsTheSameContext();
RxContext->FcbResourceAcquired = FALSE;
RxContext->FcbPagingIoResourceAcquired = FALSE;
LowIoContext = &RxContext->LowIoContext;
CheckForLoudOperations(RxContext);
if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
{
DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
ByteOffset, WriteLength,
Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
}
RxDeviceObject = RxContext->RxDeviceObject;
/* Update stats */
if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
{
InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
{
InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
}
Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
if (PagingIo)
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength);
}
else if (NoCache)
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength);
}
else
{
ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength);
}
}
NetRoot = (PNET_ROOT)Fcb->NetRoot;
IsPipe = (NetRoot->Type == NET_ROOT_PIPE);
/* Keep track for normal writes */
if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
{
NormalFile = TRUE;
}
else
{
NormalFile = FALSE;
}
/* Zero-length write is immediate success */
if (NormalFile && WriteLength == 0)
{
return STATUS_SUCCESS;
}
/* Check whether we have input data */
if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
{
return STATUS_INVALID_PARAMETER;
}
/* Are we writting to EOF? */
WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1));
/* FIXME: validate length/offset */
/* Get our SRV_OPEN in case of normal write */
if (Fobx != NULL)
{
SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
}
else
{
SrvOpen = NULL;
}
FileObject = Stack->FileObject;
/* If we have caching enabled, check whether we have to defer write */
if (!NoCache)
{
if (RxWriteCacheingAllowed(Fcb, SrvOpen))
{
if (!CcCanIWrite(FileObject, WriteLength,
(CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)),
BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE)))
{
BOOLEAN Retrying;
Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
RxPrePostIrp(RxContext, Irp);
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
return STATUS_PENDING;
}
}
}
/* Initialize the low IO context for write */
RxInitializeLowIoContext(LowIoContext, LOWIO_OP_WRITE);
/* Initialize our (many) booleans */
RecursiveWriteThrough = FALSE;
CalledByLazyWriter = FALSE;
SwitchBackToAsync = FALSE;
ExtendingFile = FALSE;
ExtendingValidData = FALSE;
UnwindOutstandingAsync = FALSE;
ResourceOwnerSet = FALSE;
PostIrp = FALSE;
ContextReferenced = FALSE;
#define _SEH2_TRY_RETURN(S) S; goto try_exit
_SEH2_TRY
{
/* No volume FCB here! */
ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) ||
(NodeTypeCode == RDBSS_NTC_SPOOLFILE) ||
(NodeTypeCode == RDBSS_NTC_MAILSLOT));
/* Writing to EOF on a paging file is non sense */
ASSERT(!(WriteToEof && PagingIo));
RxItsTheSameContext();
/* Start locking stuff */
if (!PagingIo && !NoPreposting)
{
/* If it's already acquired, all fine */
if (RxContext->FcbResourceAcquired)
{
ASSERT(!IsPipe);
}
else
{
/* Otherwise, try to acquire shared (excepted for pipes) */
if (IsPipe)
{
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
}
else if (CanWait ||
(!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen)))
{
Status = RxAcquireSharedFcb(RxContext, Fcb);
}
else
{
Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
}
/* We'll post IRP to retry */
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostIrp = TRUE;
DPRINT1("Failed to acquire lock!\n");
_SEH2_TRY_RETURN(Status);
}
/* We'll just fail */
if (Status != STATUS_SUCCESS)
{
_SEH2_TRY_RETURN(Status);
}
/* Resource acquired */
RxContext->FcbResourceAcquired = TRUE;
}
/* At that point, resource is acquired */
if (IsPipe)
{
ASSERT(RxContext->FcbResourceAcquired);
}
else
{
BOOLEAN IsDormant;
/* Now, check whether we have to promote shared lock */
if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
{
IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
}
else
{
IsDormant = FALSE;
}
/* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
if (RxIsFcbAcquiredShared(Fcb) &&
ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart)
{
if (!IsDormant)
{
RxReleaseFcb(RxContext, Fcb);
RxContext->FcbResourceAcquired = FALSE;
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostIrp = TRUE;
DPRINT1("Failed to acquire lock!\n");
_SEH2_TRY_RETURN(Status);
}
if (Status != STATUS_SUCCESS)
{
_SEH2_TRY_RETURN(Status);
}
RxContext->FcbResourceAcquired = TRUE;
}
}
/* If we're writing in VDL, or if we're dormant, shared lock is enough */
if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart ||
IsDormant)
{
if (RxIsFcbAcquiredExclusive(Fcb))
{
RxConvertToSharedFcb(RxContext, Fcb);
}
}
else
{
/* We're extending file, disable collapsing */
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
DPRINT("Disabling collapsing\n");
if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
{
SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
}
}
ASSERT(RxContext->FcbResourceAcquired);
}
/* Keep track of the acquired resource */
LowIoContext->Resource = Fcb->Header.Resource;
}
else
{
/* Paging IO */
ASSERT(!IsPipe);
/* Lock the paging resource */
RxAcquirePagingIoResourceShared(RxContext, Fcb, TRUE);
/* Keep track of the acquired resource */
LowIoContext->Resource = Fcb->Header.PagingIoResource;
}
if (IsPipe)
{
UNIMPLEMENTED;
_SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
}
/* If it's a non cached write, or if caching is disallowed */
if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
{
/* If cache was previously enabled, we'll have to flush before writing */
if (!PagingIo && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
{
LARGE_INTEGER FlushOffset;
/* FCB is lock */
ASSERT(RxIsFcbAcquiredExclusive(Fcb) || RxIsFcbAcquiredShared(Fcb));
/* If shared, we'll have to relock exclusive */
if (!RxIsFcbAcquiredExclusive(Fcb))
{
/* Release and retry exclusive */
RxReleaseFcb(RxContext, Fcb);
RxContext->FcbResourceAcquired = FALSE;
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostIrp = TRUE;
DPRINT1("Failed to acquire lock for flush!\n");
_SEH2_TRY_RETURN(Status);
}
if (Status != STATUS_SUCCESS)
{
_SEH2_TRY_RETURN(Status);
}
RxContext->FcbResourceAcquired = TRUE;
}
/* Get the length to flush */
if (WriteToEof)
{
RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart);
}
else
{
FlushOffset.QuadPart = ByteOffset.QuadPart;
}
/* Perform the flushing */
RxAcquirePagingIoResource(RxContext, Fcb);
CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset,
WriteLength, &Irp->IoStatus);
RxReleasePagingIoResource(RxContext, Fcb);
/* Cannot continue if flushing failed */
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
_SEH2_TRY_RETURN(Status = Irp->IoStatus.Status);
}
/* Synchronize */
RxAcquirePagingIoResource(RxContext, Fcb);
RxReleasePagingIoResource(RxContext, Fcb);
/* And purge */
CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers,
&FlushOffset, WriteLength, FALSE);
}
}
/* If not paging IO, check if write is allowed */
if (!PagingIo)
{
if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp))
{
_SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
}
}
/* Get file sizes */
ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
RxGetFileSizeWithLock(Fcb, &FileSize);
ASSERT(ValidDataLength <= FileSize);
/* If paging IO, we cannot write past file size
* so fix write length if needed
*/
if (PagingIo)
{
if (ByteOffset.QuadPart >= FileSize)
{
_SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
}
if (WriteLength > FileSize - ByteOffset.QuadPart)
{
WriteLength = FileSize - ByteOffset.QuadPart;
}
}
/* If we're being called by the lazywrite */
if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread())
{
CalledByLazyWriter = TRUE;
/* Fail if we're beyong VDL */
if (BooleanFlagOn(Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE))
{
if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) &&
(ByteOffset.QuadPart < FileSize))
{
if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
{
_SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
}
}
}
}
/* If that's a recursive synchronous page write */
if (BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
{
PIRP TopIrp;
/* Check the top level IRP on the FastIO path */
TopIrp = RxGetTopIrpIfRdbssIrp();
if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP)
{
PIO_STACK_LOCATION IrpStack;
ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
/* If the top level IRP was a cached write for this file, keep track */
IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
if (IrpStack->MajorFunction == IRP_MJ_WRITE &&
IrpStack->FileObject->FsContext == FileObject->FsContext)
{
RecursiveWriteThrough = TRUE;
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
}
}
}
/* Now, deal with file size and VDL */
if (!CalledByLazyWriter && !RecursiveWriteThrough &&
(WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength))
{
/* Not sync? Let's make it sync, just the time we extended */
if (!Sync)
{
CanWait = TRUE;
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
Sync = TRUE;
/* Keep track we'll have to switch back to async */
if (NoCache)
{
SwitchBackToAsync = TRUE;
}
}
/* Release all the locks */
RxWriteReleaseResources(RxContext, 0);
/* Acquire exclusive */
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status == STATUS_LOCK_NOT_GRANTED)
{
PostIrp = TRUE;
DPRINT1("Failed to acquire lock for extension!\n");
_SEH2_TRY_RETURN(Status);
}
if (Status != STATUS_SUCCESS)
{
_SEH2_TRY_RETURN(Status);
}
RxContext->FcbResourceAcquired = TRUE;
RxItsTheSameContext();
/* Get the sizes again, to be sure they didn't change in the meantime */
ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
RxGetFileSizeWithLock(Fcb, &FileSize);
ASSERT(ValidDataLength <= FileSize);
/* Check we can switch back to async? */
if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
(ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync)
{
SwitchBackToAsync = FALSE;
}
/* If paging IO, check we don't try to extend the file */
if (PagingIo)
{
if (ByteOffset.QuadPart >= FileSize)
{
_SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
}
if (WriteLength > FileSize - ByteOffset.QuadPart)
{
WriteLength = FileSize - ByteOffset.QuadPart;
}
}
}
/* Save our initial sizes for potential rollback */
InitialFileSize = FileSize;
InitialValidDataLength = ValidDataLength;
/* If writing to EOF, update byte offset with file size */
if (WriteToEof)
{
ByteOffset.QuadPart = FileSize;
}
/* Check again whether we're allowed to write */
if (!PagingIo)
{
if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp ))
{
_SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
}
/* Do we have to extend? */
if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize))
{
DPRINT("Need to extend file\n");
ExtendingFile = TRUE;
SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE);
}
}
/* Let's start to extend */
if (ExtendingFile)
{
/* If we're past allocating, inform mini-rdr */
FileSize = ByteOffset.QuadPart + WriteLength;
if (FileSize > Fcb->Header.AllocationSize.QuadPart)
{
LARGE_INTEGER NewAllocationSize;
DPRINT("Extending %p\n", RxContext);
if (NoCache)
{
C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache,
(RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
}
else
{
C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache,
(RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
}
if (!NT_SUCCESS(Status))
{
_SEH2_TRY_RETURN(Status);
}
if (FileSize > NewAllocationSize.QuadPart)
{
NewAllocationSize.QuadPart = FileSize;
}
/* And update FCB */
Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
}
/* Set the new sizes */
RxSetFileSizeWithLock(Fcb, &FileSize);
RxAdjustAllocationSizeforCC(Fcb);
/* And inform Cc */
if (CcIsFileCached(FileObject))
{
CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
}
}
/* Do we have to extend VDL? */
if (!CalledByLazyWriter && !RecursiveWriteThrough)
{
if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)
{
ExtendingValidData = TRUE;
SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL);
}
}
/* If none cached write */
if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
{
/* Switch back to async, if asked to */
if (SwitchBackToAsync)
{
CanWait = FALSE;
Sync = FALSE;
ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
}
/* If not synchronous, keep track of writes to be finished */
if (!Sync)
{
if (Fcb->NonPaged->OutstandingAsyncEvent == NULL)
{
Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent;
KeInitializeEvent(Fcb->NonPaged->OutstandingAsyncEvent,
NotificationEvent, FALSE);
}
if (ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites,
1,
&RxStrucSupSpinLock) == 0)
{
KeResetEvent(Fcb->NonPaged->OutstandingAsyncEvent);
}
UnwindOutstandingAsync = TRUE;
LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
}
/* Set our LOWIO_CONTEXT information */
LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
RxItsTheSameContext();
/* We have to be locked */
ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
/* Update thread ID if we're in FSP */
if (InFsp)
{
LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
if (RxContext->FcbResourceAcquired)
{
ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3));
}
if (RxContext->FcbPagingIoResourceAcquired)
{
ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3));
}
ResourceOwnerSet = TRUE;
}
/* And perform the write */
Status = RxLowIoWriteShell(RxContext);
RxItsTheSameContext();
/* Not outstanding write anymore */
if (UnwindOutstandingAsync && Status == STATUS_PENDING)
{
UnwindOutstandingAsync = FALSE;
}
}
/* Cached write */
else
{
/* If cache wasn't enabled yet, do it */
if (FileObject->PrivateCacheMap == NULL)
{
if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
{
_SEH2_TRY_RETURN(Status = STATUS_FILE_CLOSED);
}
RxAdjustAllocationSizeforCC(Fcb);
CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
FALSE, &RxData.CacheManagerCallbacks, Fcb);
CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
}
/* If that's a MDL backed write */
if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
{
/* Shouldn't happen */
ASSERT(FALSE);
ASSERT(CanWait);
/* Perform it, though */
CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength,
&Irp->MdlAddress, &Irp->IoStatus);
Status = Irp->IoStatus.Status;
}
else
{
PVOID SystemBuffer;
ULONG BreakpointsSave;
/* Map the user buffer */
SystemBuffer = RxNewMapUserBuffer(RxContext);
if (SystemBuffer == NULL)
{
_SEH2_TRY_RETURN(Status = STATUS_INSUFFICIENT_RESOURCES);
}
RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
/* And deal with Cc */
if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait,
SystemBuffer))
{
RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
PostIrp = TRUE;
}
else
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = WriteLength;
RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
RxItsTheSameContext();
DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
}
}
}
try_exit: NOTHING;
/* If we've to post the IRP */
if (PostIrp)
{
/* Reset the file size if required */
if (ExtendingFile && !IsPipe)
{
ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen));
ASSERT(Fcb->Header.PagingIoResource != NULL);
RxAcquirePagingIoResource(RxContext, Fcb);
RxSetFileSizeWithLock(Fcb, &InitialFileSize);
RxReleasePagingIoResource(RxContext, Fcb);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
*CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
}
}
InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
ContextReferenced = TRUE;
/* Release locks */
ASSERT(!ResourceOwnerSet);
RxWriteReleaseResources(RxContext, ResourceOwnerSet);
#ifdef RDBSS_TRACKER
ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
#endif
/* And post the request */
Status = RxFsdPostRequest(RxContext);
}
else
{
if (!IsPipe)
{
/* Update FILE_OBJECT if synchronous write succeed */
if (!PagingIo)
{
if (NT_SUCCESS(Status) && BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
{
FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
}
}
/* If write succeed, ,also update FILE_OBJECT flags */
if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
/* File was modified */
if (!PagingIo)
{
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
}
/* If was even extended */
if (ExtendingFile)
{
SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
}
/* If VDL was extended, update FCB and inform Cc */
if (ExtendingValidData)
{
LONGLONG LastOffset;
LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information;
if (FileSize < LastOffset)
{
LastOffset = FileSize;
}
Fcb->Header.ValidDataLength.QuadPart = LastOffset;
if (NoCache && CcIsFileCached(FileObject))
{
CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
}
}
}
}
}
}
_SEH2_FINALLY
{
/* Finally, if we failed while extension was required */
if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData))
{
/* Rollback! */
if (!IsPipe)
{
ASSERT(Fcb->Header.PagingIoResource != NULL);
RxAcquirePagingIoResource(RxContext, Fcb);
RxSetFileSizeWithLock(Fcb, &InitialFileSize);
Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
RxReleasePagingIoResource(RxContext, Fcb);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
*CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
}
}
}
/* One async write less */
if (UnwindOutstandingAsync)
{
ASSERT(!IsPipe);
ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock);
KeSetEvent(Fcb->NonPaged->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
}
/* And now, cleanup everything */
if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp)
{
/* If we didn't post, release every lock (for posting, it's already done) */
if (!PostIrp)
{
RxWriteReleaseResources(RxContext, ResourceOwnerSet);
}
/* If the context was referenced - posting, dereference it */
if (ContextReferenced)
{
RxDereferenceAndDeleteRxContext(RxContext);
}
/* If that's a pipe operation, resume any blocked one */
if (!PostIrp)
{
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
}
}
/* Sanity check for write */
if (Status == STATUS_SUCCESS)
{
ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
}
}
/* Just dereference our context */
else
{
ASSERT(!Sync);
RxDereferenceAndDeleteRxContext(RxContext);
}
}
_SEH2_END;
#undef _SEH2_TRY_RETURN
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxCompleteMdl(
IN PRX_CONTEXT RxContext)
{
PIRP Irp;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
#define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
PAGED_CODE();
Irp = RxContext->CurrentIrp;
Stack = RxContext->CurrentIrpSp;
FileObject = Stack->FileObject;
/* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
switch (RxContext->MajorFunction)
{
/* Call the Cc function */
case IRP_MJ_READ:
CcMdlReadComplete(FileObject, Irp->MdlAddress);
break;
case IRP_MJ_WRITE:
/* If here, we can wait */
ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
/* Call the Cc function */
CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction);
RxBugCheck(RxContext->MajorFunction, 0, 0);
break;
}
/* MDL was freed */
Irp->MdlAddress = NULL;
/* And complete the IRP */
RxCompleteRequest(RxContext, STATUS_SUCCESS);
#undef BugCheckFileId
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
RxConjureOriginalName(
PFCB Fcb,
PFOBX Fobx,
PULONG ActualNameLength,
PWCHAR OriginalName,
PLONG LengthRemaining,
RX_NAME_CONJURING_METHODS NameConjuringMethod)
{
PWSTR Prefix, Name;
PV_NET_ROOT VNetRoot;
USHORT PrefixLength, NameLength, ToCopy;
PAGED_CODE();
VNetRoot = Fcb->VNetRoot;
/* We will use the prefix contained in NET_ROOT, if we don't have
* a V_NET_ROOT, or if it wasn't null deviced or if we already have
* a UNC path */
if (VNetRoot == NULL || VNetRoot->PrefixEntry.Prefix.Buffer[1] != L';' ||
BooleanFlagOn(Fobx->Flags, FOBX_FLAG_UNC_NAME))
{
Prefix = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Buffer;
PrefixLength = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Length;
NameLength = 0;
/* In that case, keep track that we will have a prefix as buffer */
NameConjuringMethod = VNetRoot_As_Prefix;
}
else
{
ASSERT(NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
/* Otherwise, return the prefix from our V_NET_ROOT */
Prefix = VNetRoot->PrefixEntry.Prefix.Buffer;
PrefixLength = VNetRoot->PrefixEntry.Prefix.Length;
NameLength = VNetRoot->NamePrefix.Length;
/* If we want a UNC path, skip potential device */
if (NameConjuringMethod == VNetRoot_As_UNC_Name)
{
do
{
++Prefix;
PrefixLength -= sizeof(WCHAR);
} while (PrefixLength > 0 && Prefix[0] != L'\\');
}
}
/* If we added an extra backslash, skip it */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ADDEDBACKSLASH))
{
NameLength += sizeof(WCHAR);
}
/* If we're asked for a drive letter, skip the prefix */
if (NameConjuringMethod == VNetRoot_As_DriveLetter)
{
PrefixLength = 0;
/* And make sure we arrive at a backslash */
if (Fcb->FcbTableEntry.Path.Length > NameLength &&
Fcb->FcbTableEntry.Path.Buffer[NameLength / sizeof(WCHAR)] != L'\\')
{
NameLength -= sizeof(WCHAR);
}
}
else
{
/* Prepare to copy the prefix, make sure not to overflow */
if (*LengthRemaining >= PrefixLength)
{
/* Copy everything */
ToCopy = PrefixLength;
*LengthRemaining = *LengthRemaining - PrefixLength;
}
else
{
/* Copy as much as we can */
ToCopy = *LengthRemaining;
/* And return failure */
*LengthRemaining = -1;
}
/* Copy the prefix */
RtlCopyMemory(OriginalName, Prefix, ToCopy);
}
/* Do we have a name to copy now? */
if (Fcb->FcbTableEntry.Path.Length > NameLength)
{
ToCopy = Fcb->FcbTableEntry.Path.Length - NameLength;
Name = Fcb->FcbTableEntry.Path.Buffer;
}
else
{
/* Just use slash for now */
ToCopy = sizeof(WCHAR);
NameLength = 0;
Name = L"\\";
}
/* Total length we will have in the output buffer (if everything is alright) */
*ActualNameLength = ToCopy + PrefixLength;
/* If we still have room to write data */
if (*LengthRemaining != -1)
{
/* If we can copy everything, it's fine! */
if (*LengthRemaining > ToCopy)
{
*LengthRemaining = *LengthRemaining - ToCopy;
}
/* Otherwise, copy as much as possible, and return failure */
else
{
ToCopy = *LengthRemaining;
*LengthRemaining = -1;
}
/* Copy name after the prefix */
RtlCopyMemory(Add2Ptr(OriginalName, PrefixLength),
Add2Ptr(Name, NameLength), ToCopy);
}
}
/*
* @implemented
*/
VOID
RxCopyCreateParameters(
IN PRX_CONTEXT RxContext)
{
PIRP Irp;
PVOID DfsContext;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PDFS_NAME_CONTEXT DfsNameContext;
PIO_SECURITY_CONTEXT SecurityContext;
Irp = RxContext->CurrentIrp;
Stack = RxContext->CurrentIrpSp;
FileObject = Stack->FileObject;
SecurityContext = Stack->Parameters.Create.SecurityContext;
RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext;
if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL)
{
RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor);
DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext,
RxContext->Create.SdLength);
}
if (SecurityContext->SecurityQos != NULL)
{
RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel;
}
else
{
RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation;
}
RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart;
RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
DfsContext = FileObject->FsContext2;
DfsNameContext = FileObject->FsContext;
RxContext->Create.NtCreateParameters.DfsContext = DfsContext;
RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext;
ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) ||
DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) ||
DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) ||
DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT));
ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT ||
DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT ||
DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT ||
DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT);
FileObject->FsContext2 = NULL;
FileObject->FsContext = NULL;
RxContext->pFcb = NULL;
RxContext->Create.ReturnedCreateInformation = 0;
/* if we stripped last \, it has to be a directory! */
if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
{
SetFlag(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DIRECTORY_FILE);
}
RxContext->Create.EaLength = Stack->Parameters.Create.EaLength;
if (RxContext->Create.EaLength == 0)
{
RxContext->Create.EaBuffer = NULL;
}
else
{
RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer;
DPRINT("EA Buffer: %p, Length: %lx\n", Irp->AssociatedIrp.SystemBuffer, RxContext->Create.EaLength);
}
}
NTSTATUS
RxCreateFromNetRoot(
PRX_CONTEXT Context,
PUNICODE_STRING NetRootName)
{
PFCB Fcb;
NTSTATUS Status;
PNET_ROOT NetRoot;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
ACCESS_MASK DesiredAccess;
USHORT DesiredShareAccess;
PAGED_CODE();
/* Validate that the context is consistent */
if (Context->Create.pNetRoot == NULL)
{
return STATUS_BAD_NETWORK_PATH;
}
NetRoot = (PNET_ROOT)Context->Create.pNetRoot;
if (Context->RxDeviceObject != NetRoot->pSrvCall->RxDeviceObject)
{
return STATUS_BAD_NETWORK_PATH;
}
if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) &&
!BooleanFlagOn(NetRoot->pSrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER))
{
return STATUS_DFS_UNAVAILABLE;
}
if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT))
{
return STATUS_OBJECT_TYPE_MISMATCH;
}
Stack = Context->CurrentIrpSp;
DesiredShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
if (NetRoot->Type == NET_ROOT_PRINT)
{
DesiredShareAccess = FILE_SHARE_VALID_FLAGS;
}
DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
/* Get file object */
FileObject = Stack->FileObject;
/* Do we have to open target directory for renaming? */
if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
{
DPRINT("Opening target directory\n");
/* If we have been asked for delete, try to purge first */
if (BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, DELETE))
{
RxPurgeRelatedFobxs((PNET_ROOT)Context->Create.pVNetRoot->pNetRoot, Context,
ATTEMPT_FINALIZE_ON_PURGE, NULL);
}
/* Create the FCB */
Fcb = RxCreateNetFcb(Context, (PV_NET_ROOT)Context->Create.pVNetRoot, NetRootName);
if (Fcb == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Fake it: it will be used only renaming */
NodeType(Fcb) = RDBSS_NTC_OPENTARGETDIR_FCB;
Context->Create.FcbAcquired = FALSE;
Context->Create.NetNamePrefixEntry = NULL;
/* Assign it to the FO */
FileObject->FsContext = Fcb;
/* If we have a FOBX already, check whether it's for DFS opening */
if (Context->pFobx != NULL)
{
/* If so, reflect this in the FOBX */
if (FileObject->FsContext2 == UIntToPtr(DFS_OPEN_CONTEXT))
{
SetFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
}
else
{
ClearFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
}
}
/* Acquire the FCB */
Status = RxAcquireExclusiveFcb(Context, Fcb);
if (Status != STATUS_SUCCESS)
{
return Status;
}
/* Reference the FCB and release */
RxReferenceNetFcb(Fcb);
RxReleaseFcb(Context, Fcb);
/* We're done! */
return STATUS_SUCCESS;
}
/* Try to find (or create) the FCB for the file */
Status = RxFindOrCreateFcb(Context, NetRootName);
Fcb = (PFCB)Context->pFcb;
if (Fcb == NULL)
{
ASSERT(!NT_SUCCESS(Status));
}
if (!NT_SUCCESS(Status) || Fcb == NULL)
{
return Status;
}
if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
{
Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT;
}
else
{
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
/* If finding FCB worked (mailslot case), mark the FCB as good and quit */
if (NT_SUCCESS(Status))
{
RxTransitionNetFcb(Fcb, Condition_Good);
DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb, Fcb->Condition);
++Fcb->OpenCount;
RxSetupNetFileObject(Context);
return STATUS_SUCCESS;
}
/* Not mailslot! */
/* Check SA for conflict */
if (Fcb->OpenCount > 0)
{
Status = RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
&Fcb->ShareAccess, FALSE, "early check per useropens", "EarlyPerUO");
if (!NT_SUCCESS(Status))
{
RxDereferenceNetFcb(Fcb);
return Status;
}
}
if (BooleanFlagOn(Context->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE) &&
!BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, ~SYNCHRONIZE))
{
UNIMPLEMENTED;
}
_SEH2_TRY
{
/* Find a SRV_OPEN that suits the opening */
Status = RxCollapseOrCreateSrvOpen(Context);
if (Status == STATUS_SUCCESS)
{
PFOBX Fobx;
PSRV_OPEN SrvOpen;
SrvOpen = (PSRV_OPEN)Context->pRelevantSrvOpen;
Fobx = (PFOBX)Context->pFobx;
/* There are already opens, check for conflict */
if (Fcb->OpenCount != 0)
{
if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess, DesiredShareAccess,
FileObject, &Fcb->ShareAccess,
FALSE, "second check per useropens",
"2ndAccPerUO")))
{
++SrvOpen->UncleanFobxCount;
RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
_SEH2_LEAVE;
}
}
else
{
if (NetRoot->Type != NET_ROOT_PIPE)
{
RxSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
&Fcb->ShareAccess, "initial shareaccess setup", "InitShrAcc");
}
}
RxSetupNetFileObject(Context);
/* No conflict? Set up SA */
if (Fcb->OpenCount != 0 && NetRoot->Type != NET_ROOT_PIPE)
{
RxUpdateShareAccess(FileObject, &Fcb->ShareAccess, "update share access", "UpdShrAcc");
}
++Fcb->UncleanCount;
if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
++Fcb->UncachedUncleanCount;
}
if (SrvOpen->UncleanFobxCount == 0 && Fcb->UncleanCount == 1 &&
!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE))
{
RxChangeBufferingState(SrvOpen, NULL, FALSE);
}
/* No pending close, we're active */
ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
++Fcb->OpenCount;
++SrvOpen->UncleanFobxCount;
++SrvOpen->OpenCount;
SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
{
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING);
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
ClearFlag(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED);
ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
}
/* Now, update SA for the SRV_OPEN */
RxUpdateShareAccessPerSrvOpens(SrvOpen);
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
{
SetFlag(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE);
}
/* Update the FOBX info */
if (Fobx != NULL)
{
if (Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
{
SetFlag(FileObject->Flags, FO_NAMED_PIPE);
}
if (Context->Create.pNetRoot->Type == NET_ROOT_PRINT ||
Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
{
Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0;
Fobx->Specific.NamedPipe.CollectDataSize = Context->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
Fobx->Specific.NamedPipe.PipeHandleInformation.TypeOfPipe = Context->Create.PipeType;
Fobx->Specific.NamedPipe.PipeHandleInformation.ReadMode = Context->Create.PipeReadMode;
Fobx->Specific.NamedPipe.PipeHandleInformation.CompletionMode = Context->Create.PipeCompletionMode;
InitializeListHead(&Fobx->Specific.NamedPipe.ReadSerializationQueue);
InitializeListHead(&Fobx->Specific.NamedPipe.WriteSerializationQueue);
}
}
Status = STATUS_SUCCESS;
}
}
_SEH2_FINALLY
{
if (Fcb->OpenCount == 0)
{
if (Context->Create.FcbAcquired)
{
Context->Create.FcbAcquired = (RxDereferenceAndFinalizeNetFcb(Fcb,
Context,
FALSE,
FALSE) == 0);
if (!Context->Create.FcbAcquired)
{
RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
}
}
}
else
{
RxDereferenceNetFcb(Fcb);
}
}
_SEH2_END;
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxCreateTreeConnect(
IN PRX_CONTEXT RxContext)
{
NTSTATUS Status;
PV_NET_ROOT VNetRoot;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
NET_ROOT_TYPE NetRootType;
UNICODE_STRING CanonicalName, RemainingName;
PAGED_CODE();
Stack = RxContext->CurrentIrpSp;
FileObject = Stack->FileObject;
RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
/* As long as we don't know connection type, mark it wild */
NetRootType = NET_ROOT_WILD;
/* Get the type by parsing the name */
Status = RxFirstCanonicalize(RxContext, &FileObject->FileName, &CanonicalName, &NetRootType);
if (!NT_SUCCESS(Status))
{
return Status;
}
RxContext->Create.ThisIsATreeConnectOpen = TRUE;
RxContext->Create.TreeConnectOpenDeferred = FALSE;
RtlInitEmptyUnicodeString(&RxContext->Create.TransportName, NULL, 0);
RtlInitEmptyUnicodeString(&RxContext->Create.UserName, NULL, 0);
RtlInitEmptyUnicodeString(&RxContext->Create.Password, NULL, 0);
RtlInitEmptyUnicodeString(&RxContext->Create.UserDomainName, NULL, 0);
/* We don't handle EA - they come from DFS, don't care */
if (Stack->Parameters.Create.EaLength > 0)
{
UNIMPLEMENTED;
}
/* Mount if required */
Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT)
{
RxScavengeVNetRoots(RxContext->RxDeviceObject);
Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
}
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Validate the rest of the name with mini-rdr */
if (RemainingName.Length > 0)
{
MINIRDR_CALL(Status, RxContext,
RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
MRxIsValidDirectory, (RxContext, &RemainingName));
}
if (!NT_SUCCESS(Status))
{
return Status;
}
VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
RxReferenceVNetRoot(VNetRoot);
if (InterlockedCompareExchange(&VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0)
{
RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
}
FileObject->FsContext = &RxDeviceFCB;
FileObject->FsContext2 = VNetRoot;
VNetRoot->ConstructionStatus = STATUS_SUCCESS;
++VNetRoot->NumberOfOpens;
/* Create is over - clear context */
RxContext->Create.pSrvCall = NULL;
RxContext->Create.pNetRoot = NULL;
RxContext->Create.pVNetRoot = NULL;
return Status;
}
VOID
NTAPI
RxDebugControlCommand(
_In_ PSTR ControlString)
{
UNIMPLEMENTED;
}
NTSTATUS
NTAPI
RxDriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
NTSTATUS Status;
USHORT i, State = 0;
DPRINT("RxDriverEntry(%p, %p)\n", DriverObject, RegistryPath);
_SEH2_TRY
{
RxCheckFcbStructuresForAlignment();
RtlZeroMemory(&RxData, sizeof(RxData));
RxData.NodeTypeCode = RDBSS_NTC_DATA_HEADER;
RxData.NodeByteSize = sizeof(RxData);
RxData.DriverObject = DriverObject;
RtlZeroMemory(&RxDeviceFCB, sizeof(RxDeviceFCB));
RxDeviceFCB.spacer.NodeTypeCode = RDBSS_NTC_DEVICE_FCB;
RxDeviceFCB.spacer.NodeByteSize = sizeof(RxDeviceFCB);
KeInitializeSpinLock(&RxStrucSupSpinLock);
RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
RxInitializeDebugSupport();
RxFileSystemDeviceObject = (PRDBSS_DEVICE_OBJECT)&RxSpaceForTheWrappersDeviceObject;
RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject, sizeof(RxSpaceForTheWrappersDeviceObject));
RxInitializeLog();
State = 2;
RxGetRegistryParameters(RegistryPath);
RxReadRegistryParameters();
Status = RxInitializeRegistrationStructures();
if (!NT_SUCCESS(Status))
{
_SEH2_LEAVE;
}
State = 1;
RxInitializeDispatcher();
ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
InitializeListHead(&RxIrpsList);
KeInitializeSpinLock(&RxIrpsListSpinLock);
InitializeListHead(&RxActiveContexts);
InitializeListHead(&RxSrvCalldownList);
ExInitializeFastMutex(&RxContextPerFileSerializationMutex);
ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex);
KeInitializeMutex(&RxScavengerMutex, 1);
KeInitializeMutex(&RxSerializationMutex, 1);
for (i = 0; i < RxMaximumWorkQueue; ++i)
{
RxFileSystemDeviceObject->PostedRequestCount[i] = 0;
RxFileSystemDeviceObject->OverflowQueueCount[i] = 0;
InitializeListHead(&RxFileSystemDeviceObject->OverflowQueue[i]);
}
KeInitializeSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock);
RxInitializeDispatchVectors(DriverObject);
ExInitializeResourceLite(&RxData.Resource);
RxData.OurProcess = IoGetCurrentProcess();
RxInitializeRxTimer();
}
_SEH2_FINALLY
{
if (!NT_SUCCESS(Status))
{
RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BC4, Status);
RxInitUnwind(DriverObject, State);
}
} _SEH2_END;
/* There are still bits to init - be consider it's fine for now */
#if 0
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
#else
return STATUS_SUCCESS;
#endif
}
#if DBG
/*
* @implemented
*/
VOID
RxDumpCurrentAccess(
_In_ PSZ where1,
_In_ PSZ where2,
_In_ PSZ wherelogtag,
_In_ PSHARE_ACCESS ShareAccess)
{
PAGED_CODE();
}
/*
* @implemented
*/
VOID
RxDumpWantedAccess(
_In_ PSZ where1,
_In_ PSZ where2,
_In_ PSZ wherelogtag,
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG DesiredShareAccess)
{
PAGED_CODE();
}
#endif
/*
* @implemented
*/
BOOLEAN
NTAPI
RxFastIoCheckIfPossible(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length, BOOLEAN Wait,
ULONG LockKey, BOOLEAN CheckForReadOperation,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
[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
PFCB Fcb;
PSRV_OPEN SrvOpen;
LARGE_INTEGER LargeLength;
[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
PAGED_CODE();
/* Get the FCB to validate it */
Fcb = FileObject->FsContext;
if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
{
DPRINT1("Not a file, FastIO not possible!\n");
return FALSE;
}
if (FileObject->DeletePending)
{
DPRINT1("File delete pending\n");
return FALSE;
}
/* If there's a pending write operation, deny fast operation */
if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
{
DPRINT1("Write operations to be completed\n");
return FALSE;
}
/* Deny read on orphaned node */
SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
{
DPRINT1("SRV_OPEN orphaned\n");
return FALSE;
}
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
{
DPRINT1("FCB orphaned\n");
return FALSE;
}
/* If there's a buffering state change pending, deny fast operation (it might change
* cache status)
*/
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
{
DPRINT1("Buffering change pending\n");
return FALSE;
}
/* File got renamed/deleted, deny operation */
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
{
DPRINT1("File renamed/deleted\n");
return FALSE;
}
/* Process pending change buffering state operations */
FsRtlEnterFileSystem();
RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
FsRtlExitFileSystem();
LargeLength.QuadPart = Length;
[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
/* If operation to come is a read operation */
if (CheckForReadOperation)
{
/* Check that read cache is enabled */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
{
DPRINT1("Read caching disabled\n");
return FALSE;
}
/* Check whether there's a lock conflict */
if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
FileOffset,
&LargeLength,
LockKey,
FileObject,
PsGetCurrentProcess()))
{
DPRINT1("FsRtlFastCheckLockForRead failed\n");
return FALSE;
}
return TRUE;
}
/* Check that write cache is enabled */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED))
{
DPRINT1("Write caching disabled\n");
return FALSE;
}
/* Check whether there's a lock conflict */
if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock,
FileOffset,
&LargeLength,
LockKey,
FileObject,
PsGetCurrentProcess()))
{
DPRINT1("FsRtlFastCheckLockForWrite failed\n");
return FALSE;
}
return TRUE;
}
BOOLEAN
NTAPI
RxFastIoDeviceControl(
PFILE_OBJECT FileObject,
BOOLEAN Wait,
PVOID InputBuffer OPTIONAL,
ULONG InputBufferLength,
PVOID OutputBuffer OPTIONAL,
ULONG OutputBufferLength,
ULONG IoControlCode,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
/* Only supported IOCTL */
if (IoControlCode == IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
{
UNIMPLEMENTED;
return FALSE;
}
else
{
return FALSE;
}
}
[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
/*
* @implemented
*/
BOOLEAN
NTAPI
RxFastIoRead(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length,
BOOLEAN Wait,
ULONG LockKey,
PVOID Buffer,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
[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
BOOLEAN Ret;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PAGED_CODE();
DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
FileObject->FsContext2);
DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
/* Prepare a TLI context */
ASSERT(RxIsThisTheTopLevelIrp(NULL));
RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
(PRDBSS_DEVICE_OBJECT)DeviceObject);
Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
IoStatus, DeviceObject, &TopLevelContext);
if (Ret)
{
DPRINT("Read OK\n");
}
else
{
DPRINT1("Read failed!\n");
}
return Ret;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
RxFastIoWrite(
PFILE_OBJECT FileObject,
PLARGE_INTEGER FileOffset,
ULONG Length,
BOOLEAN Wait,
ULONG LockKey,
PVOID Buffer,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
PFOBX Fobx;
BOOLEAN Ret;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PAGED_CODE();
Fobx = (PFOBX)FileObject->FsContext2;
if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE))
{
return FALSE;
}
DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext,
FileObject->FsContext2);
DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
/* Prepare a TLI context */
ASSERT(RxIsThisTheTopLevelIrp(NULL));
RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
(PRDBSS_DEVICE_OBJECT)DeviceObject);
Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
IoStatus, DeviceObject, &TopLevelContext);
if (Ret)
{
DPRINT("Write OK\n");
}
else
{
DPRINT1("Write failed!\n");
}
return Ret;
}
NTSTATUS
RxFindOrCreateFcb(
PRX_CONTEXT RxContext,
PUNICODE_STRING NetRootName)
{
PFCB Fcb;
ULONG Version;
NTSTATUS Status;
PNET_ROOT NetRoot;
PV_NET_ROOT VNetRoot;
BOOLEAN TableAcquired, AcquiredExclusive;
PAGED_CODE();
NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
ASSERT(NetRoot == VNetRoot->NetRoot);
Status = STATUS_SUCCESS;
AcquiredExclusive = FALSE;
RxAcquireFcbTableLockShared(&NetRoot->FcbTable, TRUE);
TableAcquired = TRUE;
Version = NetRoot->FcbTable.Version;
/* Look for a cached FCB */
Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
if (Fcb == NULL)
{
DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName);
}
else
{
DPRINT("FCB found for %wZ\n", &Fcb->FcbTableEntry.Path);
/* If FCB was to be orphaned, consider it as not suitable */
if (Fcb->fShouldBeOrphaned)
{
RxDereferenceNetFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
TableAcquired = TRUE;
AcquiredExclusive = TRUE;
Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
if (Fcb != NULL && Fcb->fShouldBeOrphaned)
{
RxOrphanThisFcb(Fcb);
RxDereferenceNetFcb(Fcb);
Fcb = NULL;
}
}
}
/* If FCB was not found or is not covering full path, prepare for more work */
if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
{
if (Fcb != NULL)
{
DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb->FcbTableEntry.Path, NetRootName);
}
if (!AcquiredExclusive)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
TableAcquired = TRUE;
}
/* If FCB table was updated in between, re-attempt a lookup */
if (NetRoot->FcbTable.Version != Version)
{
Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
{
Fcb = NULL;
}
}
}
/* Allocate the FCB */
_SEH2_TRY
{
if (Fcb == NULL)
{
Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName);
if (Fcb == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
}
}
}
_SEH2_FINALLY
{
if (_SEH2_AbnormalTermination())
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
TableAcquired = FALSE;
if (Fcb != NULL)
{
RxTransitionNetFcb(Fcb, Condition_Bad);
ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0)
{
ExReleaseResourceLite(Fcb->Header.Resource);
}
}
}
}
_SEH2_END;
if (TableAcquired)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
}
if (!NT_SUCCESS(Status))
{
return Status;
}
RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
if (!RxContext->Create.FcbAcquired)
{
RxWaitForStableNetFcb(Fcb, RxContext);
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
}
return Status;
}
NTSTATUS
RxFirstCanonicalize(
PRX_CONTEXT RxContext,
PUNICODE_STRING FileName,
PUNICODE_STRING CanonicalName,
PNET_ROOT_TYPE NetRootType)
{
NTSTATUS Status;
NET_ROOT_TYPE Type;
BOOLEAN UncName, PrependString, IsSpecial;
USHORT CanonicalLength;
UNICODE_STRING SessionIdString;
WCHAR SessionIdBuffer[16];
PAGED_CODE();
Type = NET_ROOT_WILD;
PrependString = FALSE;
IsSpecial = FALSE;
UncName = FALSE;
Status = STATUS_SUCCESS;
/* Name has to contain at least \\ */
if (FileName->Length < 2 * sizeof(WCHAR))
{
return STATUS_OBJECT_NAME_INVALID;
}
/* First easy check, is that a path with a name? */
CanonicalLength = FileName->Length;
if (FileName->Length > 5 * sizeof(WCHAR))
{
if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';')
{
if (FileName->Buffer[3] == ':')
{
Type = NET_ROOT_DISK;
}
else
{
Type = NET_ROOT_PRINT;
}
}
}
/* Nope, attempt deeper parsing */
if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';')
{
ULONG SessionId;
PWSTR FirstSlash, EndOfString;
SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME);
UncName = TRUE;
/* The lack of drive letter will be replaced by session ID */
SessionId = RxGetSessionId(RxContext->CurrentIrpSp);
RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer));
RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
EndOfString = Add2Ptr(FileName->Buffer, FileName->Length);
for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash)
{
if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR)
{
break;
}
}
if (EndOfString - FirstSlash <= sizeof(WCHAR))
{
Status = STATUS_OBJECT_NAME_INVALID;
}
else
{
UNIMPLEMENTED;
DPRINT1("WARNING: Assuming not special + disk!\n");
Type = NET_ROOT_DISK;
Status = STATUS_SUCCESS;
//Status = STATUS_NOT_IMPLEMENTED;
/* Should be check against IPC, mailslot, and so on */
}
}
/* Update net root type with our deduced one */
*NetRootType = Type;
DPRINT("Returning type: %x\n", Type);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Do we have to prepend session ID? */
if (UncName)
{
if (!IsSpecial)
{
PrependString = TRUE;
CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR);
}
}
/* If not UNC path, we should preprend stuff */
if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\')
{
return STATUS_OBJECT_PATH_INVALID;
}
/* Allocate the buffer */
Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* We don't support that case, we always return disk */
if (IsSpecial)
{
ASSERT(CanonicalName->Length == CanonicalLength);
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
}
else
{
/* If we have to prepend, go ahead */
if (PrependString)
{
CanonicalName->Buffer[0] = '\\';
CanonicalName->Buffer[1] = ';';
CanonicalName->Buffer[2] = ':';
CanonicalName->Length = 3 * sizeof(WCHAR);
RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString);
RtlAppendUnicodeStringToString(CanonicalName, FileName);
DPRINT1("CanonicalName: %wZ\n", CanonicalName);
}
/* Otherwise, that's a simple copy */
else
{
RtlCopyUnicodeString(CanonicalName, FileName);
}
}
return Status;
}
/*
* @implemented
*/
VOID
RxFreeCanonicalNameBuffer(
PRX_CONTEXT Context)
{
/* These two buffers are always the same */
ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
if (Context->Create.CanonicalNameBuffer != NULL)
{
RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
Context->Create.CanonicalNameBuffer = NULL;
Context->AlsoCanonicalNameBuffer = NULL;
}
ASSERT(Context->AlsoCanonicalNameBuffer == NULL);
}
NTSTATUS
RxFsdCommonDispatch(
PRX_FSD_DISPATCH_VECTOR DispatchVector,
UCHAR MajorFunction,
PIO_STACK_LOCATION Stack,
PFILE_OBJECT FileObject,
PIRP Irp,
PRDBSS_DEVICE_OBJECT RxDeviceObject)
{
KIRQL OldIrql;
NTSTATUS Status;
PRX_CONTEXT Context;
UCHAR MinorFunction;
PFILE_OBJECT StackFileObject;
PRX_FSD_DISPATCH DispatchFunc;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
Status = STATUS_SUCCESS;
DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
FsRtlEnterFileSystem();
TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
_SEH2_TRY
{
CanWait = TRUE;
Closing = FALSE;
PostRequest = FALSE;
SetCancelRoutine = TRUE;
MinorFunction = Stack->MinorFunction;
/* Can we wait? */
switch (MajorFunction)
{
case IRP_MJ_FILE_SYSTEM_CONTROL:
if (FileObject != NULL)
{
CanWait = IoIsOperationSynchronous(Irp);
}
else
{
CanWait = TRUE;
}
break;
case IRP_MJ_READ:
case IRP_MJ_WRITE:
case IRP_MJ_QUERY_INFORMATION:
case IRP_MJ_SET_INFORMATION:
case IRP_MJ_QUERY_EA:
case IRP_MJ_SET_EA:
case IRP_MJ_FLUSH_BUFFERS:
case IRP_MJ_QUERY_VOLUME_INFORMATION:
case IRP_MJ_SET_VOLUME_INFORMATION:
case IRP_MJ_DIRECTORY_CONTROL:
case IRP_MJ_DEVICE_CONTROL:
case IRP_MJ_LOCK_CONTROL:
case IRP_MJ_QUERY_SECURITY:
case IRP_MJ_SET_SECURITY:
CanWait = IoIsOperationSynchronous(Irp);
break;
case IRP_MJ_CLOSE:
case IRP_MJ_CLEANUP:
Closing = TRUE;
SetCancelRoutine = FALSE;
break;
default:
break;
}
KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
/* Should we stop it right now, or mini-rdr deserves to know? */
PassToDriver = TRUE;
if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE)
{
if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing)
{
PassToDriver = FALSE;
Status = STATUS_REDIRECTOR_NOT_STARTED;
DPRINT1("Not started!\n");
}
}
else
{
if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL))
{
PassToDriver = FALSE;
Status = STATUS_REDIRECTOR_NOT_STARTED;
DPRINT1("Not started!\n");
}
}
KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
StackFileObject = Stack->FileObject;
/* Make sure we don't deal with orphaned stuff */
if (StackFileObject != NULL && StackFileObject->FsContext != NULL)
{
if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) &&
StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
StackFileObject->FsContext != &RxDeviceFCB)
{
PFCB Fcb;
PFOBX Fobx;
Fcb = StackFileObject->FsContext;
Fobx = StackFileObject->FsContext2;
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) ||
((Fobx != NULL) && BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED)))
{
if (Closing)
{
PassToDriver = TRUE;
}
else
{
PassToDriver = FALSE;
Status = STATUS_UNEXPECTED_NETWORK_ERROR;
DPRINT1("Operation on orphaned FCB: %p\n", Fcb);
}
}
}
}
/* Did we receive a close request whereas we're stopping? */
if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing)
{
PFCB Fcb;
Fcb = StackFileObject->FsContext;
DPRINT1("Close received after stop\n");
DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
if (Fcb != NULL && Fcb != &RxDeviceFCB &&
NodeTypeIsFcb(Fcb))
{
DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path);
}
}
/* Should we stop the whole thing now? */
if (!PassToDriver)
{
if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE)
{
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
Status = STATUS_PENDING;
}
else
{
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
_SEH2_LEAVE;
}
/* No? Allocate a context to deal with the mini-rdr */
Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0));
if (Context == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES);
_SEH2_LEAVE;
}
/* Set cancel routine if required */
if (SetCancelRoutine)
{
IoAcquireCancelSpinLock(&OldIrql);
IoSetCancelRoutine(Irp, RxCancelRoutine);
}
else
{
IoAcquireCancelSpinLock(&OldIrql);
IoSetCancelRoutine(Irp, NULL);
}
IoReleaseCancelSpinLock(OldIrql);
ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
/* Get the dispatch routine */
DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE)
{
/* Handle the complete MDL case */
if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE))
{
DispatchFunc = RxCompleteMdl;
}
else
{
/* Do we have to post request? */
if (BooleanFlagOn(MinorFunction, IRP_MN_DPC))
{
PostRequest = TRUE;
}
else
{
/* Our read function needs stack, make sure we won't overflow,
* otherwise, post the request
*/
if (MajorFunction == IRP_MJ_READ)
{
if (IoGetRemainingStackSize() < 0xE00)
{
Context->PendingReturned = TRUE;
Status = RxPostStackOverflowRead(Context);
if (Status != STATUS_PENDING)
{
Context->PendingReturned = FALSE;
RxCompleteAsynchronousRequest(Context, Status);
}
_SEH2_LEAVE;
}
}
}
}
}
Context->ResumeRoutine = DispatchFunc;
/* There's a dispatch routine? Time to dispatch! */
if (DispatchFunc != NULL)
{
Context->PendingReturned = TRUE;
if (PostRequest)
{
Status = RxFsdPostRequest(Context);
}
else
{
/* Retry as long as we have */
do
{
Status = DispatchFunc(Context);
}
while (Status == STATUS_RETRY);
if (Status == STATUS_PENDING)
{
_SEH2_LEAVE;
}
/* Sanity check: did someone mess with our context? */
if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack ||
Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction)
{
DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context);
DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp);
DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack);
DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction);
DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction);
}
Context->PendingReturned = FALSE;
Status = RxCompleteAsynchronousRequest(Context, Status);
}
}
else
{
Status = STATUS_NOT_IMPLEMENTED;
}
}
_SEH2_FINALLY
{
if (TopLevel)
{
RxUnwindTopLevelIrp(&TopLevelContext);
}
FsRtlExitFileSystem();
}
_SEH2_END;
DPRINT("RxFsdDispatch, Status: %lx\n", Status);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxFsdDispatch(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN PIRP Irp)
{
PFCB Fcb;
PIO_STACK_LOCATION Stack;
PRX_FSD_DISPATCH_VECTOR DispatchVector;
PAGED_CODE();
DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Dispatch easy case */
if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
{
return RxSystemControl(RxDeviceObject, Irp);
}
/* Bail out broken cases */
if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ||
Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE)
{
IoMarkIrpPending(Irp);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_PENDING;
}
/* Immediately handle create */
if (Stack->MajorFunction == IRP_MJ_CREATE)
{
return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
}
/* If not a creation, we must have at least a FO with a FCB */
if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL)
{
IoMarkIrpPending(Irp);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_PENDING;
}
/* Set the dispatch vector if required */
Fcb = Stack->FileObject->FsContext;
if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL)
{
DispatchVector = &RxFsdDispatchVector[0];
}
else
{
DispatchVector = Fcb->PrivateDispatchVector;
}
/* Device cannot accept such requests */
if (RxDeviceObject == RxFileSystemDeviceObject)
{
IoMarkIrpPending(Irp);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_PENDING;
}
/* Dispatch for real! */
return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
}
/*
* @implemented
*/
NTSTATUS
RxFsdPostRequest(
IN PRX_CONTEXT RxContext)
{
/* Initialize posting if required */
if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
{
RxPrePostIrp(RxContext, RxContext->CurrentIrp);
}
DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
RxContext->MinorFunction, RxContext,
RxContext->CurrentIrp, RxContext->LastExecutionThread,
RxContext->SerialNumber);
RxAddToWorkque(RxContext, RxContext->CurrentIrp);
return STATUS_PENDING;
}
/*
* @implemented
*/
VOID
NTAPI
RxFspDispatch(
IN PVOID Context)
{
KIRQL EntryIrql;
WORK_QUEUE_TYPE Queue;
PRDBSS_DEVICE_OBJECT VolumeDO;
PRX_CONTEXT RxContext, EntryContext;
PAGED_CODE();
RxContext = Context;
EntryContext = Context;
/* Save IRQL at entry for later checking */
EntryIrql = KeGetCurrentIrql();
/* No FO, deal with device */
if (RxContext->CurrentIrpSp->FileObject != NULL)
{
VolumeDO = RxFileSystemDeviceObject;
}
else
{
VolumeDO = NULL;
}
/* Which queue to used for delayed? */
if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE))
{
Queue = DelayedWorkQueue;
}
else
{
ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
Queue = CriticalWorkQueue;
}
do
{
PIRP Irp;
NTSTATUS Status;
BOOLEAN RecursiveCall;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
ASSERT(!RxContext->PostRequest);
RxContext->LastExecutionThread = PsGetCurrentThread();
SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext->MinorFunction,
RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
RxContext->SerialNumber);
Irp = RxContext->CurrentIrp;
FsRtlEnterFileSystem();
RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
RxTryToBecomeTheTopLevelIrp(&TopLevelContext,
(RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp),
RxContext->RxDeviceObject, TRUE);
ASSERT(RxContext->ResumeRoutine != NULL);
if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL)
{
ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ));
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
}
/* Call the resume routine */
do
{
BOOLEAN NoComplete;
NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
Status = RxContext->ResumeRoutine(RxContext);
if (!NoComplete && Status != STATUS_PENDING)
{
if (Status != STATUS_RETRY)
{
Status = RxCompleteRequest(RxContext, Status);
}
}
}
while (Status == STATUS_RETRY);
RxUnwindTopLevelIrp(&TopLevelContext);
FsRtlExitFileSystem();
if (VolumeDO != NULL)
{
RxContext = RxRemoveOverflowEntry(VolumeDO, Queue);
}
else
{
RxContext = NULL;
}
} while (RxContext != NULL);
/* Did we mess with IRQL? */
if (KeGetCurrentIrql() >= APC_LEVEL)
{
DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql);
}
}
/*
* @implemented
*/
ULONG
RxGetNetworkProviderPriority(
PUNICODE_STRING DeviceName)
{
PAGED_CODE();
return 1;
}
/*
* @implemented
*/
VOID
NTAPI
RxGetRegistryParameters(
IN PUNICODE_STRING RegistryPath)
{
USHORT i;
NTSTATUS Status;
UCHAR Buffer[0x400];
HANDLE DriverHandle, KeyHandle;
UNICODE_STRING KeyName, OutString;
OBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return;
}
RtlInitUnicodeString(&KeyName, L"Parameters");
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE);
Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* The only parameter we deal with is InitialDebugString */
RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0);
if (OutString.Length != 0 && OutString.Length < 0x140)
{
PWSTR Read;
PSTR Write;
Read = OutString.Buffer;
Write = (PSTR)OutString.Buffer;
for (i = 0; i < OutString.Length; ++i)
{
*Read = *Write;
++Write;
*Write = ANSI_NULL;
++Read;
}
/* Which is a string we'll just write out */
DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer);
RxDebugControlCommand((PSTR)OutString.Buffer);
}
ZwClose(KeyHandle);
}
ZwClose(DriverHandle);
}
/*
* @implemented
*/
ULONG
RxGetSessionId(
IN PIO_STACK_LOCATION IrpSp)
{
ULONG SessionId;
PACCESS_TOKEN Token;
PIO_SECURITY_CONTEXT SecurityContext;
PAGED_CODE();
/* If that's not a prefix claim, not an open request, session id will be 0 */
if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH)
{
if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL)
{
return 0;
}
SecurityContext = IrpSp->Parameters.Create.SecurityContext;
}
else
{
SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext;
}
/* Query the session id */
Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext);
SeQuerySessionIdToken(Token, &SessionId);
return SessionId;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxGetStringRegistryParameter(
IN HANDLE KeyHandle,
IN PCWSTR KeyName,
OUT PUNICODE_STRING OutString,
IN PUCHAR Buffer,
IN ULONG BufferLength,
IN BOOLEAN LogFailure)
{
NTSTATUS Status;
ULONG ResultLength;
UNICODE_STRING KeyString;
PAGED_CODE();
RtlInitUnicodeString(&KeyString, KeyName);
Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength);
OutString->Length = 0;
OutString->Buffer = 0;
if (!NT_SUCCESS(Status))
{
if (LogFailure)
{
RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status);
}
return Status;
}
OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL);
OutString->MaximumLength = OutString->Length;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
PRDBSS_DEVICE_OBJECT
RxGetTopDeviceObjectIfRdbssIrp(
VOID)
{
PIRP TopLevelIrp;
PRDBSS_DEVICE_OBJECT TopDevice = NULL;
TopLevelIrp = IoGetTopLevelIrp();
if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
{
TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject;
}
return TopDevice;
}
/*
* @implemented
*/
PIRP
RxGetTopIrpIfRdbssIrp(
VOID)
{
PIRP Irp = NULL;
PRX_TOPLEVELIRP_CONTEXT TopLevel;
TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
if (RxIsThisAnRdbssTopLevelContext(TopLevel))
{
Irp = TopLevel->Irp;
}
return Irp;
}
/*
* @implemented
*/
LUID
RxGetUid(
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
{
LUID Luid;
PACCESS_TOKEN Token;
PAGED_CODE();
Token = SeQuerySubjectContextToken(SubjectSecurityContext);
SeQueryAuthenticationIdToken(Token, &Luid);
return Luid;
}
VOID
NTAPI
RxIndicateChangeOfBufferingStateForSrvOpen(
PMRX_SRV_CALL SrvCall,
PMRX_SRV_OPEN SrvOpen,
PVOID SrvOpenKey,
PVOID Context)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
VOID
NTAPI
RxInitializeDispatchVectors(
PDRIVER_OBJECT DriverObject)
{
USHORT i;
PAGED_CODE();
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
{
DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
}
RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector;
ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
DriverObject->FastIoDispatch = &RxFastIoDispatch;
RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch);
RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
RxFastIoDispatch.FastIoRead = RxFastIoRead;
RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
RxFastIoDispatch.FastIoLock = NULL;
RxFastIoDispatch.FastIoUnlockSingle = NULL;
RxFastIoDispatch.FastIoUnlockAll = NULL;
RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
RxInitializeTopLevelIrpPackage();
RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite;
RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite;
RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead;
RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire;
RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease;
RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire;
RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;
}
NTSTATUS
NTAPI
RxInitializeLog(
VOID)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VOID
RxInitializeMinirdrDispatchTable(
IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxInitializeRegistrationStructures(
VOID)
{
PAGED_CODE();
ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
RxData.NumberOfMinirdrsRegistered = 0;
RxData.NumberOfMinirdrsStarted = 0;
InitializeListHead(&RxData.RegisteredMiniRdrs);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
NTAPI
RxInitializeTopLevelIrpPackage(
VOID)
{
KeInitializeSpinLock(&TopLevelIrpSpinLock);
InitializeListHead(&TopLevelIrpAllocatedContextsList);
}
VOID
NTAPI
RxInitUnwind(
PDRIVER_OBJECT DriverObject,
USHORT State)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
BOOLEAN
RxIsMemberOfTopLevelIrpAllocatedContextsList(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
{
KIRQL OldIrql;
PLIST_ENTRY NextEntry;
BOOLEAN Found = FALSE;
PRX_TOPLEVELIRP_CONTEXT ListContext;
/* Browse all the allocated TLC to find ours */
KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
for (NextEntry = TopLevelIrpAllocatedContextsList.Flink;
NextEntry != &TopLevelIrpAllocatedContextsList;
NextEntry = NextEntry->Flink)
{
ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry);
ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
/* Found! */
if (ListContext == TopLevelContext)
{
Found = TRUE;
break;
}
}
KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
return Found;
}
/*
* @implemented
*/
BOOLEAN
RxIsOkToPurgeFcb(
PFCB Fcb)
{
PLIST_ENTRY Entry;
/* No associated SRV_OPEN, it's OK to purge */
if (IsListEmpty(&Fcb->SrvOpenList))
{
return TRUE;
}
/* Only allow to purge if all the associated SRV_OPEN
* - have no outstanding opens ongoing
* - have only read attribute set
*/
for (Entry = Fcb->SrvOpenList.Flink;
Entry != &Fcb->SrvOpenList;
Entry = Entry->Flink)
{
PSRV_OPEN SrvOpen;
SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
/* Failing previous needs, don't allow purge */
if (SrvOpen->UncleanFobxCount != 0 ||
(SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
{
return FALSE;
}
}
/* All correct, allow purge */
return TRUE;
}
/*
* @implemented
*/
BOOLEAN
RxIsThisAnRdbssTopLevelContext(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
{
ULONG_PTR StackTop, StackBottom;
/* Bail out for flags */
if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP)
{
return FALSE;
}
/* Is our provided TLC allocated on stack? */
IoGetStackLimits(&StackTop, &StackBottom);
if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) &&
(ULONG_PTR)TopLevelContext >= StackTop)
{
/* Yes, so check whether it's really a TLC by checking alignement & signature */
if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)
{
return TRUE;
}
return FALSE;
}
/* No, use the helper function */
return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);
}
/*
* @implemented
*/
BOOLEAN
RxIsThisTheTopLevelIrp(
IN PIRP Irp)
{
PIRP TopLevelIrp;
/* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
TopLevelIrp = IoGetTopLevelIrp();
if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
{
TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp;
}
return (TopLevelIrp == Irp);
}
NTSTATUS
NTAPI
RxLockOperationCompletion(
IN PVOID Context,
IN PIRP Irp)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VOID
NTAPI
RxLogEventDirect(
IN PRDBSS_DEVICE_OBJECT DeviceObject,
IN PUNICODE_STRING OriginatorId,
IN ULONG EventId,
IN NTSTATUS Status,
IN ULONG Line)
{
PUNICODE_STRING Originator = OriginatorId;
LARGE_INTEGER LargeLine;
/* Set optional parameters */
LargeLine.QuadPart = Line;
if (OriginatorId == NULL || OriginatorId->Length == 0)
{
Originator = (PUNICODE_STRING)&unknownId;
}
/* And log */
RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);
}
VOID
NTAPI
RxLogEventWithAnnotation(
IN PRDBSS_DEVICE_OBJECT DeviceObject,
IN ULONG EventId,
IN NTSTATUS Status,
IN PVOID DataBuffer,
IN USHORT DataBufferLength,
IN PUNICODE_STRING Annotation,
IN ULONG AnnotationCount)
{
UNIMPLEMENTED;
}
NTSTATUS
NTAPI
RxLowIoCompletion(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxLowIoIoCtlShellCompletion(
PRX_CONTEXT RxContext)
{
PIRP Irp;
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
Irp = RxContext->CurrentIrp;
Status = RxContext->IoStatusBlock.Status;
/* Set information and status */
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
{
Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
}
Irp->IoStatus.Status = Status;
return Status;
}
NTSTATUS
RxLowIoLockControlShell(
IN PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxLowIoNotifyChangeDirectoryCompletion(
PRX_CONTEXT RxContext)
{
PAGED_CODE();
DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
/* Just copy back the IO_STATUS to the IRP */
RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status);
RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
return RxContext->IoStatusBlock.Status;
}
/*
* @implemented
*/
NTSTATUS
RxLowIoReadShell(
PRX_CONTEXT RxContext)
{
PFCB Fcb;
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoReadShell(%p)\n", RxContext);
Fcb = (PFCB)RxContext->pFcb;
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
{
return STATUS_MORE_PROCESSING_REQUIRED;
}
/* Always update stats for disks */
if (Fcb->CachedNetRootType == NET_ROOT_DISK)
{
ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
}
/* And forward the read to the mini-rdr */
Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion);
DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
return Status;
}
NTSTATUS
NTAPI
RxLowIoReadShellCompletion(
PRX_CONTEXT RxContext)
{
PIRP Irp;
PFCB Fcb;
NTSTATUS Status;
BOOLEAN PagingIo, IsPipe;
PIO_STACK_LOCATION Stack;
PLOWIO_CONTEXT LowIoContext;
PAGED_CODE();
DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
Status = RxContext->IoStatusBlock.Status;
DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
Irp = RxContext->CurrentIrp;
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
/* Set IRP information from the RX_CONTEXT status block */
Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
/* Fixup status for paging file if nothing was read */
if (PagingIo)
{
if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0)
{
Status = STATUS_END_OF_FILE;
}
}
LowIoContext = &RxContext->LowIoContext;
ASSERT(RxLowIoIsBufferLocked(LowIoContext));
/* Check broken cases that should never happen */
Fcb = (PFCB)RxContext->pFcb;
if (Status == STATUS_FILE_LOCK_CONFLICT)
{
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED))
{
ASSERT(FALSE);
return STATUS_RETRY;
}
}
else if (Status == STATUS_SUCCESS)
{
if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
{
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) ||
BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED))
{
ASSERT(FALSE);
}
}
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
{
ASSERT(FALSE);
}
}
/* Readahead should go through Cc and not finish here */
ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
/* If it's sync, RxCommonRead will finish the work - nothing to do here */
if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
{
return Status;
}
Stack = RxContext->CurrentIrpSp;
IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
/* Release lock if required */
if (PagingIo)
{
RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
else
{
/* Set FastIo if read was a success */
if (NT_SUCCESS(Status) && !IsPipe)
{
SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ);
}
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue);
}
else
{
RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
}
if (IsPipe)
{
UNIMPLEMENTED;
}
/* Final sanity checks */
ASSERT(Status != STATUS_RETRY);
ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxLowIoWriteShell(
IN PRX_CONTEXT RxContext)
{
PFCB Fcb;
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
Fcb = (PFCB)RxContext->pFcb;
ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
/* Always update stats for disks */
if (Fcb->CachedNetRootType == NET_ROOT_DISK)
{
ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
}
/* And forward the write to the mini-rdr */
Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion);
DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
return Status;
}
NTSTATUS
NTAPI
RxLowIoWriteShellCompletion(
PRX_CONTEXT RxContext)
{
PIRP Irp;
PFCB Fcb;
NTSTATUS Status;
BOOLEAN PagingIo;
PLOWIO_CONTEXT LowIoContext;
PAGED_CODE();
DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
Status = RxContext->IoStatusBlock.Status;
DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
Irp = RxContext->CurrentIrp;
/* Set IRP information from the RX_CONTEXT status block */
Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
LowIoContext = &RxContext->LowIoContext;
ASSERT(RxLowIoIsBufferLocked(LowIoContext));
/* Perform a few sanity checks */
Fcb = (PFCB)RxContext->pFcb;
if (Status == STATUS_SUCCESS)
{
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED))
{
ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
}
ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED));
}
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
if (Status != STATUS_SUCCESS && PagingIo)
{
DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status);
}
/* In case of async call, perform last bits not done in RxCommonWrite */
if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
{
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
/* We only succeed if we wrote what was asked for */
if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
{
ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount);
}
/* If write succeed, ,also update FILE_OBJECT flags */
Stack = RxContext->CurrentIrpSp;
FileObject = Stack->FileObject;
if (!PagingIo)
{
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
}
if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE))
{
SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
}
/* If VDL was extended, fix attributes */
if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL))
{
LONGLONG LastOffset, FileSize;
LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset +
Irp->IoStatus.Information;
RxGetFileSizeWithLock(Fcb, &FileSize);
if (FileSize < LastOffset)
{
LastOffset = FileSize;
}
Fcb->Header.ValidDataLength.QuadPart = LastOffset;
}
/* One less outstanding write */
if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
PNON_PAGED_FCB NonPagedFcb;
NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
if (NonPagedFcb != NULL)
{
if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites,
-1, &RxStrucSupSpinLock) == 1)
{
KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
}
}
}
/* Release paging resource if acquired */
if (RxContext->FcbPagingIoResourceAcquired)
{
RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
/* Resume blocked operations for pipes */
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
RxResumeBlockedOperations_Serially(RxContext,
&((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue);
}
else
{
/* And release FCB only for files */
if (RxContext->FcbResourceAcquired)
{
RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
}
}
/* Final sanity checks */
ASSERT(Status != STATUS_RETRY);
ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length));
ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
{
UNIMPLEMENTED;
}
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxNotifyChangeDirectory(
PRX_CONTEXT RxContext)
{
PIRP Irp;
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
/* The IRP can abviously wait */
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
/* Initialize its lowio */
RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
_SEH2_TRY
{
/* Lock user buffer */
Stack = RxContext->CurrentIrpSp;
RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
/* Copy parameters from IO_STACK */
RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE);
RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter;
RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
/* If we have an associated MDL */
Irp = RxContext->CurrentIrp;
if (Irp->MdlAddress != NULL)
{
/* Then, call mini-rdr */
RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL)
{
Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion);
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
_SEH2_FINALLY
{
/* All correct */
}
_SEH2_END;
return Status;
}
NTSTATUS
RxPostStackOverflowRead (
IN PRX_CONTEXT RxContext)
{
PAGED_CODE();
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VOID
RxpPrepareCreateContextForReuse(
PRX_CONTEXT RxContext)
{
/* Reuse can only happen for open operations (STATUS_RETRY) */
ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
/* Release the FCB if it was acquired */
if (RxContext->Create.FcbAcquired)
{
RxReleaseFcb(RxContext, RxContext->pFcb);
RxContext->Create.FcbAcquired = FALSE;
}
/* Free the canonical name */
RxFreeCanonicalNameBuffer(RxContext);
/* If we have a VNetRoot associated */
if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL)
{
/* Remove our link and thus, dereference the VNetRoot */
RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE);
if (RxContext->Create.pVNetRoot != NULL)
{
RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE);
RxContext->Create.pVNetRoot = NULL;
}
RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
}
DPRINT("RxContext: %p prepared for reuse\n", RxContext);
}
/*
* @implemented
*/
NTSTATUS
RxpQueryInfoMiniRdr(
PRX_CONTEXT RxContext,
FILE_INFORMATION_CLASS FileInfoClass,
PVOID Buffer)
{
PFCB Fcb;
NTSTATUS Status;
Fcb = (PFCB)RxContext->pFcb;
/* Set the RX_CONTEXT */
RxContext->Info.FileInformationClass = FileInfoClass;
RxContext->Info.Buffer = Buffer;
/* Pass down */
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxPrefixClaim(
IN PRX_CONTEXT RxContext)
{
PIRP Irp;
NTSTATUS Status;
NET_ROOT_TYPE NetRootType;
UNICODE_STRING CanonicalName, FileName, NetRootName;
PAGED_CODE();
Irp = RxContext->CurrentIrp;
/* This has to come from MUP */
if (Irp->RequestorMode == UserMode)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
PQUERY_PATH_REQUEST QueryRequest;
/* Get parameters */
QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
/* Don't overflow allocation */
if (QueryRequest->PathNameLength >= MAXUSHORT - 1)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Forcefully rewrite IRP MJ */
RxContext->MajorFunction = IRP_MJ_CREATE;
/* Fake canon name */
RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Leave;
}
/* Copy the prefix to look for */
RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength);
RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength;
RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
/* Zero the create parameters */
RtlZeroMemory(&RxContext->Create,
FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters));
RxContext->Create.ThisIsATreeConnectOpen = TRUE;
RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext;
}
else
{
/* If not devcontrol, it comes from open, name was already copied */
ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL);
}
/* Canonilize name */
NetRootType = NET_ROOT_WILD;
RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType);
/* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
if (NT_SUCCESS(Status))
{
Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName);
}
if (Status == STATUS_PENDING)
{
return Status;
}
/* Reply to MUP */
if (NT_SUCCESS(Status))
{
PQUERY_PATH_RESPONSE QueryResponse;
/* We accept the length that was canon (minus netroot) */
QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length;
}
Leave:
/* If we reach that point with MJ, reset everything and make IRP being a device control */
if (RxContext->MajorFunction == IRP_MJ_CREATE)
{
if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
{
RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
}
RxpPrepareCreateContextForReuse(RxContext);
RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxPrepareToReparseSymbolicLink(
PRX_CONTEXT RxContext,
BOOLEAN SymbolicLinkEmbeddedInOldPath,
PUNICODE_STRING NewPath,
BOOLEAN NewPathIsAbsolute,
PBOOLEAN ReparseRequired)
{
PWSTR NewBuffer;
USHORT NewLength;
PFILE_OBJECT FileObject;
/* Assume no reparse is required first */
*ReparseRequired = FALSE;
/* Only supported for IRP_MJ_CREATE */
if (RxContext->MajorFunction != IRP_MJ_CREATE)
{
return STATUS_INVALID_PARAMETER;
}
/* If symbolic link is not embedded, and DELETE is specified, fail */
if (!SymbolicLinkEmbeddedInOldPath)
{
/* Excepted if DELETE is the only flag specified, then, open has to succeed
* See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
*/
if (BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, DELETE) &&
BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, ~DELETE))
{
return STATUS_ACCESS_DENIED;
}
}
/* At that point, assume reparse will be required */
*ReparseRequired = TRUE;
/* If new path isn't absolute, it's up to us to make it absolute */
if (!NewPathIsAbsolute)
{
/* The prefix will be \Device\Mup */
NewLength = NewPath->Length + (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL));
NewBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, NewLength,
RX_MISC_POOLTAG);
if (NewBuffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy data for the new path */
RtlMoveMemory(NewBuffer, L"\\Device\\Mup", (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL)));
RtlMoveMemory(Add2Ptr(NewBuffer, (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))),
NewPath->Buffer, NewPath->Length);
}
/* Otherwise, use caller path as it */
else
{
NewLength = NewPath->Length;
NewBuffer = NewPath->Buffer;
}
/* Get the FILE_OBJECT we'll modify */
FileObject = RxContext->CurrentIrpSp->FileObject;
/* Free old path first */
ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
/* And setup new one */
FileObject->FileName.Length = NewLength;
FileObject->FileName.MaximumLength = NewLength;
FileObject->FileName.Buffer = NewBuffer;
/* And set reparse flag */
SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE);
/* Done! */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
RxPrePostIrp(
IN PVOID Context,
IN PIRP Irp)
{
LOCK_OPERATION Lock;
PIO_STACK_LOCATION Stack;
PRX_CONTEXT RxContext = Context;
/* NULL IRP is no option */
if (Irp == NULL)
{
return;
}
/* Check whether preparation was really needed */
if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
{
return;
}
/* Mark the context as prepared */
SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
/* Just lock the user buffer, with the correct length, depending on the MJ */
Lock = IoReadAccess;
Stack = RxContext->CurrentIrpSp;
if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
{
if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
{
if (RxContext->MajorFunction == IRP_MJ_READ)
{
Lock = IoWriteAccess;
}
RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length);
}
}
else
{
if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) ||
RxContext->MajorFunction == IRP_MJ_QUERY_EA)
{
Lock = IoWriteAccess;
RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length);
}
else if (RxContext->MajorFunction == IRP_MJ_SET_EA)
{
RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length);
}
}
/* As it will be posted (async), mark the IRP pending */
IoMarkIrpPending(Irp);
}
/*
* @implemented
*/
NTSTATUS
RxpSetInfoMiniRdr(
PRX_CONTEXT RxContext,
FILE_INFORMATION_CLASS Class)
{
PFCB Fcb;
NTSTATUS Status;
/* Initialize parameters in RX_CONTEXT */
RxContext->Info.FileInformationClass = Class;
RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
/* And call mini-rdr */
Fcb = (PFCB)RxContext->pFcb;
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
return Status;
}
VOID
NTAPI
RxpUnregisterMinirdr(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
{
UNIMPLEMENTED;
}
[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
/*
* @implemented
*/
VOID
RxPurgeNetFcb(
PFCB Fcb,
PRX_CONTEXT LocalContext)
{
NTSTATUS Status;
PAGED_CODE();
/* First, flush */
MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
/* And force close */
RxReleaseFcb(NULL, Fcb);
MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
Status = RxAcquireExclusiveFcb(NULL, Fcb);
ASSERT(Status == STATUS_SUCCESS);
}
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
PFILE_NAME_INFORMATION AltNameInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxQueryBasicInfo(
PRX_CONTEXT RxContext,
PFILE_BASIC_INFORMATION BasicInfo)
{
PAGED_CODE();
DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
/* Simply zero and forward to mini-rdr */
RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION));
return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);
}
NTSTATUS
RxQueryCompressedInfo(
PRX_CONTEXT RxContext,
PFILE_COMPRESSION_INFORMATION CompressionInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxQueryDirectory(
PRX_CONTEXT RxContext)
{
PIRP Irp;
PFCB Fcb;
PFOBX Fobx;
UCHAR Flags;
NTSTATUS Status;
BOOLEAN LockNotGranted;
ULONG Length, FileIndex;
PUNICODE_STRING FileName;
PIO_STACK_LOCATION Stack;
FILE_INFORMATION_CLASS FileInfoClass;
PAGED_CODE();
DPRINT("RxQueryDirectory(%p)\n", RxContext);
/* Get parameters */
Stack = RxContext->CurrentIrpSp;
Length = Stack->Parameters.QueryDirectory.Length;
FileName = Stack->Parameters.QueryDirectory.FileName;
FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass;
DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length,
FileName, FileInfoClass);
Irp = RxContext->CurrentIrp;
Flags = Stack->Flags;
FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
if (FileName != NULL)
{
DPRINT("FileName: %wZ\n", FileName);
}
/* No FOBX: not a standard file/directory */
Fobx = (PFOBX)RxContext->pFobx;
if (Fobx == NULL)
{
return STATUS_OBJECT_NAME_INVALID;
}
/* We can only deal with a disk */
Fcb = (PFCB)RxContext->pFcb;
if (Fcb->pNetRoot->Type != NET_ROOT_DISK)
{
DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type);
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Setup RX_CONTEXT related fields */
RxContext->QueryDirectory.FileIndex = FileIndex;
RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN);
RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY);
RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED);
RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
/* We don't support (yet?) a specific index being set */
if (RxContext->QueryDirectory.IndexSpecified)
{
return STATUS_NOT_IMPLEMENTED;
}
/* Try to lock FCB */
LockNotGranted = TRUE;
if (RxContext->QueryDirectory.InitialQuery)
{
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status != STATUS_LOCK_NOT_GRANTED)
{
if (!NT_SUCCESS(Status))
{
return Status;
}
if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
{
RxContext->QueryDirectory.InitialQuery = FALSE;
RxConvertToSharedFcb(RxContext, Fcb);
}
LockNotGranted = FALSE;
}
}
else
{
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
if (Status != STATUS_LOCK_NOT_GRANTED)
{
if (!NT_SUCCESS(Status))
{
return Status;
}
LockNotGranted = FALSE;
}
}
/* If it failed, post request */
if (LockNotGranted)
{
return RxFsdPostRequest(RxContext);
}
/* This cannot be done on a orphaned directory */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
{
RxReleaseFcb(RxContext, Fcb);
return STATUS_FILE_CLOSED;
}
_SEH2_TRY
{
/* Set index */
if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan)
{
RxContext->QueryDirectory.FileIndex = 0;
}
/* Assume success */
Status = STATUS_SUCCESS;
/* If initial query, prepare FOBX */
if (RxContext->QueryDirectory.InitialQuery)
{
/* We cannot have a template already! */
ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
/* If we have a file name and a correct one, duplicate it in the FOBX */
if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL &&
(FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') &&
(FileName->Length != 12 * sizeof(WCHAR) ||
RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR)))
{
Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
{
/* UNICODE_STRING; length has to be even */
if ((FileName->Length & 1) != 0)
{
Status = STATUS_INVALID_PARAMETER;
RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
}
else
{
Fobx->UnicodeQueryTemplate.Length = FileName->Length;
Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE);
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
/* No name specified, or a match all wildcard? Match everything */
else
{
Fobx->ContainsWildCards = TRUE;
Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate;
Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
}
/* No need for exclusive any longer */
if (NT_SUCCESS(Status))
{
RxConvertToSharedFcb(RxContext, Fcb);
}
}
/* Lock user buffer and forward to mini-rdr */
if (NT_SUCCESS(Status))
{
RxLockUserBuffer(RxContext, IoModifyAccess, Length);
RxContext->Info.FileInformationClass = FileInfoClass;
RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext);
RxContext->Info.Length = Length;
if (RxContext->Info.Buffer != NULL)
{
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext));
}
/* Post if mini-rdr asks to */
if (RxContext->PostRequest)
{
RxFsdPostRequest(RxContext);
}
else
{
Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining;
}
}
}
_SEH2_FINALLY
{
RxReleaseFcb(RxContext, Fcb);
}
_SEH2_END;
return Status;
}
NTSTATUS
RxQueryEaInfo(
PRX_CONTEXT RxContext,
PFILE_EA_INFORMATION EaInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RxQueryInternalInfo(
PRX_CONTEXT RxContext,
PFILE_INTERNAL_INFORMATION InternalInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxQueryNameInfo(
PRX_CONTEXT RxContext,
PFILE_NAME_INFORMATION NameInfo)
{
PFCB Fcb;
PFOBX Fobx;
PAGED_CODE();
DPRINT("RxQueryNameInfo(%p, %p)\n", RxContext, NameInfo);
/* Check we can at least copy name size */
if (RxContext->Info.LengthRemaining < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
{
DPRINT1("Buffer too small: %d\n", RxContext->Info.LengthRemaining);
RxContext->Info.Length = 0;
return STATUS_BUFFER_OVERFLOW;
}
RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
Fcb = (PFCB)RxContext->pFcb;
Fobx = (PFOBX)RxContext->pFobx;
/* Get the UNC name */
RxConjureOriginalName(Fcb, Fobx, &NameInfo->FileNameLength, &NameInfo->FileName[0],
&RxContext->Info.Length, VNetRoot_As_UNC_Name);
/* If RxConjureOriginalName returned a negative len (-1) then output buffer
* was too small, return the appropriate length & status.
*/
if (RxContext->Info.LengthRemaining < 0)
{
DPRINT1("Buffer too small!\n");
RxContext->Info.Length = 0;
return STATUS_BUFFER_OVERFLOW;
}
/* All correct */
return STATUS_SUCCESS;
}
NTSTATUS
RxQueryPipeInfo(
PRX_CONTEXT RxContext,
PFILE_PIPE_INFORMATION PipeInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RxQueryPositionInfo(
PRX_CONTEXT RxContext,
PFILE_POSITION_INFORMATION PositionInfo)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxQueryStandardInfo(
PRX_CONTEXT RxContext,
PFILE_STANDARD_INFORMATION StandardInfo)
{
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
/* Zero output buffer */
RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
Fcb = (PFCB)RxContext->pFcb;
Fobx = (PFOBX)RxContext->pFobx;
/* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
{
return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
}
/* Otherwise, fill what we can already */
Status = STATUS_SUCCESS;
StandardInfo->NumberOfLinks = Fcb->NumberOfLinks;
StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
if (StandardInfo->NumberOfLinks == 0)
{
StandardInfo->NumberOfLinks = 1;
}
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
{
StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart);
}
/* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED))
{
Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
}
else
{
RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION);
}
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
RxReadRegistryParameters(
VOID)
{
NTSTATUS Status;
HANDLE KeyHandle;
ULONG ResultLength;
UCHAR Buffer[0x40];
UNICODE_STRING KeyName, ParamName;
OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
PAGED_CODE();
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return;
}
PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles");
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
}
RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
ULONG Granularity = *(PULONG)PartialInfo->Data;
if (Granularity > 16)
{
Granularity = 16;
}
ReadAheadGranularity = Granularity << PAGE_SHIFT;
}
RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup");
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
}
ZwClose(KeyHandle);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxRegisterMinirdr(
OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
IN OUT PDRIVER_OBJECT DriverObject,
IN PMINIRDR_DISPATCH MrdrDispatch,
IN ULONG Controls,
IN PUNICODE_STRING DeviceName,
IN ULONG DeviceExtensionSize,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics)
{
NTSTATUS Status;
PRDBSS_DEVICE_OBJECT RDBSSDevice;
PAGED_CODE();
if (!DeviceObject)
{
return STATUS_INVALID_PARAMETER;
}
/* Create device object with provided parameters */
Status = IoCreateDevice(DriverObject,
DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT),
DeviceName,
DeviceType,
DeviceCharacteristics,
FALSE,
(PDEVICE_OBJECT *)&RDBSSDevice);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (!RxData.DriverObject)
{
return STATUS_UNSUCCESSFUL;
}
/* Initialize our DO extension */
RDBSSDevice->RDBSSDeviceObject = NULL;
++RxFileSystemDeviceObject->ReferenceCount;
*DeviceObject = RDBSSDevice;
RDBSSDevice->RdbssExports = &RxExports;
RDBSSDevice->Dispatch = MrdrDispatch;
RDBSSDevice->RegistrationControls = Controls;
RDBSSDevice->DeviceName = *DeviceName;
RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
InitializeListHead(&RDBSSDevice->OverflowQueue[0]);
InitializeListHead(&RDBSSDevice->OverflowQueue[1]);
InitializeListHead(&RDBSSDevice->OverflowQueue[2]);
KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock);
RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex);
InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks);
ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
/* Unless mini-rdr explicitly asked not to, initialize dispatch table */
if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH))
{
RxInitializeMinirdrDispatchTable(DriverObject);
}
/* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER))
{
LARGE_INTEGER ScavengerTimeLimit;
RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject;
RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
}
RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
RxRemoveFromTopLevelIrpAllocatedContextsList(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
{
KIRQL OldIrql;
/* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
RemoveEntryList(&TopLevelContext->ListEntry);
KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
}
/*
* @implemented
*/
PRX_CONTEXT
RxRemoveOverflowEntry(
PRDBSS_DEVICE_OBJECT DeviceObject,
WORK_QUEUE_TYPE Queue)
{
KIRQL OldIrql;
PRX_CONTEXT Context;
KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql);
if (DeviceObject->OverflowQueueCount[Queue] <= 0)
{
/* No entries left, nothing to return */
InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]);
Context = NULL;
}
else
{
PLIST_ENTRY Entry;
/* Decrement count */
--DeviceObject->OverflowQueueCount[Queue];
/* Return head */
Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]);
Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry);
ClearFlag(Context->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
Context->OverflowListEntry.Flink = NULL;
}
KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
return Context;
}
#if DBG
[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
/*
* @implemented
*/
VOID
RxRemoveShareAccess(
_Inout_ PFILE_OBJECT FileObject,
_Inout_ PSHARE_ACCESS ShareAccess,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
[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
PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
IoRemoveShareAccess(FileObject, ShareAccess);
RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
}
#endif
[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
/*
* @implemented
*/
VOID
RxRemoveShareAccessPerSrvOpens(
IN OUT PSRV_OPEN SrvOpen)
{
ACCESS_MASK DesiredAccess;
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
PAGED_CODE();
/* Get access that were granted to SRV_OPEN */
DesiredAccess = SrvOpen->DesiredAccess;
ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
DeleteAccess = (DesiredAccess & DELETE) != 0;
/* If any, drop them */
if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
{
BOOLEAN SharedRead;
BOOLEAN SharedWrite;
BOOLEAN SharedDelete;
ULONG DesiredShareAccess;
PSHARE_ACCESS ShareAccess;
ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
DesiredShareAccess = SrvOpen->ShareAccess;
ShareAccess->Readers -= ReadAccess;
ShareAccess->Writers -= WriteAccess;
ShareAccess->Deleters -= DeleteAccess;
ShareAccess->OpenCount--;
SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
ShareAccess->SharedRead -= SharedRead;
ShareAccess->SharedWrite -= SharedWrite;
ShareAccess->SharedDelete -= SharedDelete;
}
}
NTSTATUS
RxSearchForCollapsibleOpen(
PRX_CONTEXT RxContext,
ACCESS_MASK DesiredAccess,
ULONG ShareAccess)
{
PFCB Fcb;
NTSTATUS Status;
PLIST_ENTRY ListEntry;
BOOLEAN ShouldTry, Purged, Scavenged;
PAGED_CODE();
DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
Fcb = (PFCB)RxContext->pFcb;
/* If we're asked to open for backup, don't allow SRV_OPEN reuse */
if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
{
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
RxScavengeRelatedFobxs(Fcb);
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
return STATUS_NOT_FOUND;
}
/* If basic open, ask the mini-rdr if we should try to collapse */
if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN ||
RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF)
{
ShouldTry = TRUE;
if (Fcb->MRxDispatch != NULL)
{
ASSERT(RxContext->pRelevantSrvOpen == NULL);
ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext));
}
}
else
{
ShouldTry = FALSE;
}
if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE))
{
ShouldTry = FALSE;
}
/* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
if (!ShouldTry)
{
if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess)))
{
return STATUS_NOT_FOUND;
}
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
RxScavengeRelatedFobxs(Fcb);
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
return STATUS_NOT_FOUND;
}
/* Only collapse for matching NET_ROOT & disks */
if (Fcb->pNetRoot != RxContext->Create.pNetRoot ||
Fcb->pNetRoot->Type != NET_ROOT_DISK)
{
return STATUS_NOT_FOUND;
}
Purged = FALSE;
Scavenged = FALSE;
Status = STATUS_NOT_FOUND;
TryAgain:
/* Browse all our SRV_OPEN to find the matching one */
for (ListEntry = Fcb->SrvOpenList.Flink;
ListEntry != &Fcb->SrvOpenList;
ListEntry = ListEntry->Flink)
{
PSRV_OPEN SrvOpen;
SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
/* Not the same VNET_ROOT, move to the next one */
if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
{
RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
continue;
}
/* Is there a sharing violation? */
if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess ||
BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED)))
{
if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
{
RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
continue;
}
/* Check against the SRV_OPEN */
Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess);
if (!NT_SUCCESS(Status))
{
break;
}
}
else
{
/* Don't allow collaspse for reparse point opening */
if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT))
{
Purged = TRUE;
Scavenged = TRUE;
Status = STATUS_NOT_FOUND;
break;
}
/* Not readonly? Or bytereange lock disabled? Try to collapse! */
if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY))
{
RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)))
{
/* Is close delayed - great reuse*/
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
{
DPRINT("Delayed close successfull, reusing %p\n", SrvOpen);
InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
}
return STATUS_SUCCESS;
}
Status = STATUS_NOT_FOUND;
break;
}
}
}
/* We browse the whole list and didn't find any matching? NOT_FOUND */
if (ListEntry == &Fcb->SrvOpenList)
{
Status = STATUS_NOT_FOUND;
}
/* Only required access: read attributes? Don't reuse */
if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES)
{
return STATUS_NOT_FOUND;
}
/* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
if (!Scavenged)
{
ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
Scavenged = TRUE;
RxScavengeRelatedFobxs(Fcb);
goto TryAgain;
}
/* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
if (!Purged && RxIsOkToPurgeFcb(Fcb))
{
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
Purged = TRUE;
goto TryAgain;
}
/* If sharing violation, keep track of it */
if (Status == STATUS_SHARING_VIOLATION)
{
RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
}
DPRINT("Status: %x\n", Status);
return Status;
}
NTSTATUS
RxSetAllocationInfo(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxSetBasicInfo(
PRX_CONTEXT RxContext)
{
NTSTATUS Status;
PAGED_CODE();
#define FILE_ATTRIBUTE_VOLUME 0x8
#define VALID_FILE_ATTRIBUTES ( \
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
#define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
/* First of all, call the mini-rdr */
Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation);
/* If it succeed, perform last bits */
if (NT_SUCCESS(Status))
{
PIRP Irp;
PFCB Fcb;
PFOBX Fobx;
PFILE_OBJECT FileObject;
ULONG Attributes, CleanAttr;
PFILE_BASIC_INFORMATION BasicInfo;
Fcb = (PFCB)RxContext->pFcb;
Fobx = (PFOBX)RxContext->pFobx;
Irp = RxContext->CurrentIrp;
BasicInfo = Irp->AssociatedIrp.SystemBuffer;
FileObject = RxContext->CurrentIrpSp->FileObject;
/* If caller provided flags, handle the change */
Attributes = BasicInfo->FileAttributes;
if (Attributes != 0)
{
/* Clean our flags first, with only stuff we support */
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
{
CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY;
}
else
{
CleanAttr = Attributes & VALID_FILE_ATTRIBUTES;
}
/* Handle the temporary mark (set/unset depending on caller) */
if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY))
{
SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
else
{
ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
/* And set new attributes */
Fcb->Attributes = CleanAttr;
}
/* If caller provided a creation time, set it */
if (BasicInfo->CreationTime.QuadPart != 0LL)
{
Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION);
}
/* If caller provided a last access time, set it */
if (BasicInfo->LastAccessTime.QuadPart != 0LL)
{
Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS);
}
/* If caller provided a last write time, set it */
if (BasicInfo->LastWriteTime.QuadPart != 0LL)
{
Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
}
/* If caller provided a last change time, set it */
if (BasicInfo->ChangeTime.QuadPart != 0LL)
{
Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
}
}
/* Done */
return Status;
}
/*
* @implemented
*/
NTSTATUS
RxSetDispositionInfo(
PRX_CONTEXT RxContext)
{
NTSTATUS Status;
PAGED_CODE();
/* First, make the mini-rdr work! */
Status = RxpSetInfoMiniRdr(RxContext, FileDispositionInformation);
/* If it succeed, we'll keep track of the change */
if (NT_SUCCESS(Status))
{
PFCB Fcb;
PFILE_OBJECT FileObject;
PFILE_DISPOSITION_INFORMATION FileDispo;
Fcb = (PFCB)RxContext->pFcb;
FileObject = RxContext->CurrentIrpSp->FileObject;
FileDispo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
/* Caller asks for deletion: mark as delete on close */
if (FileDispo->DeleteFile)
{
SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
FileObject->DeletePending = TRUE;
}
/* Otherwise, clear it */
else
{
ClearFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
FileObject->DeletePending = FALSE;
}
/* Sanitize output */
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS
RxSetEndOfFileInfo(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RxSetPipeInfo(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RxSetPositionInfo(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
RxSetRenameInfo(
PRX_CONTEXT RxContext)
{
ULONG Length;
NTSTATUS Status;
PFCB RenameFcb, Fcb;
PIO_STACK_LOCATION Stack;
PFILE_RENAME_INFORMATION RenameInfo, UserInfo;
PAGED_CODE();
DPRINT("RxSetRenameInfo(%p)\n", RxContext);
Stack = RxContext->CurrentIrpSp;
DPRINT("FO: %p, Replace: %d\n", Stack->Parameters.SetFile.FileObject, Stack->Parameters.SetFile.ReplaceIfExists);
/* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
RxContext->Info.ReplaceIfExists = Stack->Parameters.SetFile.ReplaceIfExists;
if (Stack->Parameters.SetFile.FileObject == NULL)
{
return RxpSetInfoMiniRdr(RxContext, Stack->Parameters.SetFile.FileInformationClass);
}
Fcb = (PFCB)RxContext->pFcb;
RenameFcb = Stack->Parameters.SetFile.FileObject->FsContext;
/* First, validate the received file object */
ASSERT(NodeType(RenameFcb) == RDBSS_NTC_OPENTARGETDIR_FCB);
if (Fcb->pNetRoot != RenameFcb->pNetRoot)
{
DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb, Fcb->pNetRoot, Fcb->pNetRoot->pNetRootName, RenameFcb, RenameFcb->pNetRoot, RenameFcb->pNetRoot->pNetRootName);
return STATUS_NOT_SAME_DEVICE;
}
/* We'll reallocate a safe buffer */
Length = Fcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize + RenameFcb->FcbTableEntry.Path.Length + FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName);
RenameInfo = RxAllocatePoolWithTag(PagedPool, Length, '??xR');
if (RenameInfo == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
_SEH2_TRY
{
/* Copy the data */
UserInfo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
RenameInfo->ReplaceIfExists = UserInfo->ReplaceIfExists;
RenameInfo->RootDirectory = UserInfo->RootDirectory;
RenameInfo->FileNameLength = RenameFcb->FcbTableEntry.Path.Length;
RtlMoveMemory(&RenameInfo->FileName[0], RenameFcb->FcbTableEntry.Path.Buffer, RenameFcb->FcbTableEntry.Path.Length);
/* Set them in the RX_CONTEXT */
RxContext->Info.FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
RxContext->Info.Buffer = RenameInfo;
RxContext->Info.Length = Length;
/* And call the mini-rdr */
MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
}
_SEH2_FINALLY
{
/* Free */
RxFreePoolWithTag(RenameInfo, '??xR');
}
_SEH2_END;
/* Done! */
return Status;
}
#if DBG
/*
* @implemented
*/
VOID
RxSetShareAccess(
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG DesiredShareAccess,
_Inout_ PFILE_OBJECT FileObject,
_Out_ PSHARE_ACCESS ShareAccess,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
}
#endif
NTSTATUS
RxSetSimpleInfo(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
VOID
RxSetupNetFileObject(
PRX_CONTEXT RxContext)
{
PFCB Fcb;
PFOBX Fobx;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PAGED_CODE();
/* Assert FOBX is FOBX or NULL */
Fobx = (PFOBX)RxContext->pFobx;
ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
Fcb = (PFCB)RxContext->pFcb;
Stack = RxContext->CurrentIrpSp;
FileObject = Stack->FileObject;
/* If it's temporary mark FO as such */
if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB &&
BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY))
{
if (FileObject == NULL)
{
return;
}
FileObject->Flags |= FO_TEMPORARY_FILE;
}
/* No FO, nothing to setup */
if (FileObject == NULL)
{
return;
}
/* Assign FCB & CCB (FOBX) to FO */
FileObject->FsContext = Fcb;
FileObject->FsContext2 = Fobx;
if (Fobx != NULL)
{
ULONG_PTR StackTop, StackBottom;
/* If FO is allocated on pool, keep track of it */
IoGetStackLimits(&StackTop, &StackBottom);
if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop)
{
Fobx->AssociatedFileObject = FileObject;
}
else
{
Fobx->AssociatedFileObject = NULL;
}
/* Make sure to mark FOBX if it's a DFS open */
if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))
{
SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
}
else
{
ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
}
}
/* Set Cc pointers */
FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
/* Update access state */
if (Stack->Parameters.Create.SecurityContext != NULL)
{
PACCESS_STATE AccessState;
AccessState = Stack->Parameters.Create.SecurityContext->AccessState;
AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess;
AccessState->RemainingDesiredAccess = 0;
}
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RxStartMinirdr(
IN PRX_CONTEXT RxContext,
OUT PBOOLEAN PostToFsp)
{
NTSTATUS Status;
BOOLEAN Wait, AlreadyStarted;
PRDBSS_DEVICE_OBJECT DeviceObject;
/* If we've not been post, then, do it */
if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
{
SECURITY_SUBJECT_CONTEXT SubjectContext;
SeCaptureSubjectContext(&SubjectContext);
RxContext->FsdUid = RxGetUid(&SubjectContext);
SeReleaseSubjectContext(&SubjectContext);
*PostToFsp = TRUE;
return STATUS_PENDING;
}
/* Acquire all the required locks */
Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait))
{
*PostToFsp = TRUE;
return STATUS_PENDING;
}
if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait))
{
ExReleaseResourceLite(&RxData.Resource);
*PostToFsp = TRUE;
return STATUS_PENDING;
}
AlreadyStarted = FALSE;
DeviceObject = RxContext->RxDeviceObject;
_SEH2_TRY
{
/* MUP handle set, means already registered */
if (DeviceObject->MupHandle != NULL)
{
AlreadyStarted = TRUE;
Status = STATUS_REDIRECTOR_STARTED;
_SEH2_LEAVE;
}
/* If we're asked to register to MUP, then do it */
Status = STATUS_SUCCESS;
if (DeviceObject->RegisterUncProvider)
{
Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle,
&DeviceObject->DeviceName,
DeviceObject->RegisterMailSlotProvider);
}
if (!NT_SUCCESS(Status))
{
DeviceObject->MupHandle = NULL;
_SEH2_LEAVE;
}
/* Register as file system */
IoRegisterFileSystem(&DeviceObject->DeviceObject);
DeviceObject->RegisteredAsFileSystem = TRUE;
/* Inform mini-rdr it has to start */
MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject));
if (NT_SUCCESS(Status))
{
++DeviceObject->StartStopContext.Version;
RxSetRdbssState(DeviceObject, RDBSS_STARTED);
InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
Status = RxInitializeMRxDispatcher(DeviceObject);
}
}
_SEH2_FINALLY
{
if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status))
{
if (!AlreadyStarted)
{
RxUnstart(RxContext, DeviceObject);
}
}
RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
ExReleaseResourceLite(&RxData.Resource);
}
_SEH2_END;
return Status;
}
NTSTATUS
NTAPI
RxStopMinirdr(
IN PRX_CONTEXT RxContext,
OUT PBOOLEAN PostToFsp)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RxSystemControl(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN PIRP Irp)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
BOOLEAN
RxTryToBecomeTheTopLevelIrp(
IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
IN PIRP Irp,
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN BOOLEAN ForceTopLevel
)
{
BOOLEAN FromPool = FALSE;
PAGED_CODE();
/* If not top level, and not have to be, quit */
if (IoGetTopLevelIrp() && !ForceTopLevel)
{
return FALSE;
}
/* If not TLC provider, allocate one */
if (TopLevelContext == NULL)
{
TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
if (TopLevelContext == NULL)
{
return FALSE;
}
FromPool = TRUE;
}
/* Init it */
__RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
if (FromPool)
{
ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
}
/* Make it top level IRP */
IoSetTopLevelIrp((PIRP)TopLevelContext);
return TRUE;
}
#if DBG
/*
* @implemented
*/
VOID
RxUpdateShareAccess(
_Inout_ PFILE_OBJECT FileObject,
_Inout_ PSHARE_ACCESS ShareAccess,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
PAGED_CODE();
RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
IoUpdateShareAccess(FileObject, ShareAccess);
RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
}
#endif
/*
* @implemented
*/
VOID
RxUninitializeCacheMap(
PRX_CONTEXT RxContext,
PFILE_OBJECT FileObject,
PLARGE_INTEGER TruncateSize)
{
PFCB Fcb;
NTSTATUS Status;
CACHE_UNINITIALIZE_EVENT UninitEvent;
PAGED_CODE();
Fcb = FileObject->FsContext;
ASSERT(NodeTypeIsFcb(Fcb));
ASSERT(RxIsFcbAcquiredExclusive(Fcb));
KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE);
CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
/* Always release the FCB before waiting for the uninit event */
RxReleaseFcb(RxContext, Fcb);
KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
/* Re-acquire it afterwards */
Status = RxAcquireExclusiveFcb(RxContext, Fcb);
ASSERT(NT_SUCCESS(Status));
}
VOID
NTAPI
RxUnload(
IN PDRIVER_OBJECT DriverObject)
{
UNIMPLEMENTED;
}
VOID
NTAPI
RxUnlockOperation(
IN PVOID Context,
IN PFILE_LOCK_INFO LockInfo)
{
UNIMPLEMENTED;
}
VOID
RxUnstart(
PRX_CONTEXT Context,
PRDBSS_DEVICE_OBJECT DeviceObject)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
VOID
RxUnwindTopLevelIrp(
IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
{
DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
/* No TLC provided? Ask the system for ours! */
if (TopLevelContext == NULL)
{
TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
if (TopLevelContext == NULL)
{
return;
}
/* In that case, just assert it's really ours */
ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext));
ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
}
ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
ASSERT(TopLevelContext->Thread == PsGetCurrentThread());
/* Restore the previous top level IRP */
IoSetTopLevelIrp(TopLevelContext->Previous);
/* If TLC was allocated from pool, remove it from list and release it */
if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
{
RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
}
}
/*
* @implemented
*/
VOID
RxUpdateShareAccessPerSrvOpens(
IN PSRV_OPEN SrvOpen)
{
ACCESS_MASK DesiredAccess;
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
PAGED_CODE();
/* If already updated, no need to continue */
if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED))
{
return;
}
/* Check if any access wanted */
DesiredAccess = SrvOpen->DesiredAccess;
ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
DeleteAccess = (DesiredAccess & DELETE) != 0;
/* In that case, update it */
if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
{
BOOLEAN SharedRead;
BOOLEAN SharedWrite;
BOOLEAN SharedDelete;
ULONG DesiredShareAccess;
PSHARE_ACCESS ShareAccess;
ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
DesiredShareAccess = SrvOpen->ShareAccess;
SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
ShareAccess->OpenCount++;
ShareAccess->Readers += ReadAccess;
ShareAccess->Writers += WriteAccess;
ShareAccess->Deleters += DeleteAccess;
ShareAccess->SharedRead += SharedRead;
ShareAccess->SharedWrite += SharedWrite;
ShareAccess->SharedDelete += SharedDelete;
}
SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);
}
/*
* @implemented
*/
NTSTATUS
RxXXXControlFileCallthru(
PRX_CONTEXT Context)
{
NTSTATUS Status;
PAGED_CODE();
DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
/* No dispatch table? Nothing to dispatch */
if (Context->RxDeviceObject->Dispatch == NULL)
{
Context->pFobx = NULL;
return STATUS_INVALID_DEVICE_REQUEST;
}
/* Init the lowio context */
Status = RxLowIoPopulateFsctlInfo(Context);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check whether we're consistent: a length means a buffer */
if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) ||
(Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL))
{
return STATUS_INVALID_PARAMETER;
}
/* Forward the call to the mini-rdr */
DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile);
Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context);
if (Status != STATUS_PENDING)
{
Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn;
}
DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information);
return Status;
}