--- /dev/null
+#ifndef _BACKPACK_
+#define _BACKPACK_
+
+typedef struct _THROTTLING_STATE
+{
+ LARGE_INTEGER NextTime;
+ volatile ULONG CurrentIncrement;
+ ULONG MaximumDelay;
+ LARGE_INTEGER Increment;
+ volatile ULONG NumberOfQueries;
+} THROTTLING_STATE, *PTHROTTLING_STATE;
+
+#define RxInitializeThrottlingState(BP, Inc, MaxDelay) \
+{ \
+ if ((Inc) > 0) \
+ { \
+ (BP)->Increment.QuadPart = (Inc) * 10000; \
+ (BP)->MaximumDelay = (MaxDelay) / (Inc); \
+ (BP)->CurrentIncrement = 0; \
+ } \
+}
+
+#endif
--- /dev/null
+#ifndef __BUFFRING_H__
+#define __BUFFRING_H__
+
+typedef struct _RX_BUFFERING_MANAGER_
+{
+ BOOLEAN DispatcherActive;
+ BOOLEAN HandlerInactive;
+ BOOLEAN LastChanceHandlerActive;
+ UCHAR Pad;
+ KSPIN_LOCK SpinLock;
+ volatile LONG CumulativeNumberOfBufferingChangeRequests;
+ LONG NumberOfUnhandledRequests;
+ LONG NumberOfUndispatchedRequests;
+ volatile LONG NumberOfOutstandingOpens;
+ LIST_ENTRY DispatcherList;
+ LIST_ENTRY HandlerList;
+ LIST_ENTRY LastChanceHandlerList;
+ RX_WORK_QUEUE_ITEM DispatcherWorkItem;
+ RX_WORK_QUEUE_ITEM HandlerWorkItem;
+ RX_WORK_QUEUE_ITEM LastChanceHandlerWorkItem;
+ FAST_MUTEX Mutex;
+ LIST_ENTRY SrvOpenLists[1];
+} RX_BUFFERING_MANAGER, *PRX_BUFFERING_MANAGER;
+
+VOID
+RxProcessFcbChangeBufferingStateRequest(
+ _In_ PFCB Fcb);
+
+VOID
+RxCompleteSrvOpenKeyAssociation(
+ _Inout_ PSRV_OPEN SrvOpen);
+
+VOID
+RxInitiateSrvOpenKeyAssociation(
+ _Inout_ PSRV_OPEN SrvOpen);
+
+NTSTATUS
+RxInitializeBufferingManager(
+ _In_ PSRV_CALL SrvCall);
+
+NTSTATUS
+RxPurgeFcbInSystemCache(
+ _In_ PFCB Fcb,
+ _In_ PLARGE_INTEGER FileOffset OPTIONAL,
+ _In_ ULONG Length,
+ _In_ BOOLEAN UninitializeCacheMaps,
+ _In_ BOOLEAN FlushFile);
+
+#endif
--- /dev/null
+#ifndef _FCB_STRUCTS_DEFINED_
+#define _FCB_STRUCTS_DEFINED_
+
+#include "buffring.h"
+
+struct _FCB_INIT_PACKET;
+typedef struct _FCB_INIT_PACKET *PFCB_INIT_PACKET;
+
+typedef struct _SRV_CALL
+{
+ union
+ {
+ MRX_SRV_CALL;
+ struct
+ {
+ MRX_NORMAL_NODE_HEADER spacer;
+ };
+ };
+ BOOLEAN UpperFinalizationDone;
+ RX_PREFIX_ENTRY PrefixEntry;
+ RX_BLOCK_CONDITION Condition;
+ ULONG SerialNumberForEnum;
+ volatile LONG NumberOfCloseDelayedFiles;
+ LIST_ENTRY TransitionWaitList;
+ LIST_ENTRY ScavengerFinalizationList;
+ PURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext;
+ RX_BUFFERING_MANAGER BufferingManager;
+} SRV_CALL, *PSRV_CALL;
+
+typedef struct _NET_ROOT
+{
+ union
+ {
+ MRX_NET_ROOT;
+ struct
+ {
+ MRX_NORMAL_NODE_HEADER spacer;
+ PSRV_CALL SrvCall;
+ };
+ };
+ BOOLEAN UpperFinalizationDone;
+ RX_BLOCK_CONDITION Condition;
+ LIST_ENTRY TransitionWaitList;
+ LIST_ENTRY ScavengerFinalizationList;
+ PURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext;
+ PV_NET_ROOT DefaultVNetRoot;
+ LIST_ENTRY VirtualNetRoots;
+ ULONG NumberOfVirtualNetRoots;
+ ULONG SerialNumberForEnum;
+ RX_PREFIX_ENTRY PrefixEntry;
+ RX_FCB_TABLE FcbTable;
+} NET_ROOT, *PNET_ROOT;
+
+typedef struct _V_NET_ROOT
+{
+ union
+ {
+ MRX_V_NET_ROOT;
+ struct
+ {
+ MRX_NORMAL_NODE_HEADER spacer;
+ PNET_ROOT NetRoot;
+ };
+ };
+ BOOLEAN UpperFinalizationDone;
+ BOOLEAN ConnectionFinalizationDone;
+ RX_BLOCK_CONDITION Condition;
+ volatile LONG AdditionalReferenceForDeleteFsctlTaken;
+ RX_PREFIX_ENTRY PrefixEntry;
+ UNICODE_STRING NamePrefix;
+ ULONG PrefixOffsetInBytes;
+ LIST_ENTRY NetRootListEntry;
+ ULONG SerialNumberForEnum;
+ LIST_ENTRY TransitionWaitList;
+ LIST_ENTRY ScavengerFinalizationList;
+} V_NET_ROOT, *PV_NET_ROOT;
+
+typedef struct _NON_PAGED_FCB
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ SECTION_OBJECT_POINTERS SectionObjectPointers;
+ ERESOURCE HeaderResource;
+ ERESOURCE PagingIoResource;
+#ifdef USE_FILESIZE_LOCK
+ FAST_MUTEX FileSizeLock;
+#endif
+ LIST_ENTRY TransitionWaitList;
+ ULONG OutstandingAsyncWrites;
+ PKEVENT OutstandingAsyncEvent;
+ KEVENT TheActualEvent;
+ PVOID MiniRdrContext[2];
+ FAST_MUTEX AdvancedFcbHeaderMutex;
+ ERESOURCE BufferedLocksResource;
+#if DBG
+ PFCB FcbBackPointer;
+#endif
+} NON_PAGED_FCB, *PNON_PAGED_FCB;
+
+typedef enum _RX_FCBTRACKER_CASES
+{
+ RX_FCBTRACKER_CASE_NORMAL,
+ RX_FCBTRACKER_CASE_NULLCONTEXT,
+ RX_FCBTRACKER_CASE_CBS_CONTEXT,
+ RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT,
+ RX_FCBTRACKER_CASE_MAXIMUM
+} RX_FCBTRACKER_CASES;
+
+typedef struct _FCB_LOCK
+{
+ struct _FCB_LOCK * Next;
+ LARGE_INTEGER Length;
+ LARGE_INTEGER BytesOffset;
+ ULONG Key;
+ BOOLEAN ExclusiveLock;
+} FCB_LOCK, *PFCB_LOCK;
+
+typedef struct _FCB_BUFFERED_LOCKS
+{
+ struct _FCB_LOCK * List;
+ volatile ULONG PendingLockOps;
+ PERESOURCE Resource;
+} FCB_BUFFERED_LOCKS, *PFCB_BUFFERED_LOCKS;
+
+typedef struct _FCB
+{
+ union
+ {
+ MRX_FCB;
+ struct
+ {
+ FSRTL_ADVANCED_FCB_HEADER spacer;
+ PNET_ROOT NetRoot;
+ };
+ };
+ PV_NET_ROOT VNetRoot;
+ PNON_PAGED_FCB NonPaged;
+ LIST_ENTRY ScavengerFinalizationList;
+ PKEVENT pBufferingStateChangeCompletedEvent;
+ LONG NumberOfBufferingStateChangeWaiters;
+ RX_FCB_TABLE_ENTRY FcbTableEntry;
+ UNICODE_STRING PrivateAlreadyPrefixedName;
+ BOOLEAN UpperFinalizationDone;
+ RX_BLOCK_CONDITION Condition;
+ PRX_FSD_DISPATCH_VECTOR PrivateDispatchVector;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PMINIRDR_DISPATCH MRxDispatch;
+ PFAST_IO_DISPATCH MRxFastIoDispatch;
+ PSRV_OPEN InternalSrvOpen;
+ PFOBX InternalFobx;
+ SHARE_ACCESS ShareAccess;
+ SHARE_ACCESS ShareAccessPerSrvOpens;
+ ULONG NumberOfLinks;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER LastChangeTime;
+#if (_WIN32_WINNT < 0x0600)
+ PETHREAD CreateSectionThread;
+#endif
+ ULONG ulFileSizeVersion;
+#if (_WIN32_WINNT < 0x0600)
+ union
+ {
+ struct
+ {
+#endif
+ FILE_LOCK FileLock;
+#if (_WIN32_WINNT < 0x0600)
+ PVOID LazyWriteThread;
+#endif
+ union
+ {
+ LOWIO_PER_FCB_INFO;
+ LOWIO_PER_FCB_INFO LowIoPerFcbInfo;
+ };
+#ifdef USE_FILESIZE_LOCK
+ PFAST_MUTEX FileSizeLock;
+#endif
+#if (_WIN32_WINNT < 0x0600)
+ } Fcb;
+ } Specific;
+#endif
+ ULONG EaModificationCount;
+ FCB_BUFFERED_LOCKS BufferedLocks;
+#if DBG
+ PNON_PAGED_FCB CopyOfNonPaged;
+#endif
+#ifdef RDBSS_TRACKER
+ ULONG FcbAcquires[RX_FCBTRACKER_CASE_MAXIMUM];
+ ULONG FcbReleases[RX_FCBTRACKER_CASE_MAXIMUM];
+#else
+#error tracker must be defined
+#endif
+ PCHAR PagingIoResourceFile;
+ ULONG PagingIoResourceLine;
+} FCB, *PFCB;
+
+#define FCB_STATE_DELETE_ON_CLOSE 0x00000001
+#define FCB_STATE_PAGING_FILE 0x00000004
+#define FCB_STATE_DISABLE_LOCAL_BUFFERING 0x00000010
+#define FCB_STATE_TEMPORARY 0x00000020
+#define FCB_STATE_BUFFERING_STATE_CHANGE_PENDING 0x00000040
+#define FCB_STATE_ORPHANED 0x00000080
+#define FCB_STATE_READAHEAD_DEFERRED 0x00000100
+#define FCB_STATE_DELAY_CLOSE 0x00000800
+#define FCB_STATE_FAKEFCB 0x00001000
+#define FCB_STATE_FILE_IS_BUF_COMPRESSED 0x00004000
+#define FCB_STATE_FILE_IS_DISK_COMPRESSED 0x00008000
+#define FCB_STATE_FILE_IS_SHADOWED 0x00010000
+#define FCB_STATE_SPECIAL_PATH 0x00020000
+#define FCB_STATE_TIME_AND_SIZE_ALREADY_SET 0x00040000
+#define FCB_STATE_FILESIZECACHEING_ENABLED 0x00100000
+#define FCB_STATE_COLLAPSING_ENABLED 0x00400000
+#define FCB_STATE_READBUFFERING_ENABLED 0x01000000
+#define FCB_STATE_READCACHING_ENABLED 0x02000000
+#define FCB_STATE_WRITEBUFFERING_ENABLED 0x04000000
+#define FCB_STATE_WRITECACHING_ENABLED 0x08000000
+#define FCB_STATE_NAME_ALREADY_REMOVED 0x10000000
+#define FCB_STATE_ADDEDBACKSLASH 0x20000000
+#define FCB_STATE_FOBX_USED 0x40000000
+#define FCB_STATE_SRVOPEN_USED 0x80000000
+
+typedef struct _FCB_INIT_PACKET
+{
+ PULONG pAttributes;
+ PULONG pNumLinks;
+ PLARGE_INTEGER pCreationTime;
+ PLARGE_INTEGER pLastAccessTime;
+ PLARGE_INTEGER pLastWriteTime;
+ PLARGE_INTEGER pLastChangeTime;
+ PLARGE_INTEGER pAllocationSize;
+ PLARGE_INTEGER pFileSize;
+ PLARGE_INTEGER pValidDataLength;
+} FCB_INIT_PACKET;
+
+#define SRVOPEN_FLAG_ENCLOSED_ALLOCATED 0x10000
+#define SRVOPEN_FLAG_FOBX_USED 0x20000
+#define SRVOPEN_FLAG_SHAREACCESS_UPDATED 0x40000
+
+typedef struct _SRV_OPEN
+{
+ union
+ {
+ MRX_SRV_OPEN;
+ struct
+ {
+ MRX_NORMAL_NODE_HEADER spacer;
+ PFCB Fcb;
+#if (_WIN32_WINNT >= 0x600)
+ PV_NET_ROOT VNetRoot;
+#endif
+ };
+ };
+ BOOLEAN UpperFinalizationDone;
+ RX_BLOCK_CONDITION Condition;
+ volatile LONG BufferingToken;
+ LIST_ENTRY ScavengerFinalizationList;
+ LIST_ENTRY TransitionWaitList;
+ LIST_ENTRY FobxList;
+ PFOBX InternalFobx;
+ union
+ {
+ LIST_ENTRY SrvOpenKeyList;
+ ULONG SequenceNumber;
+ };
+ NTSTATUS OpenStatus;
+} SRV_OPEN, *PSRV_OPEN;
+
+#define FOBX_FLAG_MATCH_ALL 0x10000
+#define FOBX_FLAG_FREE_UNICODE 0x20000
+#define FOBX_FLAG_DELETE_ON_CLOSE 0x800000
+#define FOBX_FLAG_UNC_NAME 0x2000000
+#define FOBX_FLAG_ENCLOSED_ALLOCATED 0x4000000
+
+typedef struct _FOBX
+{
+ union
+ {
+ MRX_FOBX;
+ struct
+ {
+ MRX_NORMAL_NODE_HEADER spacer;
+ PSRV_OPEN SrvOpen;
+ };
+ };
+ volatile ULONG FobxSerialNumber;
+ LIST_ENTRY FobxQLinks;
+ LIST_ENTRY ScavengerFinalizationList;
+ LIST_ENTRY ClosePendingList;
+ LARGE_INTEGER CloseTime;
+ BOOLEAN UpperFinalizationDone;
+ BOOLEAN ContainsWildCards;
+ BOOLEAN fOpenCountDecremented;
+ union
+ {
+ struct
+ {
+ union
+ {
+ MRX_PIPE_HANDLE_INFORMATION;
+ MRX_PIPE_HANDLE_INFORMATION PipeHandleInformation;
+ };
+ LARGE_INTEGER CollectDataTime;
+ ULONG CollectDataSize;
+ THROTTLING_STATE ThrottlingState;
+ LIST_ENTRY ReadSerializationQueue;
+ LIST_ENTRY WriteSerializationQueue;
+ } NamedPipe;
+ struct {
+ RXVBO PredictedReadOffset;
+ RXVBO PredictedWriteOffset;
+ THROTTLING_STATE LockThrottlingState;
+ LARGE_INTEGER LastLockOffset;
+ LARGE_INTEGER LastLockRange;
+ } DiskFile;
+ } Specific;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+} FOBX, *PFOBX;
+
+#define RDBSS_REF_TRACK_SRVCALL 0x00000001
+#define RDBSS_REF_TRACK_NETROOT 0x00000002
+#define RDBSS_REF_TRACK_VNETROOT 0x00000004
+#define RDBSS_REF_TRACK_NETFOBX 0x00000008
+#define RDBSS_REF_TRACK_NETFCB 0x00000010
+#define RDBSS_REF_TRACK_SRVOPEN 0x00000020
+
+extern ULONG RdbssReferenceTracingValue;
+
+VOID
+RxpTrackReference(
+ _In_ ULONG TraceType,
+ _In_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance);
+
+BOOLEAN
+RxpTrackDereference(
+ _In_ ULONG TraceType,
+ _In_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance);
+
+#define RxReferenceSrvCall(SrvCall) \
+ RxpTrackReference(RDBSS_REF_TRACK_SRVCALL, __FILE__, __LINE__, SrvCall); \
+ RxReference(SrvCall)
+
+#define RxDereferenceSrvCall(SrvCall, LockHoldingState) \
+ RxpTrackDereference(RDBSS_REF_TRACK_SRVCALL, __FILE__, __LINE__, SrvCall); \
+ RxDereference(SrvCall, LockHoldingState)
+
+#define RxReferenceNetRoot(NetRoot) \
+ RxpTrackReference(RDBSS_REF_TRACK_NETROOT, __FILE__, __LINE__, NetRoot); \
+ RxReference(NetRoot)
+
+#define RxDereferenceNetRoot(NetRoot, LockHoldingState) \
+ RxpTrackDereference(RDBSS_REF_TRACK_NETROOT, __FILE__, __LINE__, NetRoot); \
+ RxDereference(NetRoot, LockHoldingState)
+
+#define RxReferenceVNetRoot(VNetRoot) \
+ RxpTrackReference(RDBSS_REF_TRACK_VNETROOT, __FILE__, __LINE__, VNetRoot); \
+ RxReference(VNetRoot)
+
+#define RxDereferenceVNetRoot(VNetRoot, LockHoldingState) \
+ RxpTrackDereference(RDBSS_REF_TRACK_VNETROOT, __FILE__, __LINE__, VNetRoot); \
+ RxDereference(VNetRoot, LockHoldingState)
+
+#define RxDereferenceNetFobx(Fobx, LockHoldingState) \
+ RxpTrackDereference(RDBSS_REF_TRACK_NETFOBX, __FILE__, __LINE__, Fobx); \
+ RxDereference(Fobx, LockHoldingState)
+
+#define RxReferenceSrvOpen(SrvOpen) \
+ RxpTrackReference(RDBSS_REF_TRACK_SRVOPEN, __FILE__, __LINE__, SrvOpen); \
+ RxReference(SrvOpen)
+
+#define RxDereferenceSrvOpen(SrvOpen, LockHoldingState) \
+ RxpTrackDereference(RDBSS_REF_TRACK_SRVOPEN, __FILE__, __LINE__, SrvOpen); \
+ RxDereference(SrvOpen, LockHoldingState)
+
+#define RxReferenceNetFcb(Fcb) \
+ (RxpTrackReference(RDBSS_REF_TRACK_NETFCB, __FILE__, __LINE__, Fcb), \
+ RxpReferenceNetFcb(Fcb))
+
+#define RxDereferenceNetFcb(Fcb) \
+ ((LONG)RxpTrackDereference(RDBSS_REF_TRACK_NETFCB, __FILE__, __LINE__, Fcb), \
+ RxpDereferenceNetFcb(Fcb))
+
+#define RxDereferenceAndFinalizeNetFcb(Fcb, RxContext, RecursiveFinalize, ForceFinalize) \
+ (RxpTrackDereference(RDBSS_REF_TRACK_NETFCB, __FILE__, __LINE__, Fcb), \
+ RxpDereferenceAndFinalizeNetFcb(Fcb, RxContext, RecursiveFinalize, ForceFinalize))
+
+PSRV_CALL
+RxCreateSrvCall(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING Name,
+ _In_opt_ PUNICODE_STRING InnerNamePrefix,
+ _In_ PRX_CONNECTION_ID RxConnectionId);
+
+#define RxWaitForStableSrvCall(S, R) RxWaitForStableCondition(&(S)->Condition, &(S)->TransitionWaitList, (R), NULL)
+#define RxTransitionSrvCall(S, C) RxUpdateCondition((C), &(S)->Condition, &(S)->TransitionWaitList)
+
+#if (_WIN32_WINNT >= 0x0600)
+BOOLEAN
+RxFinalizeSrvCall(
+ _Out_ PSRV_CALL ThisSrvCall,
+ _In_ BOOLEAN ForceFinalize);
+#else
+BOOLEAN
+RxFinalizeSrvCall(
+ _Out_ PSRV_CALL ThisSrvCall,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize);
+#endif
+
+PNET_ROOT
+RxCreateNetRoot(
+ _In_ PSRV_CALL SrvCall,
+ _In_ PUNICODE_STRING Name,
+ _In_ ULONG NetRootFlags,
+ _In_opt_ PRX_CONNECTION_ID RxConnectionId);
+
+#define RxWaitForStableNetRoot(N, R) RxWaitForStableCondition(&(N)->Condition, &(N)->TransitionWaitList, (R), NULL)
+#define RxTransitionNetRoot(N, C) RxUpdateCondition((C), &(N)->Condition, &(N)->TransitionWaitList)
+
+BOOLEAN
+RxFinalizeNetRoot(
+ _Out_ PNET_ROOT ThisNetRoot,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize);
+
+NTSTATUS
+RxInitializeVNetRootParameters(
+ _In_ PRX_CONTEXT RxContext,
+ _Out_ LUID *LogonId,
+ _Out_ PULONG SessionId,
+ _Out_ PUNICODE_STRING *UserNamePtr,
+ _Out_ PUNICODE_STRING *UserDomainNamePtr,
+ _Out_ PUNICODE_STRING *PasswordPtr,
+ _Out_ PULONG Flags);
+
+VOID
+RxUninitializeVNetRootParameters(
+ _In_ PUNICODE_STRING UserName,
+ _In_ PUNICODE_STRING UserDomainName,
+ _In_ PUNICODE_STRING Password,
+ _Out_ PULONG Flags);
+
+PV_NET_ROOT
+RxCreateVNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PNET_ROOT NetRoot,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ PUNICODE_STRING LocalNetRootName,
+ _In_ PUNICODE_STRING FilePath,
+ _In_ PRX_CONNECTION_ID RxConnectionId);
+
+#define RxWaitForStableVNetRoot(V, R) RxWaitForStableCondition(&(V)->Condition, &(V)->TransitionWaitList, (R), NULL)
+#define RxTransitionVNetRoot(V, C) RxUpdateCondition((C), &(V)->Condition, &(V)->TransitionWaitList)
+
+VOID
+RxGetFileSizeWithLock(
+ _In_ PFCB Fcb,
+ _Out_ PLONGLONG FileSize);
+
+#if (_WIN32_WINNT >= 0x0600)
+RxCreateNetFcb(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PV_NET_ROOT VNetRoot,
+ _In_ PUNICODE_STRING Name);
+#else
+PFCB
+RxCreateNetFcb(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PV_NET_ROOT VNetRoot,
+ _In_ PUNICODE_STRING Name);
+#endif
+
+#define RxWaitForStableNetFcb(F, R) RxWaitForStableCondition(&(F)->Condition, &(F)->NonPaged->TransitionWaitList, (R), NULL )
+#define RxTransitionNetFcb(F, C) RxUpdateCondition((C), &(F)->Condition, &(F)->NonPaged->TransitionWaitList)
+
+#define RxFormInitPacket(IP, I1, I1a, I2, I3, I4a, I4b, I5, I6, I7) ( \
+ IP.pAttributes = I1, IP.pNumLinks = I1a, \
+ IP.pCreationTime = I2, IP.pLastAccessTime = I3, \
+ IP.pLastWriteTime = I4a, IP.pLastChangeTime = I4b, \
+ IP.pAllocationSize = I5, IP.pFileSize = I6, \
+ IP.pValidDataLength = I7, &IP)
+
+#if DBG
+#define ASSERT_CORRECT_FCB_STRUCTURE_DBG_ONLY(Fcb) \
+{ \
+ ASSERT(Fcb->NonPaged == Fcb->CopyOfNonPaged); \
+ ASSERT(Fcb->NonPaged->FcbBackPointer == Fcb); \
+}
+#else
+#define ASSERT_CORRECT_FCB_STRUCTURE_DBG_ONLY(Fcb)
+#endif
+
+#define ASSERT_CORRECT_FCB_STRUCTURE(Fcb) \
+{ \
+ ASSERT(NodeTypeIsFcb(Fcb)); \
+ ASSERT(Fcb->NonPaged != NULL ); \
+ ASSERT(NodeType(Fcb->NonPaged) == RDBSS_NTC_NONPAGED_FCB); \
+ ASSERT_CORRECT_FCB_STRUCTURE_DBG_ONLY(Fcb); \
+}
+
+VOID
+NTAPI
+RxFinishFcbInitialization(
+ _In_ OUT PMRX_FCB Fcb,
+ _In_ RX_FILE_TYPE FileType,
+ _In_opt_ PFCB_INIT_PACKET InitPacket);
+
+#define RxWaitForStableSrvOpen(S, R) RxWaitForStableCondition(&(S)->Condition, &(S)->TransitionWaitList, (R), NULL)
+#define RxTransitionSrvOpen(S, C) RxUpdateCondition((C), &(S)->Condition, &(S)->TransitionWaitList)
+
+LONG
+RxpReferenceNetFcb(
+ _In_ PFCB Fcb);
+
+LONG
+RxpDereferenceNetFcb(
+ _In_ PFCB Fcb);
+
+BOOLEAN
+RxpDereferenceAndFinalizeNetFcb(
+ _Out_ PFCB ThisFcb,
+ _In_ PRX_CONTEXT RxContext,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize);
+
+PSRV_OPEN
+RxCreateSrvOpen(
+ _In_ PV_NET_ROOT VNetRoot,
+ _In_ OUT PFCB Fcb);
+
+BOOLEAN
+RxFinalizeSrvOpen(
+ _Out_ PSRV_OPEN ThisSrvOpen,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize);
+
+extern INLINE
+PUNICODE_STRING
+GET_ALREADY_PREFIXED_NAME(
+ PMRX_SRV_OPEN SrvOpen,
+ PMRX_FCB Fcb)
+{
+ PFCB ThisFcb = (PFCB)Fcb;
+
+#if DBG
+ if (SrvOpen != NULL)
+ {
+ ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
+ ASSERT(ThisFcb != NULL);
+ ASSERT(NodeTypeIsFcb(Fcb));
+ ASSERT(SrvOpen->pFcb == Fcb);
+ ASSERT(SrvOpen->pAlreadyPrefixedName == &ThisFcb->PrivateAlreadyPrefixedName);
+ }
+#endif
+
+ return &ThisFcb->PrivateAlreadyPrefixedName;
+}
+#define GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(Rxcontext) GET_ALREADY_PREFIXED_NAME((Rxcontext)->pRelevantSrvOpen, (Rxcontext)->pFcb)
+
+PMRX_FOBX
+NTAPI
+RxCreateNetFobx(
+ _Out_ PRX_CONTEXT RxContext,
+ _In_ PMRX_SRV_OPEN MrxSrvOpen);
+
+#ifdef __REACTOS__
+#define FILL_IN_FCB(Fcb, a, nl, ct, lat, lwt, lct, as, fs, vdl) \
+ (Fcb)->Attributes = a; \
+ (Fcb)->NumberOfLinks = nl; \
+ (Fcb)->CreationTime.QuadPart = ct; \
+ (Fcb)->LastAccessTime.QuadPart = lat; \
+ (Fcb)->LastWriteTime.QuadPart = lwt; \
+ (Fcb)->LastChangeTime.QuadPart = lct; \
+ (Fcb)->ActualAllocationLength = as; \
+ (Fcb)->Header.AllocationSize.QuadPart = as; \
+ (Fcb)->Header.FileSize.QuadPart = fs; \
+ (Fcb)->Header.ValidDataLength.QuadPart = vdl; \
+ (Fcb)->FcbState |= FCB_STATE_TIME_AND_SIZE_ALREADY_SET
+
+#define TRACKER_ACQUIRE_FCB 0x61616161
+#define TRACKER_RELEASE_FCB_NO_BUFF_PENDING 0x72727272
+#define TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING 0x72727230
+#define TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING 0x72727231
+#define TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING 0x72727474
+#define TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING 0x72727430
+#define TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING 0x72727431
+#define TRACKER_FCB_FREE 0x72724372
+#endif
+
+#endif
--- /dev/null
+#ifndef _RXFCBTABLE_
+#define _RXFCBTABLE_
+
+typedef struct _RX_FCB_TABLE_ENTRY {
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ ULONG HashValue;
+ UNICODE_STRING Path;
+ LIST_ENTRY HashLinks;
+ LONG Lookups;
+} RX_FCB_TABLE_ENTRY, *PRX_FCB_TABLE_ENTRY;
+
+#define RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS 32
+
+typedef struct _RX_FCB_TABLE
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ volatile ULONG Version;
+ BOOLEAN CaseInsensitiveMatch;
+ USHORT NumberOfBuckets;
+ volatile LONG Lookups;
+ volatile LONG FailedLookups;
+ volatile LONG Compares;
+ ERESOURCE TableLock;
+ PRX_FCB_TABLE_ENTRY TableEntryForNull;
+ LIST_ENTRY HashBuckets[RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS];
+} RX_FCB_TABLE, *PRX_FCB_TABLE;
+
+VOID
+RxInitializeFcbTable(
+ _Inout_ PRX_FCB_TABLE FcbTable,
+ _In_ BOOLEAN CaseInsensitiveMatch);
+
+PFCB
+RxFcbTableLookupFcb(
+ _In_ PRX_FCB_TABLE FcbTable,
+ _In_ PUNICODE_STRING Path);
+
+NTSTATUS
+RxFcbTableInsertFcb(
+ _Inout_ PRX_FCB_TABLE FcbTable,
+ _Inout_ PFCB Fcb);
+
+NTSTATUS
+RxFcbTableRemoveFcb(
+ _Inout_ PRX_FCB_TABLE FcbTable,
+ _Inout_ PFCB Fcb);
+
+#define RxAcquireFcbTableLockShared(T, W) ExAcquireResourceSharedLite(&(T)->TableLock, W)
+#define RxAcquireFcbTableLockExclusive(T, W) ExAcquireResourceExclusiveLite(&(T)->TableLock, W)
+#define RxReleaseFcbTableLock(T) ExReleaseResourceLite(&(T)->TableLock)
+
+#define RxIsFcbTableLockExclusive(T) ExIsResourceAcquiredExclusiveLite(&(T)->TableLock)
+
+#ifdef __REACTOS__
+#define FCB_HASH_BUCKET(T, H) &(T)->HashBuckets[H % (T)->NumberOfBuckets]
+#endif
+
+#endif
--- /dev/null
+#ifndef _RXLOWIO_
+#define _RXLOWIO_
+
+#include "mrx.h"
+
+extern FAST_MUTEX RxLowIoPagingIoSyncMutex;
+
+#define RxLowIoIsMdlLocked(MDL) (RxMdlIsLocked((MDL)) || RxMdlSourceIsNonPaged((MDL)))
+
+#define RxLowIoIsBufferLocked(LowIoContext) \
+ (((LowIoContext)->Operation > LOWIO_OP_WRITE) || \
+ ((LowIoContext)->ParamsFor.ReadWrite.Buffer == NULL) || \
+ (((LowIoContext)->ParamsFor.ReadWrite.Buffer != NULL) && \
+ RxLowIoIsMdlLocked(((LowIoContext)->ParamsFor.ReadWrite.Buffer))))
+
+
+typedef struct _LOWIO_PER_FCB_INFO
+{
+ LIST_ENTRY PagingIoReadsOutstanding;
+ LIST_ENTRY PagingIoWritesOutstanding;
+} LOWIO_PER_FCB_INFO, *PLOWIO_PER_FCB_INFO;
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+NTAPI
+RxLowIoPopulateFsctlInfo(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp);
+#else
+NTSTATUS
+NTAPI
+RxLowIoPopulateFsctlInfo(
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+NTAPI
+RxLowIoSubmit(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PFCB Fcb,
+ _In_ PLOWIO_COMPLETION_ROUTINE CompletionRoutine);
+#else
+NTSTATUS
+NTAPI
+RxLowIoSubmit(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PLOWIO_COMPLETION_ROUTINE CompletionRoutine);
+#endif
+
+NTSTATUS
+NTAPI
+RxLowIoCompletion(
+ _In_ PRX_CONTEXT RxContext);
+
+#if (_WIN32_WINNT >= 0x0600)
+VOID
+NTAPI
+RxInitializeLowIoContext(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ ULONG Operation,
+ _Out_ PLOWIO_CONTEXT LowIoContext);
+#else
+VOID
+NTAPI
+RxInitializeLowIoContext(
+ _Out_ PLOWIO_CONTEXT LowIoContext,
+ _In_ ULONG Operation);
+#endif
+
+VOID
+RxInitializeLowIoPerFcbInfo(
+ _Inout_ PLOWIO_PER_FCB_INFO LowIoPerFcbInfo);
+
+#endif
--- /dev/null
+#ifndef _RXMINIRDR_
+#define _RXMINIRDR_
+
+#define RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS 0x00000001
+#define RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS 0x00000002
+#define RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH 0x00000004
+#define RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER 0x00000008
+
+NTSTATUS
+NTAPI
+RxRegisterMinirdr(
+ _Out_ PRDBSS_DEVICE_OBJECT *DeviceObject,
+ _Inout_ PDRIVER_OBJECT DriverObject,
+ _In_ PMINIRDR_DISPATCH MrdrDispatch,
+ _In_ ULONG Controls,
+ _In_ PUNICODE_STRING DeviceName,
+ _In_ ULONG DeviceExtensionSize,
+ _In_ DEVICE_TYPE DeviceType,
+ _In_ ULONG DeviceCharacteristics);
+
+VOID
+NTAPI
+RxpUnregisterMinirdr(
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject);
+
+NTSTATUS
+NTAPI
+RxStartMinirdr(
+ _In_ PRX_CONTEXT RxContext,
+ _Out_ PBOOLEAN PostToFsp);
+
+NTSTATUS
+NTAPI
+RxStopMinirdr(
+ _In_ PRX_CONTEXT RxContext,
+ _Out_ PBOOLEAN PostToFsp);
+
+NTSTATUS
+NTAPI
+RxFsdDispatch(
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ PIRP Irp);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CALLDOWN) (
+ _Inout_ PRX_CONTEXT RxContext);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CALLDOWN_CTX) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _Inout_ PRDBSS_DEVICE_OBJECT RxDeviceObject);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CHKDIR_CALLDOWN) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING DirectoryName);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CHKFCB_CALLDOWN) (
+ _In_ PFCB Fcb1,
+ _In_ PFCB Fcb2);
+
+typedef enum _RX_BLOCK_CONDITION {
+ Condition_Uninitialized = 0,
+ Condition_InTransition,
+ Condition_Closing,
+ Condition_Good,
+ Condition_Bad,
+ Condition_Closed
+} RX_BLOCK_CONDITION, *PRX_BLOCK_CONDITION;
+
+#define StableCondition(X) ((X) >= Condition_Good)
+
+typedef
+VOID
+(NTAPI *PMRX_NETROOT_CALLBACK) (
+ _Inout_ PMRX_CREATENETROOT_CONTEXT CreateContext);
+
+typedef
+VOID
+(NTAPI *PMRX_EXTRACT_NETROOT_NAME) (
+ _In_ PUNICODE_STRING FilePathName,
+ _In_ PMRX_SRV_CALL SrvCall,
+ _Out_ PUNICODE_STRING NetRootName,
+ _Out_opt_ PUNICODE_STRING RestOfName);
+
+typedef struct _MRX_CREATENETROOT_CONTEXT
+{
+ PRX_CONTEXT RxContext;
+ PV_NET_ROOT pVNetRoot;
+ KEVENT FinishEvent;
+ NTSTATUS VirtualNetRootStatus;
+ NTSTATUS NetRootStatus;
+ RX_WORK_QUEUE_ITEM WorkQueueItem;
+ PMRX_NETROOT_CALLBACK Callback;
+} MRX_CREATENETROOT_CONTEXT, *PMRX_CREATENETROOT_CONTEXT;
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CREATE_V_NET_ROOT) (
+ _Inout_ PMRX_CREATENETROOT_CONTEXT Context);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_UPDATE_NETROOT_STATE) (
+ _Inout_ PMRX_NET_ROOT NetRoot);
+
+typedef struct _MRX_SRVCALL_CALLBACK_CONTEXT
+{
+ PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure;
+ ULONG CallbackContextOrdinal;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ NTSTATUS Status;
+ PVOID RecommunicateContext;
+} MRX_SRVCALL_CALLBACK_CONTEXT, *PMRX_SRVCALL_CALLBACK_CONTEXT;
+
+typedef
+VOID
+(NTAPI *PMRX_SRVCALL_CALLBACK) (
+ _Inout_ PMRX_SRVCALL_CALLBACK_CONTEXT Context);
+
+typedef struct _MRX_SRVCALLDOWN_STRUCTURE
+{
+ KEVENT FinishEvent;
+ LIST_ENTRY SrvCalldownList;
+ PRX_CONTEXT RxContext;
+ PMRX_SRV_CALL SrvCall;
+ PMRX_SRVCALL_CALLBACK CallBack;
+ BOOLEAN CalldownCancelled;
+ ULONG NumberRemaining;
+ ULONG NumberToWait;
+ ULONG BestFinisherOrdinal;
+ PRDBSS_DEVICE_OBJECT BestFinisher;
+ MRX_SRVCALL_CALLBACK_CONTEXT CallbackContexts[1];
+} MRX_SRVCALLDOWN_STRUCTURE, *PMRX_SRVCALLDOWN_STRUCTURE;
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CREATE_SRVCALL) (
+ _Inout_ PMRX_SRV_CALL SrvCall,
+ _Inout_ PMRX_SRVCALL_CALLBACK_CONTEXT SrvCallCallBackContext);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_SRVCALL_WINNER_NOTIFY)(
+ _Inout_ PMRX_SRV_CALL SrvCall,
+ _In_ BOOLEAN ThisMinirdrIsTheWinner,
+ _Inout_ PVOID RecommunicateContext);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_DEALLOCATE_FOR_FCB) (
+ _Inout_ PMRX_FCB Fcb);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_DEALLOCATE_FOR_FOBX) (
+ _Inout_ PMRX_FOBX Fobx);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_IS_LOCK_REALIZABLE) (
+ _Inout_ PMRX_FCB Fcb,
+ _In_ PLARGE_INTEGER ByteOffset,
+ _In_ PLARGE_INTEGER Length,
+ _In_ ULONG LowIoLockFlags);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_FORCECLOSED_CALLDOWN) (
+ _Inout_ PMRX_SRV_OPEN SrvOpen);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_FINALIZE_SRVCALL_CALLDOWN) (
+ _Inout_ PMRX_SRV_CALL SrvCall,
+ _In_ BOOLEAN Force);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_FINALIZE_V_NET_ROOT_CALLDOWN) (
+ _Inout_ PMRX_V_NET_ROOT VirtualNetRoot,
+ _In_ PBOOLEAN Force);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_FINALIZE_NET_ROOT_CALLDOWN) (
+ _Inout_ PMRX_NET_ROOT NetRoot,
+ _In_ PBOOLEAN Force);
+
+typedef
+ULONG
+(NTAPI *PMRX_EXTENDFILE_CALLDOWN) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _Inout_ PLARGE_INTEGER NewFileSize,
+ _Out_ PLARGE_INTEGER NewAllocationSize);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_CHANGE_BUFFERING_STATE_CALLDOWN) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_SRV_OPEN SrvOpen,
+ _In_ PVOID MRxContext);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_PREPARSE_NAME) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING Name);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_GET_CONNECTION_ID) (
+ _Inout_ PRX_CONTEXT RxContext,
+ _Inout_ PRX_CONNECTION_ID UniqueId);
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_COMPUTE_NEW_BUFFERING_STATE) (
+ _Inout_ PMRX_SRV_OPEN SrvOpen,
+ _In_ PVOID MRxContext,
+ _Out_ PULONG NewBufferingState);
+
+typedef enum _LOWIO_OPS {
+ LOWIO_OP_READ = 0,
+ LOWIO_OP_WRITE,
+ LOWIO_OP_SHAREDLOCK,
+ LOWIO_OP_EXCLUSIVELOCK,
+ LOWIO_OP_UNLOCK,
+ LOWIO_OP_UNLOCK_MULTIPLE,
+ LOWIO_OP_FSCTL,
+ LOWIO_OP_IOCTL,
+ LOWIO_OP_NOTIFY_CHANGE_DIRECTORY,
+ LOWIO_OP_CLEAROUT,
+ LOWIO_OP_MAXIMUM
+} LOWIO_OPS;
+
+typedef
+NTSTATUS
+(NTAPI *PLOWIO_COMPLETION_ROUTINE) (
+ _In_ PRX_CONTEXT RxContext);
+
+typedef LONGLONG RXVBO;
+
+typedef struct _LOWIO_LOCK_LIST
+{
+ struct _LOWIO_LOCK_LIST * Next;
+ ULONG LockNumber;
+ RXVBO ByteOffset;
+ LONGLONG Length;
+ BOOLEAN ExclusiveLock;
+ ULONG Key;
+} LOWIO_LOCK_LIST, *PLOWIO_LOCK_LIST;
+
+typedef struct _XXCTL_LOWIO_COMPONENT
+{
+ ULONG Flags;
+ union
+ {
+ ULONG FsControlCode;
+ ULONG IoControlCode;
+ };
+ ULONG InputBufferLength;
+ PVOID pInputBuffer;
+ ULONG OutputBufferLength;
+ PVOID pOutputBuffer;
+ UCHAR MinorFunction;
+} XXCTL_LOWIO_COMPONENT;
+
+typedef struct _LOWIO_CONTEXT
+{
+ USHORT Operation;
+ USHORT Flags;
+ PLOWIO_COMPLETION_ROUTINE CompletionRoutine;
+ PERESOURCE Resource;
+ ERESOURCE_THREAD ResourceThreadId;
+ union
+ {
+ struct
+ {
+ ULONG Flags;
+ PMDL Buffer;
+ RXVBO ByteOffset;
+ ULONG ByteCount;
+ ULONG Key;
+ PNON_PAGED_FCB NonPagedFcb;
+ } ReadWrite;
+ struct
+ {
+ union
+ {
+ PLOWIO_LOCK_LIST LockList;
+ LONGLONG Length;
+ };
+ ULONG Flags;
+ RXVBO ByteOffset;
+ ULONG Key;
+ } Locks;
+ XXCTL_LOWIO_COMPONENT FsCtl;
+ XXCTL_LOWIO_COMPONENT IoCtl;
+ struct
+ {
+ BOOLEAN WatchTree;
+ ULONG CompletionFilter;
+ ULONG NotificationBufferLength;
+ PVOID pNotificationBuffer;
+ } NotifyChangeDirectory;
+ } ParamsFor;
+} LOWIO_CONTEXT;
+
+#define LOWIO_CONTEXT_FLAG_SYNCCALL 0x01
+#define LOWIO_CONTEXT_FLAG_LOUDOPS 0x04
+#define LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL 0x08
+
+#define LOWIO_READWRITEFLAG_PAGING_IO 0x01
+
+#define RDBSS_MANAGE_SRV_CALL_EXTENSION 0x01
+#define RDBSS_MANAGE_NET_ROOT_EXTENSION 0x02
+#define RDBSS_MANAGE_V_NET_ROOT_EXTENSION 0x04
+#define RDBSS_MANAGE_FCB_EXTENSION 0x08
+#define RDBSS_MANAGE_SRV_OPEN_EXTENSION 0x10
+#define RDBSS_MANAGE_FOBX_EXTENSION 0x20
+#define RDBSS_NO_DEFERRED_CACHE_READAHEAD 0x1000
+
+typedef struct _MINIRDR_DISPATCH
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ ULONG MRxFlags;
+ ULONG MRxSrvCallSize;
+ ULONG MRxNetRootSize;
+ ULONG MRxVNetRootSize;
+ ULONG MRxFcbSize;
+ ULONG MRxSrvOpenSize;
+ ULONG MRxFobxSize;
+ PMRX_CALLDOWN_CTX MRxStart;
+ PMRX_CALLDOWN_CTX MRxStop;
+ PMRX_CALLDOWN MRxCancel;
+ PMRX_CALLDOWN MRxCreate;
+ PMRX_CALLDOWN MRxCollapseOpen;
+ PMRX_CALLDOWN MRxShouldTryToCollapseThisOpen;
+ PMRX_CALLDOWN MRxFlush;
+ PMRX_CALLDOWN MRxZeroExtend;
+ PMRX_CALLDOWN MRxTruncate;
+ PMRX_CALLDOWN MRxCleanupFobx;
+ PMRX_CALLDOWN MRxCloseSrvOpen;
+ PMRX_DEALLOCATE_FOR_FCB MRxDeallocateForFcb;
+ PMRX_DEALLOCATE_FOR_FOBX MRxDeallocateForFobx;
+ PMRX_IS_LOCK_REALIZABLE MRxIsLockRealizable;
+ PMRX_FORCECLOSED_CALLDOWN MRxForceClosed;
+ PMRX_CHKFCB_CALLDOWN MRxAreFilesAliased;
+ PMRX_CALLDOWN MRxOpenPrintFile;
+ PMRX_CALLDOWN MRxClosePrintFile;
+ PMRX_CALLDOWN MRxWritePrintFile;
+ PMRX_CALLDOWN MRxEnumeratePrintQueue;
+ PMRX_CALLDOWN MRxClosedSrvOpenTimeOut;
+ PMRX_CALLDOWN MRxClosedFcbTimeOut;
+ PMRX_CALLDOWN MRxQueryDirectory;
+ PMRX_CALLDOWN MRxQueryFileInfo;
+ PMRX_CALLDOWN MRxSetFileInfo;
+ PMRX_CALLDOWN MRxSetFileInfoAtCleanup;
+ PMRX_CALLDOWN MRxQueryEaInfo;
+ PMRX_CALLDOWN MRxSetEaInfo;
+ PMRX_CALLDOWN MRxQuerySdInfo;
+ PMRX_CALLDOWN MRxSetSdInfo;
+ PMRX_CALLDOWN MRxQueryQuotaInfo;
+ PMRX_CALLDOWN MRxSetQuotaInfo;
+ PMRX_CALLDOWN MRxQueryVolumeInfo;
+ PMRX_CALLDOWN MRxSetVolumeInfo;
+ PMRX_CHKDIR_CALLDOWN MRxIsValidDirectory;
+ PMRX_COMPUTE_NEW_BUFFERING_STATE MRxComputeNewBufferingState;
+ PMRX_CALLDOWN MRxLowIOSubmit[LOWIO_OP_MAXIMUM+1];
+ PMRX_EXTENDFILE_CALLDOWN MRxExtendForCache;
+ PMRX_EXTENDFILE_CALLDOWN MRxExtendForNonCache;
+ PMRX_CHANGE_BUFFERING_STATE_CALLDOWN MRxCompleteBufferingStateChangeRequest;
+ PMRX_CREATE_V_NET_ROOT MRxCreateVNetRoot;
+ PMRX_FINALIZE_V_NET_ROOT_CALLDOWN MRxFinalizeVNetRoot;
+ PMRX_FINALIZE_NET_ROOT_CALLDOWN MRxFinalizeNetRoot;
+ PMRX_UPDATE_NETROOT_STATE MRxUpdateNetRootState;
+ PMRX_EXTRACT_NETROOT_NAME MRxExtractNetRootName;
+ PMRX_CREATE_SRVCALL MRxCreateSrvCall;
+ PMRX_CREATE_SRVCALL MRxCancelCreateSrvCall;
+ PMRX_SRVCALL_WINNER_NOTIFY MRxSrvCallWinnerNotify;
+ PMRX_FINALIZE_SRVCALL_CALLDOWN MRxFinalizeSrvCall;
+ PMRX_CALLDOWN MRxDevFcbXXXControlFile;
+ PMRX_PREPARSE_NAME MRxPreparseName;
+ PMRX_GET_CONNECTION_ID MRxGetConnectionId;
+ ULONG ScavengerTimeout;
+} MINIRDR_DISPATCH, *PMINIRDR_DISPATCH;
+
+#endif
--- /dev/null
+#ifndef __MRXFCB_H__
+#define __MRXFCB_H__
+
+typedef struct _MRX_NORMAL_NODE_HEADER
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ volatile ULONG NodeReferenceCount;
+} MRX_NORMAL_NODE_HEADER;
+
+#define SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS 0x4
+#define SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES 0x8
+#define SRVCALL_FLAG_DFS_AWARE_SERVER 0x10
+
+typedef struct _MRX_SRV_CALL_
+{
+ MRX_NORMAL_NODE_HEADER;
+ PVOID Context;
+ PVOID Context2;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PUNICODE_STRING pSrvCallName;
+ PUNICODE_STRING pPrincipalName;
+ PUNICODE_STRING pDomainName;
+ ULONG Flags;
+ LONG MaximumNumberOfCloseDelayedFiles;
+ NTSTATUS Status;
+} MRX_SRV_CALL, *PMRX_SRV_CALL;
+
+#define NET_ROOT_DISK ((UCHAR)0)
+#define NET_ROOT_PIPE ((UCHAR)1)
+#define NET_ROOT_PRINT ((UCHAR)3)
+#define NET_ROOT_WILD ((UCHAR)4)
+
+typedef UCHAR NET_ROOT_TYPE, *PNET_ROOT_TYPE;
+
+#define MRX_NET_ROOT_STATE_GOOD ((UCHAR)0)
+
+typedef UCHAR MRX_NET_ROOT_STATE, *PMRX_NET_ROOT_STATE;
+typedef UCHAR MRX_PURGE_RELATIONSHIP, *PMRX_PURGE_RELATIONSHIP;
+typedef UCHAR MRX_PURGE_SYNCLOCATION, *PMRX_PURGE_SYNCLOCATION;
+
+#define NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS 0x1
+#define NETROOT_FLAG_DFS_AWARE_NETROOT 0x2
+
+typedef struct _NETROOT_THROTTLING_PARAMETERS
+{
+ ULONG Increment;
+ ULONG MaximumDelay;
+} NETROOT_THROTTLING_PARAMETERS, *PNETROOT_THROTTLING_PARAMETERS;
+
+typedef struct _MRX_NET_ROOT_
+{
+ MRX_NORMAL_NODE_HEADER;
+ PMRX_SRV_CALL pSrvCall;
+ PVOID Context;
+ PVOID Context2;
+ ULONG Flags;
+ volatile ULONG NumberOfFcbs;
+ volatile ULONG NumberOfSrvOpens;
+ MRX_NET_ROOT_STATE MRxNetRootState;
+ NET_ROOT_TYPE Type;
+ MRX_PURGE_RELATIONSHIP PurgeRelationship;
+ MRX_PURGE_SYNCLOCATION PurgeSyncLocation;
+ DEVICE_TYPE DeviceType;
+ PUNICODE_STRING pNetRootName;
+ UNICODE_STRING InnerNamePrefix;
+ ULONG ParameterValidationStamp;
+ union
+ {
+ struct
+ {
+ ULONG DataCollectionSize;
+ NETROOT_THROTTLING_PARAMETERS PipeReadThrottlingParameters;
+ } NamedPipeParameters;
+ struct
+ {
+ ULONG ClusterSize;
+ ULONG ReadAheadGranularity;
+ NETROOT_THROTTLING_PARAMETERS LockThrottlingParameters;
+ ULONG RenameInfoOverallocationSize;
+ GUID VolumeId;
+ } DiskParameters;
+ };
+} MRX_NET_ROOT, *PMRX_NET_ROOT;
+
+#define VNETROOT_FLAG_CSCAGENT_INSTANCE 0x00000001
+
+typedef struct _MRX_V_NET_ROOT_
+{
+ MRX_NORMAL_NODE_HEADER;
+ PMRX_NET_ROOT pNetRoot;
+ PVOID Context;
+ PVOID Context2;
+ ULONG Flags;
+ ULONG NumberOfOpens;
+ volatile ULONG NumberOfFobxs;
+ LUID LogonId;
+ PUNICODE_STRING pUserDomainName;
+ PUNICODE_STRING pUserName;
+ PUNICODE_STRING pPassword;
+ ULONG SessionId;
+ NTSTATUS ConstructionStatus;
+ BOOLEAN IsExplicitConnection;
+} MRX_V_NET_ROOT, *PMRX_V_NET_ROOT;
+
+typedef struct _MRX_FCB_
+{
+ FSRTL_ADVANCED_FCB_HEADER Header;
+ PMRX_NET_ROOT pNetRoot;
+ PVOID Context;
+ PVOID Context2;
+ volatile ULONG NodeReferenceCount;
+ ULONG FcbState;
+ volatile CLONG UncleanCount;
+ CLONG UncachedUncleanCount;
+ volatile CLONG OpenCount;
+ volatile ULONG OutstandingLockOperationsCount;
+ ULONGLONG ActualAllocationLength;
+ ULONG Attributes;
+ BOOLEAN IsFileWritten;
+ BOOLEAN fShouldBeOrphaned;
+ BOOLEAN fMiniInited;
+ UCHAR CachedNetRootType;
+ LIST_ENTRY SrvOpenList;
+ ULONG SrvOpenListVersion;
+} MRX_FCB, *PMRX_FCB;
+
+#define SRVOPEN_FLAG_DONTUSE_READ_CACHING 0x1
+#define SRVOPEN_FLAG_DONTUSE_WRITE_CACHING 0x2
+#define SRVOPEN_FLAG_CLOSED 0x4
+#define SRVOPEN_FLAG_CLOSE_DELAYED 0x8
+#define SRVOPEN_FLAG_FILE_RENAMED 0x10
+#define SRVOPEN_FLAG_FILE_DELETED 0x20
+#define SRVOPEN_FLAG_COLLAPSING_DISABLED 0x80
+#define SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE 0x200
+#define SRVOPEN_FLAG_ORPHANED 0x400
+
+typedef
+NTSTATUS
+(NTAPI *PMRX_SHADOW_CALLDOWN) (
+ IN OUT PRX_CONTEXT RxContext
+ );
+
+typedef struct
+{
+ PFILE_OBJECT UnderlyingFileObject;
+ PDEVICE_OBJECT UnderlyingDeviceObject;
+ ULONG LockKey;
+ PFAST_IO_READ FastIoRead;
+ PFAST_IO_WRITE FastIoWrite;
+ PMRX_SHADOW_CALLDOWN DispatchRoutine;
+} MRXSHADOW_SRV_OPEN, *PMRXSHADOW_SRV_OPEN;
+
+typedef struct _MRX_SRV_OPEN_
+{
+ MRX_NORMAL_NODE_HEADER;
+ PMRX_FCB pFcb;
+ PMRX_V_NET_ROOT pVNetRoot;
+ PVOID Context;
+ PVOID Context2;
+#if (_WIN32_WINNT >= 0x0600)
+ PMRXSHADOW_SRV_OPEN ShadowContext;
+#endif
+ ULONG Flags;
+ PUNICODE_STRING pAlreadyPrefixedName;
+ CLONG UncleanFobxCount;
+ CLONG OpenCount;
+ PVOID Key;
+ ACCESS_MASK DesiredAccess;
+ ULONG ShareAccess;
+ ULONG CreateOptions;
+ ULONG BufferingFlags;
+ ULONG ulFileSizeVersion;
+ LIST_ENTRY SrvOpenQLinks;
+} MRX_SRV_OPEN, *PMRX_SRV_OPEN;
+
+#define FOBX_FLAG_DFS_OPEN 0x0001
+#define FOBX_FLAG_BACKUP_INTENT 0x0004
+
+typedef struct _MRX_PIPE_HANDLE_INFORMATION
+{
+ ULONG TypeOfPipe;
+ ULONG ReadMode;
+ ULONG CompletionMode;
+} MRX_PIPE_HANDLE_INFORMATION, *PMRX_PIPE_HANDLE_INFORMATION;
+
+typedef struct _MRX_FOBX_
+{
+ MRX_NORMAL_NODE_HEADER;
+ PMRX_SRV_OPEN pSrvOpen;
+ PFILE_OBJECT AssociatedFileObject;
+ PVOID Context;
+ PVOID Context2;
+ ULONG Flags;
+ union
+ {
+ struct
+ {
+ UNICODE_STRING UnicodeQueryTemplate;
+ };
+ PMRX_PIPE_HANDLE_INFORMATION PipeHandleInformation;
+ };
+ ULONG OffsetOfNextEaToReturn;
+} MRX_FOBX, *PMRX_FOBX;
+
+NTSTATUS
+NTAPI
+RxAcquireExclusiveFcbResourceInMRx(
+ _Inout_ PMRX_FCB Fcb);
+
+#endif
--- /dev/null
+#ifndef _NODETYPE_INCLUDED_
+#define _NODETYPE_INCLUDED_
+
+
+typedef USHORT NODE_TYPE_CODE;
+typedef NODE_TYPE_CODE *PNODE_TYPE_CODE;
+typedef CSHORT NODE_BYTE_SIZE;
+
+#ifndef NodeType
+#define NodeType(Ptr) (*((PNODE_TYPE_CODE)(Ptr)))
+#endif
+
+typedef struct _NODE_TYPE_CODE_AND_SIZE_NO_REFCOUNT
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+} NODE_TYPE_CODE_AND_SIZE_NO_REFCOUNT;
+
+typedef struct _NODE_TYPE_CODE_AND_SIZE
+{
+ NODE_TYPE_CODE_AND_SIZE_NO_REFCOUNT;
+ volatile ULONG NodeReferenceCount;
+} NODE_TYPE_CODE_AND_SIZE, *PNODE_TYPE_AND_SIZE;
+
+#define ZeroAndInitializeNodeType(Node, Type, Size) \
+{ \
+ RtlZeroMemory(Node, Size); \
+ ((NODE_TYPE_CODE_AND_SIZE *)(Node))->NodeTypeCode = Type; \
+ ((NODE_TYPE_CODE_AND_SIZE *)(Node))->NodeByteSize = (CSHORT)Size; \
+}
+
+#define RDBSS_STORAGE_NTC(x) (0xec00 + (x))
+
+typedef enum _RX_FILE_TYPE
+{
+ FileTypeNotYetKnown = 0,
+ FileTypeDirectory = 2,
+ FileTypeFile = 3
+} RX_FILE_TYPE;
+
+#define RDBSS_NTC_STORAGE_TYPE_UNKNOWN ((NODE_TYPE_CODE)0xec00)
+#define RDBSS_NTC_STORAGE_TYPE_DIRECTORY ((NODE_TYPE_CODE)0xec02)
+#define RDBSS_NTC_STORAGE_TYPE_FILE ((NODE_TYPE_CODE)0xec03)
+#define RDBSS_NTC_OPENTARGETDIR_FCB ((NODE_TYPE_CODE)0xecff)
+#define RDBSS_NTC_MAILSLOT ((NODE_TYPE_CODE)0xecfd)
+#define RDBSS_NTC_SPOOLFILE ((NODE_TYPE_CODE)0xecfc)
+#define RDBSS_NTC_SRVCALL ((NODE_TYPE_CODE)0xeb10)
+#define RDBSS_NTC_NETROOT ((NODE_TYPE_CODE)0xeb11)
+#define RDBSS_NTC_V_NETROOT ((NODE_TYPE_CODE)0xeb12)
+#define RDBSS_NTC_VOLUME_FCB ((NODE_TYPE_CODE)0xeb1f)
+#define RDBSS_NTC_SRVOPEN ((NODE_TYPE_CODE)0xeb1c)
+#define RDBSS_NTC_INTERNAL_SRVOPEN ((NODE_TYPE_CODE)0xeb1d)
+#define RDBSS_NTC_DEVICE_FCB ((NODE_TYPE_CODE)0xeb9a)
+#define RDBSS_NTC_DATA_HEADER ((NODE_TYPE_CODE)0xeb00)
+#define RDBSS_NTC_VCB ((NODE_TYPE_CODE)0xeb01)
+#define RDBSS_NTC_FOBX ((NODE_TYPE_CODE)0xeb07)
+#define RDBSS_NTC_RX_CONTEXT ((NODE_TYPE_CODE)0xeb08)
+#define RDBSS_NTC_PREFIX_TABLE ((NODE_TYPE_CODE)0xeb0d)
+#define RDBSS_NTC_PREFIX_ENTRY ((NODE_TYPE_CODE)0xeb0e)
+#define RDBSS_NTC_FCB_TABLE ((NODE_TYPE_CODE)0xeb09)
+#define RDBSS_NTC_FCB_TABLE_ENTRY ((NODE_TYPE_CODE)0xeb0a)
+#define RDBSS_NTC_NONPAGED_FCB ((NODE_TYPE_CODE)0xebfd)
+#define RDBSS_NTC_MINIRDR_DISPATCH ((NODE_TYPE_CODE)0xebff)
+
+#define NodeTypeIsFcb(FCB) ((((NodeType(FCB) & 0xff00) == RDBSS_NTC_STORAGE_TYPE_UNKNOWN)) || ((NodeType(FCB) & 0xfff0) == 0xeb90))
+
+#define RX_SCAVENGER_MASK (0x1000)
+
+typedef enum _RDBSS_BUG_CHECK_CODES
+{
+ RDBSS_BUG_CHECK_FCBSTRUC = 0xfcb00000,
+ RDBSS_BUG_CHECK_CACHESUP = 0xca550000,
+ RDBSS_BUG_CHECK_CLEANUP = 0xc1ee0000,
+ RDBSS_BUG_CHECK_CLOSE = 0xc10e0000,
+ RDBSS_BUG_CHECK_NTEXCEPT = 0xbaad0000,
+#ifdef __REACTOS__
+ RDBSS_BUG_CHECK_ASSERT = 0xa55a0000,
+#endif
+} RDBSS_BUG_CHECK_CODES;
+
+#define RDBSS_FILE_SYSTEM RDR_FILE_SYSTEM
+
+#define RxBugCheck(A, B, C) KeBugCheckEx(RDBSS_FILE_SYSTEM, BugCheckFileId | ((ULONG)(__LINE__)), A, B, C)
+
+#endif
--- /dev/null
+#ifndef _RX_NTDEFS_DEFINED_
+#define _RX_NTDEFS_DEFINED_
+
+#define INLINE __inline
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE ((HANDLE)-1)
+#endif
+
+#define RxAllocatePoolWithTag ExAllocatePoolWithTag
+#define RxFreePool ExFreePool
+
+#define RxMdlIsLocked(Mdl) ((Mdl)->MdlFlags & MDL_PAGES_LOCKED)
+#define RxMdlSourceIsNonPaged(Mdl) ((Mdl)->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL)
+
+#define RxAdjustAllocationSizeforCC(Fcb) \
+{ \
+ if ((Fcb)->Header.FileSize.QuadPart > (Fcb)->Header.AllocationSize.QuadPart) \
+ { \
+ PMRX_NET_ROOT NetRoot = (Fcb)->pNetRoot; \
+ ULONGLONG ClusterSize = NetRoot->DiskParameters.ClusterSize; \
+ ULONGLONG FileSize = (Fcb)->Header.FileSize.QuadPart; \
+ ASSERT(ClusterSize != 0); \
+ (Fcb)->Header.AllocationSize.QuadPart = (FileSize + ClusterSize) &~ (ClusterSize - 1); \
+ } \
+ ASSERT ((Fcb)->Header.ValidDataLength.QuadPart <= (Fcb)->Header.FileSize.QuadPart); \
+}
+
+#endif
--- /dev/null
+#ifndef _RXPREFIX_
+#define _RXPREFIX_
+
+typedef struct _RX_CONNECTION_ID
+{
+ union
+ {
+ ULONG SessionID;
+ LUID Luid;
+ };
+} RX_CONNECTION_ID, *PRX_CONNECTION_ID;
+
+ULONG
+RxTableComputeHashValue(
+ _In_ PUNICODE_STRING Name);
+
+PVOID
+RxPrefixTableLookupName(
+ _In_ PRX_PREFIX_TABLE ThisTable,
+ _In_ PUNICODE_STRING CanonicalName,
+ _Out_ PUNICODE_STRING RemainingName,
+ _In_ PRX_CONNECTION_ID ConnectionId);
+
+PRX_PREFIX_ENTRY
+RxPrefixTableInsertName(
+ _Inout_ PRX_PREFIX_TABLE ThisTable,
+ _Inout_ PRX_PREFIX_ENTRY ThisEntry,
+ _In_ PVOID Container,
+ _In_ PULONG ContainerRefCount,
+ _In_ USHORT CaseInsensitiveLength,
+ _In_ PRX_CONNECTION_ID ConnectionId);
+
+VOID
+RxInitializePrefixTable(
+ _Inout_ PRX_PREFIX_TABLE ThisTable,
+ _In_opt_ ULONG TableSize,
+ _In_ BOOLEAN CaseInsensitiveMatch);
+
+typedef struct _RX_PREFIX_ENTRY
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ USHORT CaseInsensitiveLength;
+ USHORT Spare1;
+ ULONG SavedHashValue;
+ LIST_ENTRY HashLinks;
+ LIST_ENTRY MemberQLinks;
+ UNICODE_STRING Prefix;
+ PULONG ContainerRefCount;
+ PVOID ContainingRecord;
+ PVOID Context;
+ RX_CONNECTION_ID ConnectionId;
+} RX_PREFIX_ENTRY, *PRX_PREFIX_ENTRY;
+
+#define RX_PREFIX_TABLE_DEFAULT_LENGTH 32
+
+typedef struct _RX_PREFIX_TABLE {
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ ULONG Version;
+ LIST_ENTRY MemberQueue;
+ ERESOURCE TableLock;
+ PRX_PREFIX_ENTRY TableEntryForNull;
+ BOOLEAN CaseInsensitiveMatch;
+ BOOLEAN IsNetNameTable;
+ ULONG TableSize;
+#if DBG
+ ULONG Lookups;
+ ULONG FailedLookups;
+ ULONG Considers;
+ ULONG Compares;
+#endif
+ LIST_ENTRY HashBuckets[RX_PREFIX_TABLE_DEFAULT_LENGTH];
+} RX_PREFIX_TABLE, *PRX_PREFIX_TABLE;
+
+#if (_WIN32_WINNT < 0x0600)
+#define RxAcquirePrefixTableLockShared(T, W) RxpAcquirePrefixTableLockShared((T),(W),TRUE)
+#define RxAcquirePrefixTableLockExclusive(T, W) RxpAcquirePrefixTableLockExclusive((T), (W), TRUE)
+#define RxReleasePrefixTableLock(T) RxpReleasePrefixTableLock((T), TRUE)
+
+BOOLEAN
+RxpAcquirePrefixTableLockShared(
+ _In_ PRX_PREFIX_TABLE pTable,
+ _In_ BOOLEAN Wait,
+ _In_ BOOLEAN ProcessBufferingStateChangeRequests);
+
+BOOLEAN
+RxpAcquirePrefixTableLockExclusive(
+ _In_ PRX_PREFIX_TABLE pTable,
+ _In_ BOOLEAN Wait,
+ _In_ BOOLEAN ProcessBufferingStateChangeRequests);
+
+VOID
+RxpReleasePrefixTableLock(
+ _In_ PRX_PREFIX_TABLE pTable,
+ _In_ BOOLEAN ProcessBufferingStateChangeRequests);
+#endif
+
+VOID
+RxExclusivePrefixTableLockToShared(
+ _In_ PRX_PREFIX_TABLE Table);
+
+#define RxIsPrefixTableLockExclusive(T) ExIsResourceAcquiredExclusiveLite(&(T)->TableLock)
+#define RxIsPrefixTableLockAcquired(T) (ExIsResourceAcquiredSharedLite(&(T)->TableLock) || \
+ ExIsResourceAcquiredExclusiveLite(&(T)->TableLock))
+
+#ifdef __REACTOS__
+#define HASH_BUCKET(T, H) &(T)->HashBuckets[H % (T)->TableSize]
+#endif
+
+#endif
--- /dev/null
+#ifndef _RX_
+#define _RX_
+
+#include "rxovride.h"
+#include "ntifs.h"
+
+#ifndef BooleanFlagOn
+#define BooleanFlagOn(Flags, SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
+#endif
+
+#ifndef SetFlag
+#define SetFlag(Flags, SetOfFlags) \
+{ \
+ (Flags) |= (SetOfFlags); \
+}
+#endif
+
+#ifndef ClearFlag
+#define ClearFlag(Flags, SetOfFlags) \
+{ \
+ (Flags) &= ~(SetOfFlags); \
+}
+#endif
+
+#define Add2Ptr(Ptr, Inc) ((PVOID)((PUCHAR)(Ptr) + (Inc)))
+
+#define INLINE __inline
+
+#include "rxtypes.h"
+
+#ifndef MINIRDR__NAME
+#include "rxpooltg.h"
+#endif
+
+#include "ntrxdef.h"
+#include "fcbtable.h"
+#include "mrxfcb.h"
+#include "rxworkq.h"
+#include "rxprocs.h"
+
+#ifndef MINIRDR__NAME
+#include "rxdata.h"
+#include "buffring.h"
+#endif
+
+#endif
--- /dev/null
+#ifndef _RX_CONTEXT_STRUCT_DEFINED_
+#define _RX_CONTEXT_STRUCT_DEFINED_
+
+#define RX_TOPLEVELIRP_CONTEXT_SIGNATURE 'LTxR'
+
+typedef struct _RX_TOPLEVELIRP_CONTEXT
+{
+ union
+ {
+#ifndef __cplusplus
+ LIST_ENTRY;
+#endif
+ LIST_ENTRY ListEntry;
+ };
+ ULONG Signature;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PRX_CONTEXT RxContext;
+ PIRP Irp;
+ ULONG Flags;
+ PVOID Previous;
+ PETHREAD Thread;
+} RX_TOPLEVELIRP_CONTEXT, *PRX_TOPLEVELIRP_CONTEXT;
+
+BOOLEAN
+RxTryToBecomeTheTopLevelIrp(
+ _Inout_ PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
+ _In_ PIRP Irp,
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ BOOLEAN ForceTopLevel);
+
+VOID
+__RxInitializeTopLevelIrpContext(
+ _Inout_ PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
+ _In_ PIRP Irp,
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ ULONG Flags);
+
+#define RxInitializeTopLevelIrpContext(a,b,c) __RxInitializeTopLevelIrpContext(a,b,c,0)
+
+PRDBSS_DEVICE_OBJECT
+RxGetTopDeviceObjectIfRdbssIrp(
+ VOID);
+
+VOID
+RxUnwindTopLevelIrp(
+ _Inout_ PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
+
+BOOLEAN
+RxIsThisTheTopLevelIrp(
+ _In_ PIRP Irp);
+
+#ifdef RDBSS_TRACKER
+typedef struct _RX_FCBTRACKER_CALLINFO
+{
+ ULONG AcquireRelease;
+ USHORT SavedTrackerValue;
+ USHORT LineNumber;
+ PSZ FileName;
+ ULONG Flags;
+} RX_FCBTRACKER_CALLINFO, *PRX_FCBTRACKER_CALLINFO;
+#define RDBSS_TRACKER_HISTORY_SIZE 32
+#endif
+
+#define MRX_CONTEXT_FIELD_COUNT 4
+
+#if (_WIN32_WINNT >= 0x0600)
+typedef
+NTSTATUS
+(NTAPI *PRX_DISPATCH) (
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp);
+#else
+typedef
+NTSTATUS
+(NTAPI *PRX_DISPATCH) (
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+typedef struct _DFS_NAME_CONTEXT_ *PDFS_NAME_CONTEXT;
+
+typedef struct _NT_CREATE_PARAMETERS
+{
+ ACCESS_MASK DesiredAccess;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG ShareAccess;
+ ULONG Disposition;
+ ULONG CreateOptions;
+ PIO_SECURITY_CONTEXT SecurityContext;
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+ PVOID DfsContext;
+ PDFS_NAME_CONTEXT DfsNameContext;
+} NT_CREATE_PARAMETERS, *PNT_CREATE_PARAMETERS;
+
+typedef struct _RX_CONTEXT
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ volatile ULONG ReferenceCount;
+ LIST_ENTRY ContextListEntry;
+ UCHAR MajorFunction;
+ UCHAR MinorFunction;
+ BOOLEAN PendingReturned;
+ BOOLEAN PostRequest;
+ PDEVICE_OBJECT RealDevice;
+ PIRP CurrentIrp;
+ PIO_STACK_LOCATION CurrentIrpSp;
+ PMRX_FCB pFcb;
+ PMRX_FOBX pFobx;
+ PMRX_SRV_OPEN pRelevantSrvOpen;
+ PNON_PAGED_FCB NonPagedFcb;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PETHREAD OriginalThread;
+ PETHREAD LastExecutionThread;
+ volatile PVOID LockManagerContext;
+ PVOID RdbssDbgExtension;
+ RX_SCAVENGER_ENTRY ScavengerEntry;
+ ULONG SerialNumber;
+ ULONG FobxSerialNumber;
+ ULONG Flags;
+ BOOLEAN FcbResourceAcquired;
+ BOOLEAN FcbPagingIoResourceAcquired;
+ UCHAR MustSucceedDescriptorNumber;
+ union
+ {
+ struct
+ {
+ union
+ {
+ NTSTATUS StoredStatus;
+ PVOID StoredStatusAlignment;
+ };
+ ULONG_PTR InformationToReturn;
+ };
+ IO_STATUS_BLOCK IoStatusBlock;
+ };
+ union
+ {
+ ULONGLONG ForceLonglongAligmentDummyField;
+ PVOID MRxContext[MRX_CONTEXT_FIELD_COUNT];
+ };
+ PVOID WriteOnlyOpenRetryContext;
+ PMRX_CALLDOWN MRxCancelRoutine;
+ PRX_DISPATCH ResumeRoutine;
+ RX_WORK_QUEUE_ITEM WorkQueueItem;
+ LIST_ENTRY OverflowListEntry;
+ KEVENT SyncEvent;
+ LIST_ENTRY BlockedOperations;
+ PFAST_MUTEX BlockedOpsMutex;
+ LIST_ENTRY RxContextSerializationQLinks;
+ union
+ {
+ struct
+ {
+ union
+ {
+ FS_INFORMATION_CLASS FsInformationClass;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ };
+ PVOID Buffer;
+ union
+ {
+ LONG Length;
+ LONG LengthRemaining;
+ };
+ BOOLEAN ReplaceIfExists;
+ BOOLEAN AdvanceOnly;
+ } Info;
+ struct
+ {
+ UNICODE_STRING SuppliedPathName;
+ NET_ROOT_TYPE NetRootType;
+ PIO_SECURITY_CONTEXT pSecurityContext;
+ } PrefixClaim;
+ };
+ union
+ {
+ struct
+ {
+ NT_CREATE_PARAMETERS NtCreateParameters;
+ ULONG ReturnedCreateInformation;
+ PWCH CanonicalNameBuffer;
+ PRX_PREFIX_ENTRY NetNamePrefixEntry;
+ PMRX_SRV_CALL pSrvCall;
+ PMRX_NET_ROOT pNetRoot;
+ PMRX_V_NET_ROOT pVNetRoot;
+ PVOID EaBuffer;
+ ULONG EaLength;
+ ULONG SdLength;
+ ULONG PipeType;
+ ULONG PipeReadMode;
+ ULONG PipeCompletionMode;
+ USHORT Flags;
+ NET_ROOT_TYPE Type;
+ UCHAR RdrFlags;
+ BOOLEAN FcbAcquired;
+ BOOLEAN TryForScavengingOnSharingViolation;
+ BOOLEAN ScavengingAlreadyTried;
+ BOOLEAN ThisIsATreeConnectOpen;
+ BOOLEAN TreeConnectOpenDeferred;
+ UNICODE_STRING TransportName;
+ UNICODE_STRING UserName;
+ UNICODE_STRING Password;
+ UNICODE_STRING UserDomainName;
+ } Create;
+ struct
+ {
+ ULONG FileIndex;
+ BOOLEAN RestartScan;
+ BOOLEAN ReturnSingleEntry;
+ BOOLEAN IndexSpecified;
+ BOOLEAN InitialQuery;
+ } QueryDirectory;
+ struct
+ {
+ PMRX_V_NET_ROOT pVNetRoot;
+ } NotifyChangeDirectory;
+ struct
+ {
+ PUCHAR UserEaList;
+ ULONG UserEaListLength;
+ ULONG UserEaIndex;
+ BOOLEAN RestartScan;
+ BOOLEAN ReturnSingleEntry;
+ BOOLEAN IndexSpecified;
+ } QueryEa;
+ struct
+ {
+ SECURITY_INFORMATION SecurityInformation;
+ ULONG Length;
+ } QuerySecurity;
+ struct
+ {
+ SECURITY_INFORMATION SecurityInformation;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ } SetSecurity;
+ struct
+ {
+ ULONG Length;
+ PSID StartSid;
+ PFILE_GET_QUOTA_INFORMATION SidList;
+ ULONG SidListLength;
+ BOOLEAN RestartScan;
+ BOOLEAN ReturnSingleEntry;
+ BOOLEAN IndexSpecified;
+ } QueryQuota;
+ struct
+ {
+ ULONG Length;
+ } SetQuota;
+ struct
+ {
+ PV_NET_ROOT VNetRoot;
+ PSRV_CALL SrvCall;
+ PNET_ROOT NetRoot;
+ } DosVolumeFunction;
+ struct {
+ ULONG FlagsForLowIo;
+ LOWIO_CONTEXT LowIoContext;
+ };
+ LUID FsdUid;
+ };
+ PWCH AlsoCanonicalNameBuffer;
+ PUNICODE_STRING LoudCompletionString;
+#ifdef RDBSS_TRACKER
+ __volatile LONG AcquireReleaseFcbTrackerX;
+ __volatile ULONG TrackerHistoryPointer;
+ RX_FCBTRACKER_CALLINFO TrackerHistory[RDBSS_TRACKER_HISTORY_SIZE];
+#endif
+#if DBG
+ ULONG ShadowCritOwner;
+#endif
+} RX_CONTEXT, *PRX_CONTEXT;
+
+typedef enum
+{
+ RX_CONTEXT_FLAG_FROM_POOL = 0x00000001,
+ RX_CONTEXT_FLAG_WAIT = 0x00000002,
+ RX_CONTEXT_FLAG_WRITE_THROUGH = 0x00000004,
+ RX_CONTEXT_FLAG_FLOPPY = 0x00000008,
+ RX_CONTEXT_FLAG_RECURSIVE_CALL = 0x00000010,
+ RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL = 0x00000020,
+ RX_CONTEXT_FLAG_DEFERRED_WRITE = 0x00000040,
+ RX_CONTEXT_FLAG_VERIFY_READ = 0x00000080,
+ RX_CONTEXT_FLAG_STACK_IO_CONTEZT = 0x00000100,
+ RX_CONTEXT_FLAG_IN_FSP = 0x00000200,
+ RX_CONTEXT_FLAG_CREATE_MAILSLOT = 0x00000400,
+ RX_CONTEXT_FLAG_MAILSLOT_REPARSE = 0x00000800,
+ RX_CONTEXT_FLAG_ASYNC_OPERATION = 0x00001000,
+ RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP = 0x00002000,
+ RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION = 0x00004000,
+ RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE = 0x00008000,
+ RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE = 0x00010000,
+ RX_CONTEXT_FLAG_MINIRDR_INVOKED = 0x00020000,
+ RX_CONTEXT_FLAG_WAITING_FOR_RESOURCE = 0x00040000,
+ RX_CONTEXT_FLAG_CANCELLED = 0x00080000,
+ RX_CONTEXT_FLAG_SYNC_EVENT_WAITERS = 0x00100000,
+ RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED = 0x00200000,
+ RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK = 0x00400000,
+ RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME = 0x00800000,
+ RX_CONTEXT_FLAG_IN_SERIALIZATION_QUEUE = 0x01000000,
+ RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT = 0x02000000,
+ RX_CONTEXT_FLAG_NEEDRECONNECT = 0x04000000,
+ RX_CONTEXT_FLAG_MUST_SUCCEED = 0x08000000,
+ RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING = 0x10000000,
+ RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED = 0x20000000,
+ RX_CONTEXT_FLAG_MINIRDR_INITIATED = 0x80000000,
+} RX_CONTEXT_FLAGS;
+
+typedef enum
+{
+ RX_CONTEXT_CREATE_FLAG_UNC_NAME = 0x1,
+ RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH = 0x2,
+ RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH = 0x4,
+ RX_CONTEXT_CREATE_FLAG_REPARSE = 0x8,
+ RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH = 0x10,
+} RX_CONTEXT_CREATE_FLAGS;
+
+typedef enum {
+ RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION = 0x1,
+ RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION = 0x2,
+ RXCONTEXT_FLAG4LOWIO_READAHEAD = 0x4,
+ RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED = 0x8,
+ RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED = 0x10,
+ RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD = 0x20,
+ RXCONTEXT_FLAG4LOWIO_LOCK_WAS_QUEUED_IN_LOCKMANAGER = 0x40,
+ RXCONTEXT_FLAG4LOWIO_THIS_IO_FAST = 0x80,
+ RXCONTEXT_FLAG4LOWIO_LOCK_OPERATION_COMPLETED = 0x100,
+ RXCONTEXT_FLAG4LOWIO_LOCK_BUFFERED_ON_ENTRY = 0x200
+} RX_CONTEXT_LOWIO_FLAGS;
+
+#if DBG
+VOID
+__RxItsTheSameContext(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ ULONG CapturedRxContextSerialNumber,
+ _In_ ULONG Line,
+ _In_ PCSTR File);
+#define RxItsTheSameContext() { __RxItsTheSameContext(RxContext, CapturedRxContextSerialNumber, __LINE__, __FILE__); }
+#else
+#define RxItsTheSameContext() { NOTHING; }
+#endif
+
+extern NPAGED_LOOKASIDE_LIST RxContextLookasideList;
+
+#define MINIRDR_CALL_THROUGH(STATUS, DISPATCH, FUNC, ARGLIST) \
+{ \
+ ASSERT(DISPATCH); \
+ ASSERT(NodeType(DISPATCH) == RDBSS_NTC_MINIRDR_DISPATCH); \
+ if (DISPATCH->FUNC == NULL) \
+ { \
+ STATUS = STATUS_NOT_IMPLEMENTED; \
+ } \
+ else \
+ { \
+ STATUS = DISPATCH->FUNC ARGLIST; \
+ } \
+}
+
+#define MINIRDR_CALL(STATUS, CONTEXT, DISPATCH, FUNC, ARGLIST) \
+{ \
+ ASSERT(DISPATCH); \
+ ASSERT(NodeType(DISPATCH) == RDBSS_NTC_MINIRDR_DISPATCH); \
+ if (DISPATCH->FUNC == NULL) \
+ { \
+ STATUS = STATUS_NOT_IMPLEMENTED; \
+ } \
+ else \
+ { \
+ if (!BooleanFlagOn((CONTEXT)->Flags, RX_CONTEXT_FLAG_CANCELLED)) \
+ { \
+ RtlZeroMemory(&((CONTEXT)->MRxContext[0]), \
+ sizeof((CONTEXT)->MRxContext)); \
+ STATUS = DISPATCH->FUNC ARGLIST; \
+ } \
+ else \
+ { \
+ STATUS = STATUS_CANCELLED; \
+ } \
+ } \
+}
+
+#define RxWaitSync(RxContext) \
+ (RxContext)->Flags |= RX_CONTEXT_FLAG_SYNC_EVENT_WAITERS; \
+ KeWaitForSingleObject(&(RxContext)->SyncEvent, \
+ Executive, KernelMode, FALSE, NULL)
+
+#define RxSignalSynchronousWaiter(RxContext) \
+ (RxContext)->Flags &= ~RX_CONTEXT_FLAG_SYNC_EVENT_WAITERS; \
+ KeSetEvent(&(RxContext)->SyncEvent, 0, FALSE)
+
+#define RxInsertContextInSerializationQueue(SerializationQueue, RxContext) \
+ (RxContext)->Flags |= RX_CONTEXT_FLAG_IN_SERIALIZATION_QUEUE; \
+ InsertTailList(SerializationQueue, &((RxContext)->RxContextSerializationQLinks))
+
+FORCEINLINE
+PRX_CONTEXT
+RxRemoveFirstContextFromSerializationQueue(
+ PLIST_ENTRY SerializationQueue)
+{
+ if (IsListEmpty(SerializationQueue))
+ {
+ return NULL;
+ }
+ else
+ {
+ PRX_CONTEXT Context = CONTAINING_RECORD(SerializationQueue->Flink,
+ RX_CONTEXT,
+ RxContextSerializationQLinks);
+
+ RemoveEntryList(SerializationQueue->Flink);
+
+ Context->RxContextSerializationQLinks.Flink = NULL;
+ Context->RxContextSerializationQLinks.Blink = NULL;
+
+ return Context;
+ }
+}
+
+#define RxTransferList(Destination, Source) \
+ if (IsListEmpty((Source))) \
+ InitializeListHead((Destination)); \
+ else \
+ { \
+ *(Destination) = *(Source); \
+ (Destination)->Flink->Blink = (Destination); \
+ (Destination)->Blink->Flink = (Destination); \
+ InitializeListHead((Source)); \
+ }
+
+VOID
+NTAPI
+RxInitializeContext(
+ _In_ PIRP Irp,
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ ULONG InitialContextFlags,
+ _Inout_ PRX_CONTEXT RxContext);
+
+PRX_CONTEXT
+NTAPI
+RxCreateRxContext(
+ _In_ PIRP Irp,
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ ULONG InitialContextFlags);
+
+VOID
+NTAPI
+RxPrepareContextForReuse(
+ _Inout_ PRX_CONTEXT RxContext);
+
+VOID
+NTAPI
+RxDereferenceAndDeleteRxContext_Real(
+ _In_ PRX_CONTEXT RxContext);
+
+#if DBG
+#define RxDereferenceAndDeleteRxContext(RXCONTEXT) \
+{ \
+ RxDereferenceAndDeleteRxContext_Real((RXCONTEXT)); \
+ (RXCONTEXT) = NULL; \
+}
+#else
+#define RxDereferenceAndDeleteRxContext(RXCONTEXT) \
+{ \
+ RxDereferenceAndDeleteRxContext_Real((RXCONTEXT)); \
+}
+#endif
+
+VOID
+NTAPI
+RxResumeBlockedOperations_Serially(
+ _Inout_ PRX_CONTEXT RxContext,
+ _Inout_ PLIST_ENTRY BlockingIoQ);
+
+#endif
--- /dev/null
+#ifndef _RDBSSDATA_
+#define _RDBSSDATA_
+
+extern RX_DISPATCHER RxDispatcher;
+extern RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
+
+extern KMUTEX RxSerializationMutex;
+#define RxAcquireSerializationMutex() KeWaitForSingleObject(&RxSerializationMutex, Executive, KernelMode, FALSE, NULL)
+#define RxReleaseSerializationMutex() KeReleaseMutex(&RxSerializationMutex, FALSE)
+
+extern PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
+
+#if DBG
+extern ULONG RxFsdEntryCount;
+#endif
+
+extern LIST_ENTRY RxSrvCalldownList;
+extern LIST_ENTRY RxActiveContexts;
+
+#endif
--- /dev/null
+#ifndef _RDBSSLOG_INCLUDED_
+#define _RDBSSLOG_INCLUDED_
+
+VOID
+NTAPI
+RxDebugControlCommand(
+ _In_ PSTR ControlString);
+
+NTSTATUS
+NTAPI
+RxInitializeLog(
+ VOID);
+
+#ifdef RDBSSLOG
+
+#if DBG
+#define RxLog(Args) _RxLog##Args
+#define RxLogRetail(Args) _RxLog##Args
+#else
+#define RxLogRetail(Args) _RxLog##Args
+#define RxLog(Args) { }
+#endif
+
+#define RxPauseLog() _RxPauseLog()
+#define RxResumeLog() _RxResumeLog()
+
+#else
+
+#define RxLog(Args) { ;}
+#define RxLogRetail(Args) { ;}
+#define RxPauseLog() { ; }
+#define RxResumeLog() { ; }
+
+#endif
+
+#endif
--- /dev/null
+#ifndef NO_RXOVRIDE_GLOBAL
+#include <struchdr.h>
+#endif
--- /dev/null
+#ifndef _RXPOOLTG_H_
+#define _RXPOOLTG_H_
+
+#define RX_SRVCALL_POOLTAG ('cSxR')
+#define RX_NETROOT_POOLTAG ('rNxR')
+#define RX_V_NETROOT_POOLTAG ('nVxR')
+#define RX_FCB_POOLTAG ('cFxR')
+#define RX_NONPAGEDFCB_POOLTAG ('fNxR')
+#define RX_WORKQ_POOLTAG ('qWxR')
+#define RX_MISC_POOLTAG ('sMxR')
+#define RX_IRPC_POOLTAG ('rIxR')
+
+#endif
--- /dev/null
+#ifndef _RDBSSPROCS_
+#define _RDBSSPROCS_
+
+#include "backpack.h"
+#include "rxlog.h"
+#include "rxtimer.h"
+#include "rxstruc.h"
+
+extern PVOID RxNull;
+
+#define RxLogFailure(DO, Originator, Event, Status) \
+ RxLogEventDirect(DO, Originator, Event, Status, __LINE__)
+
+VOID
+NTAPI
+RxLogEventDirect(
+ _In_ PRDBSS_DEVICE_OBJECT DeviceObject,
+ _In_ PUNICODE_STRING OriginatorId,
+ _In_ ULONG EventId,
+ _In_ NTSTATUS Status,
+ _In_ ULONG Line);
+
+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);
+
+NTSTATUS
+RxPrefixClaim(
+ _In_ PRX_CONTEXT RxContext);
+
+VOID
+RxpPrepareCreateContextForReuse(
+ _In_ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxLowIoCompletionTail(
+ _In_ PRX_CONTEXT RxContext);
+
+LUID
+RxGetUid(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext);
+
+ULONG
+RxGetSessionId(
+ _In_ PIO_STACK_LOCATION IrpSp);
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+RxFindOrCreateConnections(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _In_ BOOLEAN TreeConnect,
+ _Out_ PUNICODE_STRING LocalNetRootName,
+ _Out_ PUNICODE_STRING FilePathName,
+ _Inout_ PLOCK_HOLDING_STATE LockState,
+ _In_ PRX_CONNECTION_ID RxConnectionId);
+#else
+NTSTATUS
+RxFindOrCreateConnections(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _Out_ PUNICODE_STRING LocalNetRootName,
+ _Out_ PUNICODE_STRING FilePathName,
+ _Inout_ PLOCK_HOLDING_STATE LockState,
+ _In_ PRX_CONNECTION_ID RxConnectionId);
+#endif
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+RxCompleteMdl(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp);
+#else
+NTSTATUS
+NTAPI
+RxCompleteMdl(
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+#if (_WIN32_WINNT >= 0x0600)
+VOID
+RxLockUserBuffer(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ LOCK_OPERATION Operation,
+ _In_ ULONG BufferLength);
+
+PVOID
+RxMapSystemBuffer(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp);
+#else
+VOID
+RxLockUserBuffer(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ LOCK_OPERATION Operation,
+ _In_ ULONG BufferLength);
+
+PVOID
+RxMapSystemBuffer(
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+#define FCB_MODE_EXCLUSIVE 1
+#define FCB_MODE_SHARED 2
+#define FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE 3
+#define FCB_MODE_SHARED_STARVE_EXCLUSIVE 4
+
+NTSTATUS
+__RxAcquireFcb(
+ _Inout_ PFCB Fcb,
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _In_ ULONG Mode
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ );
+
+#ifdef RDBSS_TRACKER
+#define RxAcquireExclusiveFcb(R, F) __RxAcquireFcb((F), (R), FCB_MODE_EXCLUSIVE, __LINE__, __FILE__, 0)
+#else
+#define RxAcquireExclusiveFcb(R, F) __RxAcquireFcb((F), (R), FCB_MODE_EXCLUSIVE)
+#endif
+
+#define RX_GET_MRX_FCB(F) ((PMRX_FCB)((F)))
+
+#ifdef RDBSS_TRACKER
+#define RxAcquireSharedFcb(R, F) __RxAcquireFcb((F), (R), FCB_MODE_SHARED, __LINE__, __FILE__, 0)
+#else
+#define RxAcquireSharedFcb(R, F) __RxAcquireFcb((F), (R), FCB_MODE_SHARED)
+#endif
+
+#ifdef RDBSS_TRACKER
+#define RxAcquireSharedFcbWaitForEx(R, F) __RxAcquireFcb((F),(R), FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE, __LINE__, __FILE__,0)
+#else
+#define RxAcquireSharedFcbWaitForEx(R, F) __RxAcquireFcb((F), (R), FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE)
+#endif
+
+VOID
+__RxReleaseFcb(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ );
+
+#ifdef RDBSS_TRACKER
+#define RxReleaseFcb(R, F) __RxReleaseFcb((R), RX_GET_MRX_FCB(F), __LINE__, __FILE__, 0)
+#else
+#define RxReleaseFcb(R, F) __RxReleaseFcb((R), RX_GET_MRX_FCB(F))
+#endif
+
+VOID
+__RxReleaseFcbForThread(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb,
+ _In_ ERESOURCE_THREAD ResourceThreadId
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ );
+
+#ifdef RDBSS_TRACKER
+#define RxReleaseFcbForThread(R, F, T) __RxReleaseFcbForThread((R), RX_GET_MRX_FCB(F), (T), __LINE__, __FILE__, 0)
+#else
+#define RxReleaseFcbForThread(R, F, T) __RxReleaseFcbForThread((R), RX_GET_MRX_FCB(F), (T))
+#endif
+
+#ifdef RDBSS_TRACKER
+VOID
+RxTrackerUpdateHistory(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb,
+ _In_ ULONG Operation,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber);
+#else
+#define RxTrackerUpdateHistory(R, F, O, L, F, S) { NOTHING; }
+#endif
+
+VOID
+RxTrackPagingIoResource(
+ _Inout_ PVOID Instance,
+ _In_ ULONG Type,
+ _In_ ULONG Line,
+ _In_ PCSTR File);
+
+#define RxIsFcbAcquiredShared(Fcb) ExIsResourceAcquiredSharedLite((Fcb)->Header.Resource)
+#define RxIsFcbAcquiredExclusive(Fcb) ExIsResourceAcquiredExclusiveLite((Fcb)->Header.Resource)
+#define RxIsFcbAcquired(Fcb) (ExIsResourceAcquiredSharedLite((Fcb)->Header.Resource) || \
+ ExIsResourceAcquiredExclusiveLite((Fcb)->Header.Resource))
+
+#define RxAcquirePagingIoResource(RxContext, Fcb) \
+ ExAcquireResourceExclusiveLite((Fcb)->Header.PagingIoResource, TRUE); \
+ if (RxContext != NULL) \
+ { \
+ (RxContext)->FcbPagingIoResourceAcquired = TRUE; \
+ } \
+ RxTrackPagingIoResource(Fcb, 1, __LINE__, __FILE__)
+
+#define RxAcquirePagingIoResourceShared(RxContext, Fcb, Flag) \
+ ExAcquireResourceSharedLite((Fcb)->Header.PagingIoResource, Flag); \
+ if (AcquiredFile) \
+ { \
+ if (RxContext != NULL) \
+ { \
+ ((PRX_CONTEXT)RxContext)->FcbPagingIoResourceAcquired = TRUE; \
+ } \
+ RxTrackPagingIoResource(Fcb, 2, __LINE__, __FILE__); \
+ }
+
+#define RxReleasePagingIoResource(RxContext, Fcb) \
+ RxTrackPagingIoResource(Fcb, 3, __LINE__, __FILE__); \
+ if (RxContext != NULL) \
+ { \
+ (RxContext)->FcbPagingIoResourceAcquired = FALSE; \
+ } \
+ ExReleaseResourceLite((Fcb)->Header.PagingIoResource)
+
+#define RxReleasePagingIoResourceForThread(RxContext, Fcb, Thread) \
+ RxTrackPagingIoResource(Fcb, 3, __LINE__, __FILE__); \
+ if (RxContext != NULL) \
+ { \
+ (RxContext)->FcbPagingIoResourceAcquired = FALSE; \
+ } \
+ ExReleaseResourceForThreadLite((Fcb)->Header.PagingIoResource, (Thread))
+
+BOOLEAN
+NTAPI
+RxAcquireFcbForLazyWrite(
+ _In_ PVOID Null,
+ _In_ BOOLEAN Wait);
+
+VOID
+NTAPI
+RxReleaseFcbFromLazyWrite(
+ _In_ PVOID Null);
+
+BOOLEAN
+NTAPI
+RxAcquireFcbForReadAhead(
+ _In_ PVOID Null,
+ _In_ BOOLEAN Wait);
+
+VOID
+NTAPI
+RxReleaseFcbFromReadAhead(
+ _In_ PVOID Null);
+
+BOOLEAN
+NTAPI
+RxNoOpAcquire(
+ _In_ PVOID Fcb,
+ _In_ BOOLEAN Wait);
+
+VOID
+NTAPI
+RxNoOpRelease(
+ _In_ PVOID Fcb);
+
+#define RxConvertToSharedFcb(R, F) ExConvertExclusiveToSharedLite(RX_GET_MRX_FCB(F)->Header.Resource)
+
+VOID
+RxVerifyOperationIsLegal(
+ _In_ PRX_CONTEXT RxContext);
+
+VOID
+RxPrePostIrp(
+ _In_ PVOID Context,
+ _In_ PIRP Irp);
+
+VOID
+RxAddToWorkque(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp);
+
+NTSTATUS
+RxFsdPostRequest(
+ _In_ PRX_CONTEXT RxContext);
+
+#define QuadAlign(V) (ALIGN_UP(V, ULONGLONG))
+
+VOID
+RxCompleteRequest_Real(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ NTSTATUS Status);
+
+NTSTATUS
+RxCompleteRequest(
+ _In_ PRX_CONTEXT pContext,
+ _In_ NTSTATUS Status);
+
+#if (_WIN32_WINNT >= 0x600)
+NTSTATUS
+RxConstructSrvCall(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PSRV_CALL SrvCall,
+ _Out_ PLOCK_HOLDING_STATE LockHoldingState);
+#else
+NTSTATUS
+RxConstructSrvCall(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PSRV_CALL SrvCall,
+ _Out_ PLOCK_HOLDING_STATE LockHoldingState);
+#endif
+
+#define RxCompleteAsynchronousRequest(C, S) RxCompleteRequest(C, S)
+
+NTSTATUS
+RxConstructNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PSRV_CALL SrvCall,
+ _In_ PNET_ROOT NetRoot,
+ _In_ PV_NET_ROOT VirtualNetRoot,
+ _Out_ PLOCK_HOLDING_STATE LockHoldingState);
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+RxConstructVirtualNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _In_ BOOLEAN TreeConnect,
+ _Out_ PV_NET_ROOT *VirtualNetRootPointer,
+ _Out_ PLOCK_HOLDING_STATE LockHoldingState,
+ _Out_ PRX_CONNECTION_ID RxConnectionId);
+
+NTSTATUS
+RxFindOrConstructVirtualNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PIRP Irp,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _In_ PUNICODE_STRING RemainingName);
+#else
+NTSTATUS
+RxConstructVirtualNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _Out_ PV_NET_ROOT *VirtualNetRootPointer,
+ _Out_ PLOCK_HOLDING_STATE LockHoldingState,
+ _Out_ PRX_CONNECTION_ID RxConnectionId);
+
+NTSTATUS
+RxFindOrConstructVirtualNetRoot(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _In_ PUNICODE_STRING RemainingName);
+#endif
+
+NTSTATUS
+NTAPI
+RxChangeBufferingState(
+ PSRV_OPEN SrvOpen,
+ PVOID Context,
+ BOOLEAN ComputeNewState);
+
+VOID
+NTAPI
+RxIndicateChangeOfBufferingStateForSrvOpen(
+ PMRX_SRV_CALL SrvCall,
+ PMRX_SRV_OPEN SrvOpen,
+ PVOID SrvOpenKey,
+ PVOID Context);
+
+NTSTATUS
+NTAPI
+RxPrepareToReparseSymbolicLink(
+ PRX_CONTEXT RxContext,
+ BOOLEAN SymbolicLinkEmbeddedInOldPath,
+ PUNICODE_STRING NewPath,
+ BOOLEAN NewPathIsAbsolute,
+ PBOOLEAN ReparseRequired);
+
+VOID
+RxReference(
+ _Inout_ PVOID Instance);
+
+VOID
+RxDereference(
+ _Inout_ PVOID Instance,
+ _In_ LOCK_HOLDING_STATE LockHoldingState);
+
+VOID
+RxWaitForStableCondition(
+ _In_ PRX_BLOCK_CONDITION Condition,
+ _Inout_ PLIST_ENTRY TransitionWaitList,
+ _Inout_ PRX_CONTEXT RxContext,
+ _Out_opt_ NTSTATUS *AsyncStatus);
+
+VOID
+RxUpdateCondition(
+ _In_ RX_BLOCK_CONDITION NewConditionValue,
+ _Out_ PRX_BLOCK_CONDITION Condition,
+ _In_ OUT PLIST_ENTRY TransitionWaitList);
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+RxCloseAssociatedSrvOpen(
+ _In_opt_ PRX_CONTEXT RxContext,
+ _In_ PFOBX Fobx);
+#else
+NTSTATUS
+RxCloseAssociatedSrvOpen(
+ _In_ PFOBX Fobx,
+ _In_opt_ PRX_CONTEXT RxContext);
+#endif
+
+NTSTATUS
+NTAPI
+RxFinalizeConnection(
+ _Inout_ PNET_ROOT NetRoot,
+ _Inout_opt_ PV_NET_ROOT VNetRoot,
+ _In_ LOGICAL ForceFilesClosed);
+
+#if DBG
+VOID
+RxDumpWantedAccess(
+ _In_ PSZ where1,
+ _In_ PSZ where2,
+ _In_ PSZ wherelogtag,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ ULONG DesiredShareAccess);
+
+VOID
+RxDumpCurrentAccess(
+ _In_ PSZ where1,
+ _In_ PSZ where2,
+ _In_ PSZ wherelogtag,
+ _In_ PSHARE_ACCESS ShareAccess);
+#else
+#define RxDumpWantedAccess(w1,w2,wlt,DA,DSA) {NOTHING;}
+#define RxDumpCurrentAccess(w1,w2,wlt,SA) {NOTHING;}
+#endif
+
+NTSTATUS
+RxCheckShareAccessPerSrvOpens(
+ _In_ PFCB Fcb,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ ULONG DesiredShareAccess);
+
+VOID
+RxUpdateShareAccessPerSrvOpens(
+ _In_ PSRV_OPEN SrvOpen);
+
+#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);
+
+VOID
+RxRemoveShareAccess(
+ _Inout_ PFILE_OBJECT FileObject,
+ _Inout_ PSHARE_ACCESS ShareAccess,
+ _In_ PSZ where,
+ _In_ PSZ wherelogtag);
+
+VOID
+RxSetShareAccess(
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ ULONG DesiredShareAccess,
+ _Inout_ PFILE_OBJECT FileObject,
+ _Out_ PSHARE_ACCESS ShareAccess,
+ _In_ PSZ where,
+ _In_ PSZ wherelogtag);
+
+VOID
+RxUpdateShareAccess(
+ _Inout_ PFILE_OBJECT FileObject,
+ _Inout_ PSHARE_ACCESS ShareAccess,
+ _In_ PSZ where,
+ _In_ PSZ wherelogtag);
+#else
+#define RxCheckShareAccess(a1, a2, a3, a4, a5, a6, a7) IoCheckShareAccess(a1, a2, a3, a4, a5)
+#define RxRemoveShareAccess(a1, a2, a3, a4) IoRemoveShareAccess(a1, a2)
+#define RxSetShareAccess(a1, a2, a3, a4, a5, a6) IoSetShareAccess(a1, a2, a3, a4)
+#define RxUpdateShareAccess(a1, a2, a3, a4) IoUpdateShareAccess(a1, a2)
+#endif
+
+NTSTATUS
+NTAPI
+RxDriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath);
+
+VOID
+NTAPI
+RxUnload(
+ _In_ PDRIVER_OBJECT DriverObject);
+
+VOID
+RxInitializeMinirdrDispatchTable(
+ _In_ PDRIVER_OBJECT DriverObject);
+
+ULONG
+RxGetNetworkProviderPriority(
+ _In_ PUNICODE_STRING DeviceName);
+
+ULONG
+RxTableComputePathHashValue(
+ _In_ PUNICODE_STRING Name);
+
+VOID
+RxExtractServerName(
+ _In_ PUNICODE_STRING FilePathName,
+ _Out_ PUNICODE_STRING SrvCallName,
+ _Out_ PUNICODE_STRING RestOfName);
+
+VOID
+NTAPI
+RxCreateNetRootCallBack(
+ _In_ PMRX_CREATENETROOT_CONTEXT CreateNetRootContext);
+
+PVOID
+RxAllocateObject(
+ _In_ NODE_TYPE_CODE NodeType,
+ _In_opt_ PMINIRDR_DISPATCH MRxDispatch,
+ _In_ ULONG NameLength);
+
+VOID
+RxFreeObject(
+ _In_ PVOID pObject);
+
+NTSTATUS
+RxInitializeSrvCallParameters(
+ _In_ PRX_CONTEXT RxContext,
+ _Inout_ PSRV_CALL SrvCall);
+
+VOID
+RxAddVirtualNetRootToNetRoot(
+ _In_ PNET_ROOT NetRoot,
+ _In_ PV_NET_ROOT VNetRoot);
+
+PVOID
+RxAllocateFcbObject(
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ _In_ NODE_TYPE_CODE NodeType,
+ _In_ POOL_TYPE PoolType,
+ _In_ ULONG NameSize,
+ _In_opt_ PVOID AlreadyAllocatedObject);
+
+VOID
+RxFreeFcbObject(
+ _In_ PVOID Object);
+
+BOOLEAN
+RxFinalizeNetFcb(
+ _Out_ PFCB ThisFcb,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize,
+ _In_ LONG ReferenceCount);
+
+BOOLEAN
+RxIsThisACscAgentOpen(
+ _In_ PRX_CONTEXT RxContext);
+
+VOID
+NTAPI
+RxCheckFcbStructuresForAlignment(
+ VOID);
+
+NTSTATUS
+RxInitializeWorkQueueDispatcher(
+ _In_ PRX_WORK_QUEUE_DISPATCHER Dispatcher);
+
+VOID
+RxInitializeWorkQueue(
+ _In_ PRX_WORK_QUEUE WorkQueue,
+ _In_ WORK_QUEUE_TYPE WorkQueueType,
+ _In_ ULONG MaximumNumberOfWorkerThreads,
+ _In_ ULONG MinimumNumberOfWorkerThreads);
+
+NTSTATUS
+RxSpinUpWorkerThread(
+ _In_ PRX_WORK_QUEUE WorkQueue,
+ _In_ PRX_WORKERTHREAD_ROUTINE Routine,
+ _In_ PVOID Parameter);
+
+VOID
+RxSpinUpWorkerThreads(
+ _In_ PRX_WORK_QUEUE WorkQueue);
+
+VOID
+NTAPI
+RxSpinUpRequestsDispatcher(
+ _In_ PVOID Dispatcher);
+
+VOID
+RxpWorkerThreadDispatcher(
+ _In_ PRX_WORK_QUEUE WorkQueue,
+ _In_ PLARGE_INTEGER WaitInterval);
+
+VOID
+NTAPI
+RxBootstrapWorkerThreadDispatcher(
+ _In_ PVOID WorkQueue);
+
+PRX_PREFIX_ENTRY
+RxTableLookupName_ExactLengthMatch(
+ _In_ PRX_PREFIX_TABLE ThisTable,
+ _In_ PUNICODE_STRING Name,
+ _In_ ULONG HashValue,
+ _In_opt_ PRX_CONNECTION_ID RxConnectionId);
+
+PVOID
+RxTableLookupName(
+ _In_ PRX_PREFIX_TABLE ThisTable,
+ _In_ PUNICODE_STRING Name,
+ _Out_ PUNICODE_STRING RemainingName,
+ _In_opt_ PRX_CONNECTION_ID RxConnectionId);
+
+VOID
+RxOrphanThisFcb(
+ _In_ PFCB Fcb);
+
+#define RxEqualConnectionId(C1, C2) RtlEqualMemory(C1, C2, sizeof(RX_CONNECTION_ID))
+
+NTSTATUS
+NTAPI
+RxLockOperationCompletion(
+ _In_ PVOID Context,
+ _In_ PIRP Irp);
+
+VOID
+NTAPI
+RxUnlockOperation(
+ _In_ PVOID Context,
+ _In_ PFILE_LOCK_INFO LockInfo);
+
+#if (_WIN32_WINNT >= 0x0600)
+NTSTATUS
+RxPostStackOverflowRead(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PFCB Fcb);
+#else
+NTSTATUS
+RxPostStackOverflowRead(
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+VOID
+NTAPI
+RxCancelRoutine(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp);
+
+#endif
--- /dev/null
+#ifndef _RDBSSSTRUC_
+#define _RDBSSSTRUC_
+
+#include "prefix.h"
+#include "lowio.h"
+#include "scavengr.h"
+#include "rxcontx.h"
+#include "fcb.h"
+
+extern RX_SPIN_LOCK RxStrucSupSpinLock;
+
+typedef struct _RDBSS_EXPORTS
+{
+ PRX_SPIN_LOCK pRxStrucSupSpinLock;
+ PLONG pRxDebugTraceIndent;
+} RDBSS_EXPORTS, *PRDBSS_EXPORTS;
+
+typedef enum _LOCK_HOLDING_STATE
+{
+ LHS_LockNotHeld,
+ LHS_SharedLockHeld,
+ LHS_ExclusiveLockHeld
+} LOCK_HOLDING_STATE, *PLOCK_HOLDING_STATE;
+
+typedef struct _RDBSS_DATA
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+ PDRIVER_OBJECT DriverObject;
+ volatile LONG NumberOfMinirdrsStarted;
+ FAST_MUTEX MinirdrRegistrationMutex;
+ LIST_ENTRY RegisteredMiniRdrs;
+ LONG NumberOfMinirdrsRegistered;
+ PEPROCESS OurProcess;
+ CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
+#if (_WIN32_WINNT < 0x0600)
+ CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks;
+#endif
+ ERESOURCE Resource;
+} RDBSS_DATA;
+typedef RDBSS_DATA *PRDBSS_DATA;
+
+extern RDBSS_DATA RxData;
+
+PEPROCESS
+NTAPI
+RxGetRDBSSProcess(
+ VOID);
+
+typedef enum _RX_RDBSS_STATE_
+{
+ RDBSS_STARTABLE = 0,
+ RDBSS_STARTED,
+ RDBSS_STOP_IN_PROGRESS
+} RX_RDBSS_STATE, *PRX_RDBSS_STATE;
+
+typedef struct _RDBSS_STARTSTOP_CONTEXT_
+{
+ RX_RDBSS_STATE State;
+ ULONG Version;
+ PRX_CONTEXT pStopContext;
+} RDBSS_STARTSTOP_CONTEXT, *PRDBSS_STARTSTOP_CONTEXT;
+
+typedef struct _RX_DISPATCHER_CONTEXT_
+{
+ volatile LONG NumberOfWorkerThreads;
+ volatile PKEVENT pTearDownEvent;
+} RX_DISPATCHER_CONTEXT, *PRX_DISPATCHER_CONTEXT;
+
+#define RxSetRdbssState(RxDeviceObject, NewState) \
+{ \
+ KIRQL OldIrql; \
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); \
+ RxDeviceObject->StartStopContext.State = (NewState); \
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); \
+}
+
+#define RxGetRdbssState(RxDeviceObject) RxDeviceObject->StartStopContext.State
+
+typedef struct _RDBSS_DEVICE_OBJECT {
+ union
+ {
+ DEVICE_OBJECT DeviceObject;
+ DEVICE_OBJECT;
+ };
+ ULONG RegistrationControls;
+ PRDBSS_EXPORTS RdbssExports;
+ PDEVICE_OBJECT RDBSSDeviceObject;
+ PMINIRDR_DISPATCH Dispatch;
+ UNICODE_STRING DeviceName;
+ ULONG NetworkProviderPriority;
+ HANDLE MupHandle;
+ BOOLEAN RegisterUncProvider;
+ BOOLEAN RegisterMailSlotProvider;
+ BOOLEAN RegisteredAsFileSystem;
+ BOOLEAN Unused;
+ LIST_ENTRY MiniRdrListLinks;
+ volatile ULONG NumberOfActiveFcbs;
+ volatile ULONG NumberOfActiveContexts;
+ struct
+ {
+ LARGE_INTEGER PagingReadBytesRequested;
+ LARGE_INTEGER NonPagingReadBytesRequested;
+ LARGE_INTEGER CacheReadBytesRequested;
+ LARGE_INTEGER FastReadBytesRequested;
+ LARGE_INTEGER NetworkReadBytesRequested;
+ volatile ULONG ReadOperations;
+ ULONG FastReadOperations;
+ volatile ULONG RandomReadOperations;
+ LARGE_INTEGER PagingWriteBytesRequested;
+ LARGE_INTEGER NonPagingWriteBytesRequested;
+ LARGE_INTEGER CacheWriteBytesRequested;
+ LARGE_INTEGER FastWriteBytesRequested;
+ LARGE_INTEGER NetworkWriteBytesRequested;
+ volatile ULONG WriteOperations;
+ ULONG FastWriteOperations;
+ volatile ULONG RandomWriteOperations;
+ };
+ volatile LONG PostedRequestCount[RxMaximumWorkQueue];
+ LONG OverflowQueueCount[RxMaximumWorkQueue];
+ LIST_ENTRY OverflowQueue[RxMaximumWorkQueue];
+ RX_SPIN_LOCK OverflowQueueSpinLock;
+ LONG AsynchronousRequestsPending;
+ PKEVENT pAsynchronousRequestsCompletionEvent;
+ RDBSS_STARTSTOP_CONTEXT StartStopContext;
+ RX_DISPATCHER_CONTEXT DispatcherContext;
+ PRX_PREFIX_TABLE pRxNetNameTable;
+ RX_PREFIX_TABLE RxNetNameTableInDeviceObject;
+ PRDBSS_SCAVENGER pRdbssScavenger;
+ RDBSS_SCAVENGER RdbssScavengerInDeviceObject;
+} RDBSS_DEVICE_OBJECT, *PRDBSS_DEVICE_OBJECT;
+
+extern INLINE
+VOID
+NTAPI
+RxUnregisterMinirdr(
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+ PDEVICE_OBJECT RDBSSDeviceObject;
+
+ RDBSSDeviceObject = RxDeviceObject->RDBSSDeviceObject;
+
+ RxpUnregisterMinirdr(RxDeviceObject);
+
+ if (RDBSSDeviceObject != NULL)
+ {
+ ObDereferenceObject(RDBSSDeviceObject);
+ }
+}
+
+#endif
--- /dev/null
+#ifndef _RXTIMER_H_
+#define _RXTIMER_H_
+
+typedef struct _RX_WORK_ITEM_
+{
+ RX_WORK_QUEUE_ITEM WorkQueueItem;
+ ULONG LastTick;
+ ULONG Options;
+} RX_WORK_ITEM, *PRX_WORK_ITEM;
+
+NTSTATUS
+NTAPI
+RxInitializeRxTimer(
+ VOID);
+
+#endif
--- /dev/null
+#ifndef _RXTYPES_INCL
+#define _RXTYPES_INCL
+
+#include "nodetype.h"
+
+#define RxMaximumWorkQueue 3
+
+typedef KSPIN_LOCK RX_SPIN_LOCK;
+typedef PKSPIN_LOCK PRX_SPIN_LOCK;
+
+#endif
--- /dev/null
+#ifndef _RXWORKQ_H_
+#define _RXWORKQ_H_
+
+typedef
+VOID
+(NTAPI *PRX_WORKERTHREAD_ROUTINE) (
+ _In_ PVOID Context);
+
+typedef struct _RX_WORK_QUEUE_ITEM_
+{
+ WORK_QUEUE_ITEM;
+ PRDBSS_DEVICE_OBJECT pDeviceObject;
+} RX_WORK_QUEUE_ITEM, *PRX_WORK_QUEUE_ITEM;
+
+typedef struct _RX_WORK_DISPATCH_ITEM_
+{
+ RX_WORK_QUEUE_ITEM WorkQueueItem;
+ PRX_WORKERTHREAD_ROUTINE DispatchRoutine;
+ PVOID DispatchRoutineParameter;
+} RX_WORK_DISPATCH_ITEM, *PRX_WORK_DISPATCH_ITEM;
+
+typedef enum _RX_WORK_QUEUE_STATE_
+{
+ RxWorkQueueActive,
+ RxWorkQueueInactive,
+ RxWorkQueueRundownInProgress
+} RX_WORK_QUEUE_STATE, *PRX_WORK_QUEUE_STATE;
+
+typedef struct _RX_WORK_QUEUE_RUNDOWN_CONTEXT_
+{
+ KEVENT RundownCompletionEvent;
+ LONG NumberOfThreadsSpunDown;
+ PETHREAD *ThreadPointers;
+} RX_WORK_QUEUE_RUNDOWN_CONTEXT, *PRX_WORK_QUEUE_RUNDOWN_CONTEXT;
+
+typedef struct _RX_WORK_QUEUE_
+{
+ USHORT State;
+ BOOLEAN SpinUpRequestPending;
+ UCHAR Type;
+ KSPIN_LOCK SpinLock;
+ PRX_WORK_QUEUE_RUNDOWN_CONTEXT pRundownContext;
+ __volatile LONG NumberOfWorkItemsDispatched;
+ __volatile LONG NumberOfWorkItemsToBeDispatched;
+ LONG CumulativeQueueLength;
+ LONG NumberOfSpinUpRequests;
+ LONG MaximumNumberOfWorkerThreads;
+ LONG MinimumNumberOfWorkerThreads;
+ __volatile LONG NumberOfActiveWorkerThreads;
+ __volatile LONG NumberOfIdleWorkerThreads;
+ LONG NumberOfFailedSpinUpRequests;
+ __volatile LONG WorkQueueItemForSpinUpWorkerThreadInUse;
+ RX_WORK_QUEUE_ITEM WorkQueueItemForTearDownWorkQueue;
+ RX_WORK_QUEUE_ITEM WorkQueueItemForSpinUpWorkerThread;
+ RX_WORK_QUEUE_ITEM WorkQueueItemForSpinDownWorkerThread;
+ KQUEUE Queue;
+ PETHREAD *ThreadPointers;
+} RX_WORK_QUEUE, *PRX_WORK_QUEUE;
+
+typedef struct _RX_WORK_QUEUE_DISPATCHER_
+{
+ RX_WORK_QUEUE WorkQueue[RxMaximumWorkQueue];
+} RX_WORK_QUEUE_DISPATCHER, *PRX_WORK_QUEUE_DISPATCHER;
+
+typedef enum _RX_DISPATCHER_STATE_
+{
+ RxDispatcherActive,
+ RxDispatcherInactive
+} RX_DISPATCHER_STATE, *PRX_DISPATCHER_STATE;
+
+typedef struct _RX_DISPATCHER_
+{
+ LONG NumberOfProcessors;
+ PEPROCESS OwnerProcess;
+ PRX_WORK_QUEUE_DISPATCHER pWorkQueueDispatcher;
+ RX_DISPATCHER_STATE State;
+ LIST_ENTRY SpinUpRequests;
+ KSPIN_LOCK SpinUpRequestsLock;
+ KEVENT SpinUpRequestsEvent;
+ KEVENT SpinUpRequestsTearDownEvent;
+} RX_DISPATCHER, *PRX_DISPATCHER;
+
+NTSTATUS
+NTAPI
+RxDispatchToWorkerThread(
+ _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ _In_ WORK_QUEUE_TYPE WorkQueueType,
+ _In_ PRX_WORKERTHREAD_ROUTINE Routine,
+ _In_ PVOID pContext);
+
+NTSTATUS
+NTAPI
+RxInitializeDispatcher(
+ VOID);
+
+NTSTATUS
+RxInitializeMRxDispatcher(
+ _Inout_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject);
+
+#endif
--- /dev/null
+#ifndef _SCAVENGR_H_
+#define _SCAVENGR_H_
+
+extern KMUTEX RxScavengerMutex;
+
+#define RX_SCAVENGER_FINALIZATION_TIME_INTERVAL (10 * 1000 * 1000 * 10)
+
+typedef struct _RX_SCAVENGER_ENTRY
+{
+ LIST_ENTRY List;
+ UCHAR Type;
+ UCHAR Operation;
+ UCHAR State;
+ UCHAR Flags;
+ struct _RX_SCAVENGER_ENTRY *pContinuationEntry;
+} RX_SCAVENGER_ENTRY, *PRX_SCAVENGER_ENTRY;
+
+#define RxInitializeScavengerEntry(ScavengerEntry) \
+ (ScavengerEntry)->State = 0; \
+ (ScavengerEntry)->Flags = 0; \
+ (ScavengerEntry)->Type = 0; \
+ (ScavengerEntry)->Operation = 0; \
+ InitializeListHead(&(ScavengerEntry)->List); \
+ (ScavengerEntry)->pContinuationEntry = NULL
+
+#define RxAcquireScavengerMutex() KeWaitForSingleObject(&RxScavengerMutex, Executive, KernelMode, FALSE, NULL)
+#define RxReleaseScavengerMutex() KeReleaseMutex(&RxScavengerMutex, FALSE)
+
+VOID
+RxMarkFobxOnCleanup(
+ _In_ PFOBX pFobx,
+ _Out_ PBOOLEAN NeedPurge);
+
+VOID
+RxMarkFobxOnClose(
+ _In_ PFOBX Fobx);
+
+typedef enum _RDBSS_SCAVENGER_STATE
+{
+ RDBSS_SCAVENGER_INACTIVE,
+ RDBSS_SCAVENGER_DORMANT,
+ RDBSS_SCAVENGER_ACTIVE,
+ RDBSS_SCAVENGER_SUSPENDED
+} RDBSS_SCAVENGER_STATE, *PRDBSS_SCAVENGER_STATE;
+
+typedef struct _RDBSS_SCAVENGER
+{
+ RDBSS_SCAVENGER_STATE State;
+ LONG MaximumNumberOfDormantFiles;
+ volatile LONG NumberOfDormantFiles;
+ LARGE_INTEGER TimeLimit;
+ ULONG SrvCallsToBeFinalized;
+ ULONG NetRootsToBeFinalized;
+ ULONG VNetRootsToBeFinalized;
+ ULONG FcbsToBeFinalized;
+ ULONG SrvOpensToBeFinalized;
+ ULONG FobxsToBeFinalized;
+ LIST_ENTRY SrvCallFinalizationList;
+ LIST_ENTRY NetRootFinalizationList;
+ LIST_ENTRY VNetRootFinalizationList;
+ LIST_ENTRY FcbFinalizationList;
+ LIST_ENTRY SrvOpenFinalizationList;
+ LIST_ENTRY FobxFinalizationList;
+ LIST_ENTRY ClosePendingFobxsList;
+ RX_WORK_ITEM WorkItem;
+ KEVENT SyncEvent;
+ KEVENT ScavengeEvent;
+ PETHREAD CurrentScavengerThread;
+ PNET_ROOT CurrentNetRootForClosePendingProcessing;
+ PFCB CurrentFcbForClosePendingProcessing;
+ KEVENT ClosePendingProcessingSyncEvent;
+} RDBSS_SCAVENGER, *PRDBSS_SCAVENGER;
+
+#define RxInitializeRdbssScavenger(Scavenger, ScavengerTimeLimit) \
+ (Scavenger)->State = RDBSS_SCAVENGER_INACTIVE; \
+ (Scavenger)->SrvCallsToBeFinalized = 0; \
+ (Scavenger)->NetRootsToBeFinalized = 0; \
+ (Scavenger)->VNetRootsToBeFinalized = 0; \
+ (Scavenger)->FcbsToBeFinalized = 0; \
+ (Scavenger)->SrvOpensToBeFinalized = 0; \
+ (Scavenger)->FobxsToBeFinalized = 0; \
+ (Scavenger)->NumberOfDormantFiles = 0; \
+ (Scavenger)->MaximumNumberOfDormantFiles = 50; \
+ (Scavenger)->CurrentFcbForClosePendingProcessing = NULL; \
+ (Scavenger)->CurrentNetRootForClosePendingProcessing = NULL; \
+ if ((ScavengerTimeLimit).QuadPart == 0) \
+ { \
+ (Scavenger)->TimeLimit.QuadPart = RX_SCAVENGER_FINALIZATION_TIME_INTERVAL; \
+ } \
+ else \
+ { \
+ (Scavenger)->TimeLimit.QuadPart = (ScavengerTimeLimit).QuadPart; \
+ } \
+ KeInitializeEvent(&((Scavenger)->SyncEvent), NotificationEvent, FALSE); \
+ KeInitializeEvent(&((Scavenger)->ScavengeEvent), SynchronizationEvent, TRUE); \
+ KeInitializeEvent(&((Scavenger)->ClosePendingProcessingSyncEvent), NotificationEvent, FALSE); \
+ InitializeListHead(&(Scavenger)->SrvCallFinalizationList); \
+ InitializeListHead(&(Scavenger)->NetRootFinalizationList); \
+ InitializeListHead(&(Scavenger)->VNetRootFinalizationList); \
+ InitializeListHead(&(Scavenger)->SrvOpenFinalizationList); \
+ InitializeListHead(&(Scavenger)->FcbFinalizationList); \
+ InitializeListHead(&(Scavenger)->FobxFinalizationList); \
+ InitializeListHead(&(Scavenger)->ClosePendingFobxsList)
+
+typedef struct _PURGE_SYNCHRONIZATION_CONTEXT
+{
+ LIST_ENTRY ContextsAwaitingPurgeCompletion;
+ BOOLEAN PurgeInProgress;
+} PURGE_SYNCHRONIZATION_CONTEXT, *PPURGE_SYNCHRONIZATION_CONTEXT;
+
+VOID
+RxInitializePurgeSyncronizationContext(
+ _In_ PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext);
+
+BOOLEAN
+RxScavengeRelatedFobxs(
+ _In_ PFCB Fcb);
+
+VOID
+RxpUndoScavengerFinalizationMarking(
+ _In_ PVOID Instance);
+
+BOOLEAN
+RxScavengeVNetRoots(
+ _In_ PRDBSS_DEVICE_OBJECT RxDeviceObject);
+
+#if (_WIN32_WINNT >= 0x0600)
+VOID
+RxSynchronizeWithScavenger(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PFCB Fcb);
+#else
+VOID
+RxSynchronizeWithScavenger(
+ _In_ PRX_CONTEXT RxContext);
+#endif
+
+#endif
--- /dev/null
+#ifndef _RDBSSSTRUCHDR_
+#define _RDBSSSTRUCHDR_
+
+typedef struct _RX_PREFIX_ENTRY *PRX_PREFIX_ENTRY;
+typedef struct _RX_PREFIX_TABLE *PRX_PREFIX_TABLE;
+typedef struct _RX_FSD_DISPATCH_VECTOR *PRX_FSD_DISPATCH_VECTOR;
+typedef struct _RDBSS_DEVICE_OBJECT *PRDBSS_DEVICE_OBJECT;
+typedef struct _SRV_CALL *PSRV_CALL;
+typedef struct _NET_ROOT *PNET_ROOT;
+typedef struct _V_NET_ROOT *PV_NET_ROOT;
+typedef struct _NON_PAGED_FCB *PNON_PAGED_FCB;
+typedef struct _FCB *PFCB;
+typedef struct _SRV_OPEN *PSRV_OPEN;
+typedef struct _FOBX *PFOBX;
+typedef struct _RX_CONTEXT *PRX_CONTEXT;
+typedef struct _LOWIO_CONTEXT *PLOWIO_CONTEXT;
+typedef struct _MINIRDR_DISPATCH *PMINIRDR_DISPATCH;
+typedef struct _MRX_SRVCALLDOWN_STRUCTURE *PMRX_SRVCALLDOWN_STRUCTURE;
+typedef struct _MRX_CREATENETROOT_CONTEXT *PMRX_CREATENETROOT_CONTEXT;
+
+#endif
add_subdirectory(libusb)
add_subdirectory(lwip)
add_subdirectory(ntoskrnl_vista)
+add_subdirectory(rdbsslib)
add_subdirectory(rtlver)
+add_subdirectory(rxce)
add_subdirectory(sound)
--- /dev/null
+add_definitions(-DUNICODE -D_UNICODE -D__NTOSKRNL__ -D_NTOSKRNL_ -DRDBSS_TRACKER)
+
+include_directories(${REACTOS_SOURCE_DIR}/drivers/filesystems/mup)
+
+list(APPEND SOURCE
+ rdbss.c)
+
+add_library(rdbsslib ${SOURCE})
+target_link_libraries(rdbsslib rxce)
+add_dependencies(rdbsslib rxce bugcodes xdk)
--- /dev/null
+/*
+ * 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>
+
+#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);
+
+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);
+
+PVOID
+RxNewMapUserBuffer(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxNotifyChangeDirectory(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxpQueryInfoMiniRdr(
+ PRX_CONTEXT RxContext,
+ FILE_INFORMATION_CLASS FileInfoClass,
+ PVOID Buffer);
+
+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);
+
+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);
+
+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;
+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;
+
+DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
+
+/* FUNCTIONS ****************************************************************/
+
+VOID
+CheckForLoudOperations(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @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);
+ }
+}
+
+NTSTATUS
+NTAPI
+RxAcquireExclusiveFcbResourceInMRx(
+ _Inout_ PMRX_FCB Fcb)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+BOOLEAN
+NTAPI
+RxAcquireFcbForLazyWrite(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOLEAN
+NTAPI
+RxAcquireFcbForReadAhead(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+VOID
+NTAPI
+RxAcquireFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxAcquireForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @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
+RxAddToWorkque(
+ IN PRX_CONTEXT RxContext,
+ IN PIRP Irp)
+{
+ ULONG Queued;
+ KIRQL OldIrql;
+ WORK_QUEUE_TYPE Queue;
+ PIO_STACK_LOCATION Stack;
+
+ Stack = RxContext->CurrentIrpSp;
+ 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 &&
+ Stack->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 (Stack->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
+ */
+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 = ExAllocatePoolWithTag(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;
+}
+
+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 + 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;
+
+ PAGED_CODE();
+
+ NetRootType = NET_ROOT_WILD;
+
+ RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
+ RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
+
+ /* if not relative opening, just handle the passed name */
+ if (RxContext->CurrentIrpSp->FileObject->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 */
+ Fcb = RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext;
+ if (Fcb == NULL ||
+ RxContext->CurrentIrpSp->FileObject->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;
+}
+
+NTSTATUS
+NTAPI
+RxChangeBufferingState(
+ PSRV_OPEN SrvOpen,
+ PVOID Context,
+ BOOLEAN ComputeNewState)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+VOID
+NTAPI
+RxCheckFcbStructuresForAlignment(
+ VOID)
+{
+ UNIMPLEMENTED;
+}
+
+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);
+}
+
+/*
+ * @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;
+}
+
+NTSTATUS
+RxCloseAssociatedSrvOpen(
+ IN PFOBX Fobx,
+ IN PRX_CONTEXT RxContext OPTIONAL)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxCollapseOrCreateSrvOpen(
+ PRX_CONTEXT RxContext)
+{
+ PFCB Fcb;
+ NTSTATUS Status;
+ ULONG Disposition;
+ PSRV_OPEN SrvOpen;
+ USHORT ShareAccess;
+ PIO_STACK_LOCATION Stack;
+ ACCESS_MASK DesiredAccess;
+ RX_BLOCK_CONDITION FcbCondition;
+
+ PAGED_CODE();
+
+ DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
+
+ Fcb = (PFCB)RxContext->pFcb;
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+ ++Fcb->UncleanCount;
+
+ Stack = RxContext->CurrentIrpSp;
+ DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
+ ShareAccess = Stack->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 */
+ SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb);
+ 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 */
+ MINIRDR_CALL(Status, RxContext, Fcb->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)
+ {
+ RxAcquirePagingIoResource(RxContext, Fcb);
+ Fcb->Header.AllocationSize.QuadPart = 0LL;
+ Fcb->Header.FileSize.QuadPart = 0LL;
+ Fcb->Header.ValidDataLength.QuadPart = 0LL;
+ RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
+ CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
+ RxReleasePagingIoResource(RxContext, Fcb);
+ }
+ else
+ {
+ /* Otherwise, adjust sizes */
+ RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
+ if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
+ {
+ RxAdjustAllocationSizeforCC(Fcb);
+ }
+ CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->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));
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ RxCompleteSrvOpenKeyAssociation(SrvOpen);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
+ {
+ ClearFlag(Fcb->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 */
+ DPRINT("Transitioning FCB %p to condition %lx\n", Fcb, Fcb->Condition);
+ RxTransitionNetFcb(Fcb, 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;
+
+ RxReleaseFcb(RxContext, Fcb);
+ RxContext->Create.FcbAcquired = FALSE;
+
+ RxWaitForStableSrvOpen(SrvOpen, RxContext);
+
+ if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, Fcb)))
+ {
+ RxContext->Create.FcbAcquired = TRUE;
+ }
+
+ IsGood = (SrvOpen->Condition == Condition_Good);
+ }
+
+ /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
+ if (IsGood)
+ {
+ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext));
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+ }
+ else
+ {
+ Status = SrvOpen->OpenStatus;
+ }
+
+ if (ExtraOpen)
+ {
+ --SrvOpen->OpenCount;
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+ }
+ }
+
+ --Fcb->UncleanCount;
+
+ DPRINT("Status: %x\n", Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+RxCommonCleanup(
+ PRX_CONTEXT Context)
+{
+#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
+ PFCB Fcb;
+ PFOBX Fobx;
+ NTSTATUS Status;
+ BOOLEAN NeedPurge;
+ PFILE_OBJECT FileObject;
+
+ 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;
+ }
+
+ Fobx->AssociatedFileObject = NULL;
+
+ /* In case SRV_OPEN used is part of FCB */
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED))
+ {
+ 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;
+ }
+
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+#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
+}
+
+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)
+ {
+ UNIMPLEMENTED;
+ }
+ 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)
+ {
+ RxAcquirePrefixTableLockShared(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)
+{
+ 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))
+ {
+ _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;
+}
+
+NTSTATUS
+NTAPI
+RxCommonSetInformation(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+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 Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxCompleteMdl(
+ IN PRX_CONTEXT RxContext)
+{
+ PAGED_CODE();
+
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @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;
+
+ /* We don't support renaming yet */
+ if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
+ {
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* 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! */
+ FileObject = Stack->FileObject;
+ /* 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, ExAllocatePoolWithTag, ExFreePool, 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
+}
+
+/*
+ * @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();
+}
+
+BOOLEAN
+NTAPI
+RxFastIoCheckIfPossible(
+ PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length, BOOLEAN Wait,
+ ULONG LockKey, BOOLEAN CheckForReadOperation,
+ PIO_STATUS_BLOCK IoStatus,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+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;
+ }
+}
+
+BOOLEAN
+NTAPI
+RxFastIoRead(
+ PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length,
+ BOOLEAN Wait,
+ ULONG LockKey,
+ PVOID Buffer,
+ PIO_STATUS_BLOCK IoStatus,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOLEAN
+NTAPI
+RxFastIoWrite(
+ PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length,
+ BOOLEAN Wait,
+ ULONG LockKey,
+ PVOID Buffer,
+ PIO_STATUS_BLOCK IoStatus,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+NTSTATUS
+NTAPI
+RxFinalizeConnection(
+ IN OUT PNET_ROOT NetRoot,
+ IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
+ IN LOGICAL ForceFilesClosed)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+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);
+
+ TableAcquired = FALSE;
+ 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 (!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)
+ {
+ ExFreePoolWithTag(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) ||
+ 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", 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
+ */
+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;
+}
+
+VOID
+NTAPI
+RxInitializeDebugSupport(
+ VOID)
+{
+ 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;
+}
+
+NTSTATUS
+NTAPI
+RxInitializeRxTimer(
+ VOID)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @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;
+}
+
+BOOLEAN
+RxIsOkToPurgeFcb(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @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;
+}
+
+/*
+ * @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;
+}
+
+NTSTATUS
+RxNotifyChangeDirectory(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+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.FsInformationClass = 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 = ExAllocatePoolWithTag(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.NtCreateParameters,
+ 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)
+ {
+ ExFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
+ }
+
+ RxpPrepareCreateContextForReuse(RxContext);
+
+ RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+RxPrepareToReparseSymbolicLink(
+ PRX_CONTEXT RxContext,
+ BOOLEAN SymbolicLinkEmbeddedInOldPath,
+ PUNICODE_STRING NewPath,
+ BOOLEAN NewPathIsAbsolute,
+ PBOOLEAN ReparseRequired)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @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);
+}
+
+VOID
+NTAPI
+RxpUnregisterMinirdr(
+ IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+ UNIMPLEMENTED;
+}
+
+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, 'cDxR');
+ if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
+ {
+ /* UNICODE_STRING; length has to be even */
+ if ((FileName->Length & 1) != 0)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ RxFreePool(Fobx->UnicodeQueryTemplate.Buffer);
+ }
+ 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;
+}
+
+NTSTATUS
+RxQueryNameInfo(
+ PRX_CONTEXT RxContext,
+ PFILE_NAME_INFORMATION NameInfo)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+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 = ((ULONG)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 = (ULONG)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 = ((ULONG)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;
+ RxInitializeRdbssScavenger(&RDBSSDevice->RdbssScavengerInDeviceObject, ScavengerTimeLimit);
+ }
+
+ RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+RxReleaseFcbFromLazyWrite(
+ PVOID Context)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+NTAPI
+RxReleaseFcbFromReadAhead(
+ PVOID Context)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+NTAPI
+RxReleaseFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxReleaseForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @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;
+}
+
+VOID
+RxRemoveShareAccess(
+ _Inout_ PFILE_OBJECT FileObject,
+ _Inout_ PSHARE_ACCESS ShareAccess,
+ _In_ PSZ where,
+ _In_ PSZ wherelogtag)
+{
+ UNIMPLEMENTED;
+}
+
+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;
+}
+
+/*
+ * @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);
+}
+
+/*
+ * @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), '??xR');
+ 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;
+}
+
+/*
+ * @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);
+}
+
+/*
+ * @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);
+ ExFreePool(TopLevelContext);
+ }
+}
+
+/*
+ * @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;
+}
--- /dev/null
+add_definitions(-DUNICODE -D_UNICODE -D__NTOSKRNL__ -D_NTOSKRNL_ -DRDBSS_TRACKER)
+
+include_directories(${REACTOS_SOURCE_DIR}/drivers/filesystems/mup)
+
+list(APPEND SOURCE
+ rxce.c)
+
+add_library(rxce ${SOURCE})
+target_link_libraries(rxce ntoskrnl memcmp)
+add_dependencies(rxce bugcodes xdk ntoskrnl)
--- /dev/null
+/*
+ * 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/rxce/rxce.c
+ * PURPOSE: RXCE library
+ * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <rx.h>
+#include <pseh/pseh2.h>
+#include <dfs.h>
+
+#define NDEBUG
+#include <debug.h>
+
+VOID
+RxAssert(
+ PVOID Assert,
+ PVOID File,
+ ULONG Line,
+ PVOID Message);
+
+VOID
+NTAPI
+RxCreateSrvCallCallBack(
+ IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context);
+
+NTSTATUS
+RxFinishSrvCallConstruction(
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown);
+
+VOID
+NTAPI
+RxFinishSrvCallConstructionDispatcher(
+ IN PVOID Context);
+
+NTSTATUS
+RxInsertWorkQueueItem(
+ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ WORK_QUEUE_TYPE WorkQueueType,
+ PRX_WORK_DISPATCH_ITEM DispatchItem);
+
+PVOID
+RxNewMapUserBuffer(
+ PRX_CONTEXT RxContext);
+
+VOID
+NTAPI
+RxWorkItemDispatcher(
+ PVOID Context);
+
+extern ULONG ReadAheadGranularity;
+
+volatile LONG RxNumberOfActiveFcbs = 0;
+ULONG SerialNumber = 1;
+PVOID RxNull = NULL;
+volatile ULONG RxContextSerialNumberCounter;
+BOOLEAN RxStopOnLoudCompletion = TRUE;
+BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
+LIST_ENTRY RxSrvCalldownList;
+RX_SPIN_LOCK RxStrucSupSpinLock;
+ULONG RdbssReferenceTracingValue;
+LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
+LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
+RX_DISPATCHER RxDispatcher;
+RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
+FAST_MUTEX RxLowIoPagingIoSyncMutex;
+BOOLEAN RxContinueFromAssert = TRUE;
+#if DBG
+BOOLEAN DumpDispatchRoutine = TRUE;
+#else
+BOOLEAN DumpDispatchRoutine = FALSE;
+#endif
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#define ASSERT(exp) \
+ if (!(exp)) \
+ { \
+ RxAssert(#exp, __FILE__, __LINE__, NULL); \
+ }
+
+/* FUNCTIONS ****************************************************************/
+
+/*
+ * @implemented
+ */
+VOID
+RxAddVirtualNetRootToNetRoot(
+ PNET_ROOT NetRoot,
+ PV_NET_ROOT VNetRoot)
+{
+ PAGED_CODE();
+
+ DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
+
+ /* Insert in the VNetRoot list - make sure lock is held */
+ ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
+
+ VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ ++NetRoot->NumberOfVirtualNetRoots;
+ InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxAllocateFcbObject(
+ PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ NODE_TYPE_CODE NodeType,
+ POOL_TYPE PoolType,
+ ULONG NameSize,
+ PVOID AlreadyAllocatedObject)
+{
+ PFCB Fcb;
+ PFOBX Fobx;
+ PSRV_OPEN SrvOpen;
+ PVOID Buffer, PAPNBuffer;
+ PNON_PAGED_FCB NonPagedFcb;
+ PMINIRDR_DISPATCH Dispatch;
+ ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
+
+ PAGED_CODE();
+
+ Dispatch = RxDeviceObject->Dispatch;
+
+ NonPagedSize = 0;
+ FobxSize = 0;
+ SrvOpenSize = 0;
+ FcbSize = 0;
+
+ Fcb = NULL;
+ Fobx = NULL;
+ SrvOpen = NULL;
+ NonPagedFcb = NULL;
+ PAPNBuffer = NULL;
+
+ /* If we ask for FOBX, just allocate FOBX and its extension if asked */
+ if (NodeType == RDBSS_NTC_FOBX)
+ {
+ FobxSize = sizeof(FOBX);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
+ {
+ FobxSize += QuadAlign(Dispatch->MRxFobxSize);
+ }
+ }
+ /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
+ else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
+ {
+ SrvOpenSize = sizeof(SRV_OPEN);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
+ {
+ SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
+ }
+
+ FobxSize = sizeof(FOBX);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
+ {
+ FobxSize += QuadAlign(Dispatch->MRxFobxSize);
+ }
+ }
+ /* Otherwise, we're asked to allocate a FCB */
+ else
+ {
+ /* So, allocate the FCB and its extension if asked */
+ FcbSize = sizeof(FCB);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
+ {
+ FcbSize += QuadAlign(Dispatch->MRxFcbSize);
+ }
+
+ /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
+ * Otherwise, it will be allocated later on, specifically
+ */
+ if (PoolType == NonPagedPool)
+ {
+ NonPagedSize = sizeof(NON_PAGED_FCB);
+ }
+
+ /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
+ if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
+ {
+ SrvOpenSize = sizeof(SRV_OPEN);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
+ {
+ SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
+ }
+
+ FobxSize = sizeof(FOBX);
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
+ {
+ FobxSize += QuadAlign(Dispatch->MRxFobxSize);
+ }
+ }
+ }
+
+ /* If we already have a buffer, go ahead */
+ if (AlreadyAllocatedObject != NULL)
+ {
+ Buffer = AlreadyAllocatedObject;
+ }
+ /* Otherwise, allocate it */
+ else
+ {
+ Buffer = ExAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
+ if (Buffer == NULL)
+ {
+ return NULL;
+ }
+ }
+
+ /* Now, get the pointers - FOBX is easy */
+ if (NodeType == RDBSS_NTC_FOBX)
+ {
+ Fobx = Buffer;
+ }
+ /* SRV_OPEN first, FOBX next */
+ else if (NodeType == RDBSS_NTC_SRVOPEN)
+ {
+ SrvOpen = Buffer;
+ Fobx = Add2Ptr(Buffer, SrvOpenSize);
+ }
+ else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
+ {
+ SrvOpen = Buffer;
+ }
+ else
+ {
+ /* FCB first, and if needed, SRV_OPEN next, FOBX last */
+ Fcb = Buffer;
+ if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
+ {
+ SrvOpen = Add2Ptr(Buffer, FcbSize);
+ Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
+ }
+
+ /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
+ if (PoolType != NonPagedPool)
+ {
+ NonPagedFcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
+ if (NonPagedFcb == NULL)
+ {
+ ExFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
+ return NULL;
+ }
+
+ PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
+ }
+ /* Otherwise, just point at the right place in what has been allocated previously */
+ else
+ {
+ NonPagedFcb = Add2Ptr(Fobx, FobxSize);
+ PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
+ }
+ }
+
+ /* If we have allocated a SRV_OPEN, initialize it */
+ if (SrvOpen != NULL)
+ {
+ ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
+
+ if (NodeType == RDBSS_NTC_SRVOPEN)
+ {
+ SrvOpen->InternalFobx = Fobx;
+ }
+ else
+ {
+ SrvOpen->InternalFobx = NULL;
+ SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
+ }
+
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
+ {
+ SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
+ }
+
+ InitializeListHead(&SrvOpen->SrvOpenQLinks);
+ }
+
+ /* If we have allocated a FOBX, initialize it */
+ if (Fobx != NULL)
+ {
+ ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
+
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
+ {
+ Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
+ }
+ }
+
+ /* If we have allocated a FCB, initialize it */
+ if (Fcb != NULL)
+ {
+ ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
+
+ Fcb->NonPaged = NonPagedFcb;
+ ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
+ Fcb->CopyOfNonPaged = NonPagedFcb;
+ NonPagedFcb->FcbBackPointer = Fcb;
+
+ Fcb->InternalSrvOpen = SrvOpen;
+ Fcb->InternalFobx = Fobx;
+
+ Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
+ Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
+ Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
+
+ if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
+ {
+ Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
+ }
+
+ ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
+
+ InterlockedIncrement(&RxNumberOfActiveFcbs);
+ InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
+
+ ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
+ FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
+ }
+
+ return Buffer;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxAllocateObject(
+ NODE_TYPE_CODE NodeType,
+ PMINIRDR_DISPATCH MRxDispatch,
+ ULONG NameLength)
+{
+ ULONG Tag, ObjectSize;
+ PVOID Object, *Extension;
+ PRX_PREFIX_ENTRY PrefixEntry;
+ USHORT StructSize, ExtensionSize;
+
+ PAGED_CODE();
+
+ /* Select the node to allocate and always deal with the fact we may have to manage its extension */
+ ExtensionSize = 0;
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ Tag = RX_SRVCALL_POOLTAG;
+ StructSize = sizeof(SRV_CALL);
+ if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
+ {
+ ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
+ }
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ Tag = RX_NETROOT_POOLTAG;
+ StructSize = sizeof(NET_ROOT);
+ if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
+ {
+ ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
+ }
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ Tag = RX_V_NETROOT_POOLTAG;
+ StructSize = sizeof(V_NET_ROOT);
+ if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
+ {
+ ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
+ }
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ /* Now, allocate the object */
+ ObjectSize = ExtensionSize + StructSize + NameLength;
+ Object = ExAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
+ if (Object == NULL)
+ {
+ return NULL;
+ }
+ /* Initialize it */
+ ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
+
+ /* For SRV_CALL and NETROOT, the name points to the prefix table name */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
+ Extension = &((PSRV_CALL)Object)->Context;
+ ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
+ Extension = &((PNET_ROOT)Object)->Context;
+ ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
+ Extension = &((PV_NET_ROOT)Object)->Context;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ /* Set the prefix table unicode string */
+ RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
+ PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
+ PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
+ PrefixEntry->Prefix.Length = NameLength;
+ PrefixEntry->Prefix.MaximumLength = NameLength;
+ PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
+
+ /* Return the extension if we are asked to manage it */
+ if (ExtensionSize != 0)
+ {
+ *Extension = Add2Ptr(Object, StructSize);
+ }
+
+ return Object;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxAssert(
+ PVOID Assert,
+ PVOID File,
+ ULONG Line,
+ PVOID Message)
+{
+ CHAR Response[2];
+ CONTEXT Context;
+
+ /* If we're not asked to continue, just stop the system */
+ if (!RxContinueFromAssert)
+ {
+ KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
+ }
+
+ /* Otherwise, capture context to offer the user to dump it */
+ RtlCaptureContext(&Context);
+
+ /* Loop until the user hits 'i' */
+ while (TRUE)
+ {
+ /* If no file provided, use empty name */
+ if (File == NULL)
+ {
+ File = "";
+ }
+
+ /* If no message provided, use empty one */
+ if (Message == NULL)
+ {
+ Message = "";
+ }
+
+ /* Display the message */
+ DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
+ /* And ask the user */
+ DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
+ /* If he asks for ignore, quit
+ * In case of invalid input, ask again
+ */
+ if (Response[0] != 'B' && Response[0] != 'b')
+ {
+ if (Response[0] == 'I' || Response[0] == 'i')
+ {
+ return;
+ }
+
+ continue;
+ }
+
+ /* Break: offer the user to dump the context and break */
+ DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
+ DbgBreakPoint();
+
+ /* Continue looping, so that after dump, execution can continue (with ignore) */
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxBootstrapWorkerThreadDispatcher(
+ IN PVOID WorkQueue)
+{
+ PRX_WORK_QUEUE RxWorkQueue;
+
+ PAGED_CODE();
+
+ RxWorkQueue = WorkQueue;
+ RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
+}
+
+NTSTATUS
+RxCheckVNetRootCredentials(
+ PRX_CONTEXT RxContext,
+ PV_NET_ROOT VNetRoot,
+ PLUID LogonId,
+ PUNICODE_STRING UserName,
+ PUNICODE_STRING UserDomain,
+ PUNICODE_STRING Password,
+ ULONG Flags)
+{
+ PAGED_CODE();
+
+ /* If that's a UNC name, there's nothing to process */
+ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
+ (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
+ Flags != 0))
+ {
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* Compare the logon ID in the VNetRoot with the one provided */
+ if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
+ {
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* No credential provided? That's OK */
+ if (UserName == NULL && UserDomain == NULL && Password == NULL)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Left to do! */
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxCompleteRequest(
+ PRX_CONTEXT Context,
+ NTSTATUS Status)
+{
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
+
+ ASSERT(Context != NULL);
+ ASSERT(Context->CurrentIrp != NULL);
+ Irp = Context->CurrentIrp;
+
+ /* Debug what the caller asks for */
+ if (Context->LoudCompletionString != NULL)
+ {
+ DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
+ /* Does the user asks to stop on failed completion */
+ if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
+ {
+ DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
+ }
+ }
+
+ /* Complete for real */
+ Context->CurrentIrp = NULL;
+ RxCompleteRequest_Real(Context, Irp, Status);
+
+ DPRINT("Status: %lx\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxCompleteRequest_Real(
+ IN PRX_CONTEXT RxContext,
+ IN PIRP Irp,
+ IN NTSTATUS Status)
+{
+ CCHAR Boost;
+ KIRQL OldIrql;
+ PIO_STACK_LOCATION Stack;
+
+ DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
+
+ /* Nothing to complete, just free context */
+ if (Irp == NULL)
+ {
+ DPRINT("NULL IRP for %p\n", RxContext);
+ if (RxContext != NULL)
+ {
+ RxDereferenceAndDeleteRxContext_Real(RxContext);
+ }
+
+ return;
+ }
+
+ /* Remove cancel routine */
+ IoAcquireCancelSpinLock(&OldIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(OldIrql);
+
+ /* Select the boost, given the success/paging operation */
+ if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
+ {
+ Boost = IO_DISK_INCREMENT;
+ }
+ else
+ {
+ Irp->IoStatus.Information = 0;
+ Boost = IO_NO_INCREMENT;
+ }
+ Irp->IoStatus.Status = Status;
+
+ if (RxContext != NULL)
+ {
+ ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
+ if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
+ {
+ DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
+ RxContext->MinorFunction, RxContext, Irp,
+ Status, Irp->IoStatus.Information, RxContext->SerialNumber);
+ }
+ }
+
+ /* If that's an opening, there might be a canonical name allocated,
+ * if completion isn't pending, release it
+ */
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
+ RxContext != NULL)
+ {
+ if (BooleanFlagOn(RxContext->Create.Flags, 2))
+ {
+ Stack->FileObject->FileName.Length += sizeof(WCHAR);
+ }
+
+ RxpPrepareCreateContextForReuse(RxContext);
+ ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
+ }
+
+ /* If it's a write, validate the correct behavior of the operation */
+ if (Stack->MajorFunction == IRP_MJ_WRITE)
+ {
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
+ }
+ }
+
+ /* If it's pending, make sure IRP is marked as such */
+ if (RxContext != NULL)
+ {
+ if (RxContext->PendingReturned)
+ {
+ ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
+ }
+ }
+
+ /* Complete now */
+ DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
+ IoCompleteRequest(Irp, Boost);
+
+ /* If there's a context, dereference it */
+ if (RxContext != NULL)
+ {
+ RxDereferenceAndDeleteRxContext_Real(RxContext);
+ }
+}
+
+VOID
+RxCompleteSrvOpenKeyAssociation(
+ IN OUT PSRV_OPEN SrvOpen)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxConstructNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PSRV_CALL SrvCall,
+ IN PNET_ROOT NetRoot,
+ IN PV_NET_ROOT VirtualNetRoot,
+ OUT PLOCK_HOLDING_STATE LockHoldingState)
+{
+ NTSTATUS Status;
+ PRX_PREFIX_TABLE PrefixTable;
+ PMRX_CREATENETROOT_CONTEXT Context;
+ RX_BLOCK_CONDITION RootCondition, VRootCondition;
+
+ PAGED_CODE();
+
+ DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
+ VirtualNetRoot, LockHoldingState);
+
+ /* Validate the lock is exclusively held */
+ PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
+ ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
+
+ /* Allocate the context */
+ Context = ExAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
+ if (Context == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* We can release lock now */
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockHoldingState = LHS_LockNotHeld;
+
+ RootCondition = Condition_Bad;
+ VRootCondition = Condition_Bad;
+
+ /* Initialize the context */
+ RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
+ KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
+ Context->RxContext = RxContext;
+ Context->pVNetRoot = VirtualNetRoot;
+ Context->Callback = RxCreateNetRootCallBack;
+
+ /* And call the mini-rdr */
+ MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for the mini-rdr to be done */
+ KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
+ /* Update the structures condition according to mini-rdr return */
+ if (NT_SUCCESS(Context->NetRootStatus))
+ {
+ if (NT_SUCCESS(Context->VirtualNetRootStatus))
+ {
+ RootCondition = Condition_Good;
+ VRootCondition = Condition_Good;
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ RootCondition = Condition_Good;
+ Status = Context->VirtualNetRootStatus;
+ }
+ }
+ else
+ {
+ Status = Context->VirtualNetRootStatus;
+ if (NT_SUCCESS(Status))
+ {
+ Status = Context->NetRootStatus;
+ }
+ }
+ }
+ else
+ {
+ /* It has to return STATUS_PENDING! */
+ ASSERT(FALSE);
+ }
+
+ /* Acquire lock again - for caller lock status will remain unchanged */
+ ASSERT(*LockHoldingState == LHS_LockNotHeld);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockHoldingState = LHS_ExclusiveLockHeld;
+
+ /* Do the transition to the condition got from mini-rdr */
+ RxTransitionNetRoot(NetRoot, RootCondition);
+ RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
+
+ /* Context is not longer needed */
+ ExFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
+
+ DPRINT("Status: %x\n", Status);
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxConstructSrvCall(
+ IN PRX_CONTEXT RxContext,
+ IN PSRV_CALL SrvCall,
+ OUT PLOCK_HOLDING_STATE LockHoldingState)
+{
+ NTSTATUS Status;
+ PRX_PREFIX_TABLE PrefixTable;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown;
+ PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
+
+ PAGED_CODE();
+
+ DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
+
+ /* Validate the lock is exclusively held */
+ RxDeviceObject = RxContext->RxDeviceObject;
+ PrefixTable = RxDeviceObject->pRxNetNameTable;
+ ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
+
+ /* Allocate the context for mini-rdr */
+ Calldown = ExAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
+ if (Calldown == NULL)
+ {
+ SrvCall->Context = NULL;
+ SrvCall->Condition = Condition_Bad;
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockHoldingState = LHS_LockNotHeld;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Initialize it */
+ RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
+
+ SrvCall->Context = NULL;
+ SrvCall->Condition = Condition_InTransition;
+
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockHoldingState = LHS_LockNotHeld;
+
+ CallbackContext = &Calldown->CallbackContexts[0];
+ DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
+ DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
+ CallbackContext->SrvCalldownStructure = Calldown;
+ CallbackContext->CallbackContextOrdinal = 0;
+ CallbackContext->RxDeviceObject = RxDeviceObject;
+
+ RxReferenceSrvCall(SrvCall);
+
+ /* If we're async, we'll post, otherwise, we'll have to wait for completion */
+ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
+ {
+ RxPrePostIrp(RxContext, RxContext->CurrentIrp);
+ }
+ else
+ {
+ KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
+ }
+
+ Calldown->NumberToWait = 1;
+ Calldown->NumberRemaining = 1;
+ Calldown->RxContext = RxContext;
+ Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
+ Calldown->CallBack = RxCreateSrvCallCallBack;
+ Calldown->BestFinisher = NULL;
+ CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
+ InitializeListHead(&Calldown->SrvCalldownList);
+
+ /* Call the mini-rdr */
+ ASSERT(RxDeviceObject->Dispatch != NULL);
+ ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
+ ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
+ Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
+ /* It has to return STATUS_PENDING! */
+ ASSERT(Status == STATUS_PENDING);
+
+ /* No async, start completion */
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
+ {
+ KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
+
+ /* Finish construction - we'll notify mini-rdr it's the winner */
+ Status = RxFinishSrvCallConstruction(Calldown);
+ if (!NT_SUCCESS(Status))
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockHoldingState = LHS_LockNotHeld;
+ }
+ else
+ {
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
+ *LockHoldingState = LHS_ExclusiveLockHeld;
+ }
+ }
+
+ DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxConstructVirtualNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PUNICODE_STRING CanonicalName,
+ IN NET_ROOT_TYPE NetRootType,
+ OUT PV_NET_ROOT *VirtualNetRootPointer,
+ OUT PLOCK_HOLDING_STATE LockHoldingState,
+ OUT PRX_CONNECTION_ID RxConnectionId)
+{
+ NTSTATUS Status;
+ PV_NET_ROOT VNetRoot;
+ RX_BLOCK_CONDITION Condition;
+ UNICODE_STRING LocalNetRootName, FilePathName;
+
+ PAGED_CODE();
+
+ ASSERT(*LockHoldingState != LHS_LockNotHeld);
+
+ VNetRoot = NULL;
+ Condition = Condition_Bad;
+ /* Before creating the VNetRoot, try to find the appropriate connection */
+ Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
+ &LocalNetRootName, &FilePathName,
+ LockHoldingState, RxConnectionId);
+ /* Found and active */
+ if (Status == STATUS_CONNECTION_ACTIVE)
+ {
+ /* We need a new VNetRoot */
+ VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
+ CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
+ if (VNetRoot != NULL)
+ {
+ RxReferenceVNetRoot(VNetRoot);
+ }
+
+ /* Dereference previous VNetRoot */
+ RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
+ /* Reset and start construct (new structures will replace old ones) */
+ RxContext->Create.pSrvCall = NULL;
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pVNetRoot = NULL;
+
+ /* Construct new NetRoot */
+ if (VNetRoot != NULL)
+ {
+ Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
+ (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
+ if (NT_SUCCESS(Status))
+ {
+ Condition = Condition_Good;
+ }
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ /* If it failed creating the connection, leave */
+ if (Status != STATUS_SUCCESS)
+ {
+ if (*LockHoldingState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
+ *LockHoldingState = LHS_LockNotHeld;
+ }
+
+ *VirtualNetRootPointer = VNetRoot;
+ DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
+ return Status;
+ }
+
+ *LockHoldingState = LHS_ExclusiveLockHeld;
+
+ VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
+ Condition = Condition_Good;
+ }
+
+ /* We have a non stable VNetRoot - transition it */
+ if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
+ {
+ RxTransitionVNetRoot(VNetRoot, Condition);
+ }
+
+ /* If recreation failed */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Dereference potential VNetRoot */
+ if (VNetRoot != NULL)
+ {
+ ASSERT(*LockHoldingState != LHS_LockNotHeld);
+ RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
+ VNetRoot = NULL;
+ }
+
+ /* Release lock */
+ if (*LockHoldingState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
+ *LockHoldingState = LHS_LockNotHeld;
+ }
+
+ /* Set NULL ptr */
+ *VirtualNetRootPointer = VNetRoot;
+ return Status;
+ }
+
+ /* Return the allocated VNetRoot */
+ *VirtualNetRootPointer = VNetRoot;
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+PFCB
+RxCreateNetFcb(
+ IN PRX_CONTEXT RxContext,
+ IN PV_NET_ROOT VNetRoot,
+ IN PUNICODE_STRING Name)
+{
+ PFCB Fcb;
+ BOOLEAN FakeFcb;
+ PNET_ROOT NetRoot;
+ POOL_TYPE PoolType;
+ NODE_TYPE_CODE NodeType;
+ PIO_STACK_LOCATION Stack;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+
+ PAGED_CODE();
+
+ /* We need a decent VNetRoot */
+ ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
+
+ NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
+ ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
+
+ RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
+
+ Stack = RxContext->CurrentIrpSp;
+
+ /* Do we need to create a fake FCB? Like for renaming */
+ FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
+ !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
+ ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
+
+ PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
+ NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
+
+ /* Allocate the FCB */
+ Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
+ NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
+ if (Fcb == NULL)
+ {
+ return NULL;
+ }
+
+ /* Initialize the FCB */
+ Fcb->CachedNetRootType = NetRoot->Type;
+ Fcb->RxDeviceObject = RxDeviceObject;
+ Fcb->MRxDispatch = RxDeviceObject->Dispatch;
+ Fcb->VNetRoot = VNetRoot;
+ Fcb->pNetRoot = VNetRoot->pNetRoot;
+
+ InitializeListHead(&Fcb->SrvOpenList);
+ Fcb->SrvOpenListVersion = 0;
+
+ Fcb->FcbTableEntry.Path.Length = Name->Length;
+ Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
+ Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
+ RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
+ NetRoot->InnerNamePrefix.Length);
+ RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
+
+ /* Copy back parameters from RxContext */
+ if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
+ {
+ Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
+ }
+
+ InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
+
+ if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
+ {
+ Fcb->FcbState |= FCB_STATE_PAGING_FILE;
+ }
+
+ if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
+ {
+ Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
+ }
+
+ Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
+ ExInitializeResourceLite(Fcb->Header.Resource);
+
+ Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
+ ExInitializeResourceLite(Fcb->Header.PagingIoResource);
+
+ Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
+ ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
+
+ /* Fake FCB doesn't go in prefix table */
+ if (FakeFcb)
+ {
+ Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
+ InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
+ DPRINT("Fake FCB: %p\n", Fcb);
+ }
+ else
+ {
+ RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
+ }
+
+ RxReferenceVNetRoot(VNetRoot);
+ InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
+
+ Fcb->ulFileSizeVersion = 0;
+
+ DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
+ RxReferenceNetFcb(Fcb);
+
+ return Fcb;
+}
+
+/*
+ * @implemented
+ */
+PMRX_FOBX
+NTAPI
+RxCreateNetFobx(
+ OUT PRX_CONTEXT RxContext,
+ IN PMRX_SRV_OPEN MrxSrvOpen)
+{
+ PFCB Fcb;
+ PFOBX Fobx;
+ ULONG Flags;
+ PNET_ROOT NetRoot;
+ PSRV_OPEN SrvOpen;
+ POOL_TYPE PoolType;
+
+ PAGED_CODE();
+
+ SrvOpen = (PSRV_OPEN)MrxSrvOpen;
+ ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
+ ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
+ ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
+
+ Fcb = SrvOpen->Fcb;
+ PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
+ /* Can we use pre-allocated FOBX? */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
+ {
+ Fobx = Fcb->InternalFobx;
+ /* Call allocate to initialize the FOBX */
+ RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
+ /* Mark it used now */
+ Fcb->FcbState |= FCB_STATE_FOBX_USED;
+ Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
+ }
+ else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
+ {
+ Fobx = SrvOpen->InternalFobx;
+ /* Call allocate to initialize the FOBX */
+ RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
+ /* Mark it used now */
+ SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
+ Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
+ }
+ else
+ {
+ /* Last case, we cannot, allocate a FOBX */
+ Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
+ Flags = 0;
+ }
+
+ /* Allocation failed! */
+ if (Fobx == NULL)
+ {
+ return NULL;
+ }
+
+ /* Set flags */
+ Fobx->Flags = Flags;
+
+ /* Initialize throttling */
+ NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
+ if (NetRoot != NULL)
+ {
+ if (NetRoot->DeviceType == FILE_DEVICE_DISK)
+ {
+ RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
+ NetRoot->DiskParameters.LockThrottlingParameters.Increment,
+ NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
+ }
+ else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
+ {
+ RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
+ NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
+ NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
+ }
+ }
+
+ /* Propagate flags fron RxContext */
+ if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
+ {
+ Fobx->Flags |= FOBX_FLAG_UNC_NAME;
+ }
+
+ if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
+ {
+ Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
+ }
+
+ /* Continue init */
+ Fobx->FobxSerialNumber = 0;
+ Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
+ Fobx->NodeReferenceCount = 1;
+ Fobx->RxDeviceObject = Fcb->RxDeviceObject;
+
+ RxReferenceSrvOpen(SrvOpen);
+ InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
+
+ InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
+ InitializeListHead(&Fobx->ScavengerFinalizationList);
+ InitializeListHead(&Fobx->ClosePendingList);
+
+ Fobx->CloseTime.QuadPart = 0;
+ Fobx->fOpenCountDecremented = FALSE;
+
+ DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
+
+ return (PMRX_FOBX)Fobx;
+}
+
+/*
+ * @implemented
+ */
+PNET_ROOT
+RxCreateNetRoot(
+ IN PSRV_CALL SrvCall,
+ IN PUNICODE_STRING Name,
+ IN ULONG NetRootFlags,
+ IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
+{
+ PNET_ROOT NetRoot;
+ USHORT CaseInsensitiveLength;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
+
+ PAGED_CODE();
+
+ /* We need a SRV_CALL */
+ ASSERT(SrvCall != NULL);
+
+ PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
+
+ /* Get name length */
+ CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
+ if (CaseInsensitiveLength > MAXUSHORT)
+ {
+ return NULL;
+ }
+
+ /* Allocate the NetRoot */
+ NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
+ CaseInsensitiveLength);
+ if (NetRoot == NULL)
+ {
+ return NULL;
+ }
+
+ /* Construct name */
+ RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
+ Name->Buffer, Name->Length);
+ if (SrvCall->PrefixEntry.Prefix.Length != 0)
+ {
+ RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
+ SrvCall->PrefixEntry.Prefix.Length);
+ }
+
+ if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
+ {
+ CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
+ }
+ /* Inisert in prefix table */
+ RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
+ (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
+ RxConnectionId);
+
+ /* Prepare the FCB table */
+ RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
+
+ InitializeListHead(&NetRoot->TransitionWaitList);
+ InitializeListHead(&NetRoot->ScavengerFinalizationList);
+ InitializeListHead(&NetRoot->VirtualNetRoots);
+
+ RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
+
+ NetRoot->SerialNumberForEnum = SerialNumber++;
+ NetRoot->Flags |= NetRootFlags;
+ NetRoot->DiskParameters.ClusterSize = 1;
+ NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
+ NetRoot->SrvCall = SrvCall;
+
+ RxReferenceSrvCall(SrvCall);
+
+ DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
+ return NetRoot;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxCreateNetRootCallBack(
+ IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
+{
+ PAGED_CODE();
+
+ KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
+}
+
+/*
+ * @implemented
+ */
+PRX_CONTEXT
+NTAPI
+RxCreateRxContext(
+ IN PIRP Irp,
+ IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ IN ULONG InitialContextFlags)
+{
+ KIRQL OldIrql;
+ PRX_CONTEXT Context;
+
+ ASSERT(RxDeviceObject != NULL);
+
+ DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
+
+ InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
+ InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
+
+ /* Allocate the context from our lookaside list */
+ Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
+ if (Context == NULL)
+ {
+ return NULL;
+ }
+
+ /* And initialize it */
+ RtlZeroMemory(Context, sizeof(RX_CONTEXT));
+ RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
+ ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
+
+ /* Add it to our global list */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ DPRINT("Context: %p\n", Context);
+ return Context;
+}
+
+/*
+ * @implemented
+ */
+PSRV_CALL
+RxCreateSrvCall(
+ IN PRX_CONTEXT RxContext,
+ IN PUNICODE_STRING Name,
+ IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
+ IN PRX_CONNECTION_ID RxConnectionId)
+{
+ ULONG NameLength;
+ PSRV_CALL SrvCall;
+
+ PAGED_CODE();
+
+ DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
+
+ ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
+
+ /* Get the name length */
+ NameLength = Name->Length + 2 * sizeof(WCHAR);
+ if (InnerNamePrefix != NULL)
+ {
+ NameLength += InnerNamePrefix->Length;
+ }
+
+ /* Allocate the object */
+ SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
+ if (SrvCall == NULL)
+ {
+ return NULL;
+ }
+
+ /* Initialize it */
+ SrvCall->SerialNumberForEnum = SerialNumber++;
+ SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
+ RxInitializeBufferingManager(SrvCall);
+ InitializeListHead(&SrvCall->TransitionWaitList);
+ InitializeListHead(&SrvCall->ScavengerFinalizationList);
+ RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
+ RxInitializeSrvCallParameters(RxContext, SrvCall);
+ RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
+ SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
+ SrvCall->PrefixEntry.Prefix.Length = Name->Length;
+ RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
+ SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
+
+ DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
+ return SrvCall;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxCreateSrvCallCallBack(
+ IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
+{
+ KIRQL OldIrql;
+ PSRV_CALL SrvCall;
+ PRX_CONTEXT RxContext;
+ ULONG NumberRemaining;
+ BOOLEAN StartDispatcher;
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown;
+
+ DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
+
+ /* Get our context structures */
+ Calldown = Context->SrvCalldownStructure;
+ SrvCall = (PSRV_CALL)Calldown->SrvCall;
+
+ /* If it is a success, that's the winner */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ if (Context->Status == STATUS_SUCCESS)
+ {
+ Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
+ Calldown->BestFinisher = Context->RxDeviceObject;
+ }
+ NumberRemaining = --Calldown->NumberRemaining;
+ SrvCall->Status = Context->Status;
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* Still some to ask, keep going */
+ if (NumberRemaining != 0)
+ {
+ return;
+ }
+
+ /* If that's not async, signal we're done */
+ RxContext = Calldown->RxContext;
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
+ {
+ KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
+ return;
+ }
+ /* If that's a mailslot, finish construction, no more to do */
+ else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
+ {
+ RxFinishSrvCallConstruction(Calldown);
+ return;
+ }
+
+ /* Queue our finish call for delayed completion */
+ DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
+ StartDispatcher = !RxSrvCallConstructionDispatcherActive;
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* If we have to start dispatcher, go ahead */
+ if (StartDispatcher)
+ {
+ NTSTATUS Status;
+
+ Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
+ RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
+ if (!NT_SUCCESS(Status))
+ {
+ /* It failed - run it manually.... */
+ RxFinishSrvCallConstructionDispatcher(NULL);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+PSRV_OPEN
+RxCreateSrvOpen(
+ IN PV_NET_ROOT VNetRoot,
+ IN OUT PFCB Fcb)
+{
+ ULONG Flags;
+ PSRV_OPEN SrvOpen;
+ POOL_TYPE PoolType;
+
+ PAGED_CODE();
+
+ ASSERT(NodeTypeIsFcb(Fcb));
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
+
+ _SEH2_TRY
+ {
+ SrvOpen = Fcb->InternalSrvOpen;
+ /* Check whethet we have to allocate a new SRV_OPEN */
+ if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
+ BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
+ !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
+ {
+ /* Proceed */
+ SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
+ RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
+ Flags = 0;
+ }
+ else
+ {
+ /* Otherwise, just use internal one and initialize it */
+ RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
+ RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
+ Fcb->InternalSrvOpen);
+ Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
+ Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
+ }
+
+ /* If SrvOpen was properly allocated, initialize it */
+ if (SrvOpen != NULL)
+ {
+ SrvOpen->Flags = Flags;
+ SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
+ SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
+ SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
+ SrvOpen->NodeReferenceCount = 1;
+
+ RxReferenceVNetRoot(VNetRoot);
+ RxReferenceNetFcb(Fcb);
+
+ InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
+ ++Fcb->SrvOpenListVersion;
+
+ InitializeListHead(&SrvOpen->ScavengerFinalizationList);
+ InitializeListHead(&SrvOpen->TransitionWaitList);
+ InitializeListHead(&SrvOpen->FobxList);
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (_SEH2_AbnormalTermination())
+ {
+ if (SrvOpen != NULL)
+ {
+ RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
+ SrvOpen = NULL;
+ }
+ }
+ else
+ {
+ DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
+ }
+ }
+ _SEH2_END;
+
+ return SrvOpen;
+}
+
+/*
+ * @implemented
+ */
+PV_NET_ROOT
+RxCreateVNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PNET_ROOT NetRoot,
+ IN PUNICODE_STRING CanonicalName,
+ IN PUNICODE_STRING LocalNetRootName,
+ IN PUNICODE_STRING FilePath,
+ IN PRX_CONNECTION_ID RxConnectionId)
+{
+ NTSTATUS Status;
+ PV_NET_ROOT VNetRoot;
+ USHORT CaseInsensitiveLength;
+
+ PAGED_CODE();
+
+ DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
+ LocalNetRootName, FilePath, RxConnectionId);
+
+ /* Lock must be held exclusively */
+ ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
+
+ /* Check for overflow */
+ if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
+ {
+ return NULL;
+ }
+
+ /* Get name length and allocate VNetRoot */
+ CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
+ VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
+ CaseInsensitiveLength);
+ if (VNetRoot == NULL)
+ {
+ return NULL;
+ }
+
+ /* Initialize its connection parameters */
+ Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
+ &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
+ &VNetRoot->pPassword, &VNetRoot->Flags);
+ if (!NT_SUCCESS(Status))
+ {
+ RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
+ VNetRoot->pPassword, &VNetRoot->Flags);
+ RxFreeObject(VNetRoot);
+
+ return NULL;
+ }
+
+ /* Set name */
+ RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
+
+ VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
+ VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
+ VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
+ VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
+
+ InitializeListHead(&VNetRoot->TransitionWaitList);
+ InitializeListHead(&VNetRoot->ScavengerFinalizationList);
+
+ if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
+ {
+ USHORT i;
+
+ if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
+ {
+ CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
+ }
+ else
+ {
+ CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
+ }
+
+ for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
+ {
+ if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
+ {
+ break;
+ }
+ }
+
+ CaseInsensitiveLength += (i * sizeof(WCHAR));
+ }
+
+ /* Insert in prefix table */
+ RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
+ VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
+ RxConnectionId);
+
+ RxReferenceNetRoot(NetRoot);
+ RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
+
+ /* Finish init */
+ VNetRoot->SerialNumberForEnum = SerialNumber++;
+ VNetRoot->UpperFinalizationDone = FALSE;
+ VNetRoot->ConnectionFinalizationDone = FALSE;
+ VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
+
+ DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
+ DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
+
+ return VNetRoot;
+}
+
+VOID
+RxDereference(
+ IN OUT PVOID Instance,
+ IN LOCK_HOLDING_STATE LockHoldingState)
+{
+ LONG RefCount;
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+
+ PAGED_CODE();
+
+ RxAcquireScavengerMutex();
+
+ /* Check we have a node we can handle */
+ NodeType = NodeType(Instance);
+ ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
+ (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
+ (NodeType == RDBSS_NTC_FOBX));
+
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
+ ASSERT(RefCount >= 0);
+
+ /* TODO: trace */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ case RDBSS_NTC_NETROOT:
+ case RDBSS_NTC_V_NETROOT:
+ case RDBSS_NTC_SRVOPEN:
+ case RDBSS_NTC_FOBX:
+ UNIMPLEMENTED;
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ /* No need to free - still in use */
+ if (RefCount > 1)
+ {
+ RxReleaseScavengerMutex();
+ return;
+ }
+
+ /* We have to be locked exclusively */
+ if (LockHoldingState != LHS_ExclusiveLockHeld)
+ {
+ UNIMPLEMENTED;
+ RxReleaseScavengerMutex();
+ return;
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* TODO: Really deallocate stuff - we're leaking as hell! */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ {
+ PSRV_CALL SrvCall;
+
+ SrvCall = (PSRV_CALL)Instance;
+
+ ASSERT(SrvCall->RxDeviceObject != NULL);
+ ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
+ RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
+ break;
+ }
+
+ case RDBSS_NTC_NETROOT:
+ UNIMPLEMENTED;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ UNIMPLEMENTED;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ UNIMPLEMENTED;
+ break;
+
+ case RDBSS_NTC_FOBX:
+ UNIMPLEMENTED;
+ break;
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxDereferenceAndDeleteRxContext_Real(
+ IN PRX_CONTEXT RxContext)
+{
+ KIRQL OldIrql;
+ ULONG RefCount;
+ BOOLEAN Allocated;
+ PRX_CONTEXT StopContext = NULL;
+
+ /* Make sure we really have a context */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
+ RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
+ /* If refcount is 0, start releasing stuff that needs spinlock held */
+ if (RefCount == 0)
+ {
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+
+ Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
+
+ /* If that's stop context from DO, remove it */
+ RxDeviceObject = RxContext->RxDeviceObject;
+ if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
+ {
+ RxDeviceObject->StartStopContext.pStopContext = NULL;
+ }
+ else
+ {
+ /* Remove it from the list */
+ ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
+ (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
+ RemoveEntryList(&RxContext->ContextListEntry);
+
+ /* If that was the last active context, save the stop context */
+ if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
+ {
+ if (RxDeviceObject->StartStopContext.pStopContext != NULL)
+ {
+ StopContext = RxDeviceObject->StartStopContext.pStopContext;
+ }
+ }
+ }
+ }
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* Now, deal with what can be done without spinlock held */
+ if (RefCount == 0)
+ {
+ /* Refcount shouldn't have changed */
+ ASSERT(RxContext->ReferenceCount == 0);
+ /* Reset everything that can be */
+ RxPrepareContextForReuse(RxContext);
+
+#ifdef RDBSS_TRACKER
+ ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
+#endif
+ /* If that was the last active, set the event */
+ if (StopContext != NULL)
+ {
+ StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
+ KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* Is ShadowCrit still owned? Shouldn't happen! */
+ if (RxContext->ShadowCritOwner != 0)
+ {
+ DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
+ ASSERT(FALSE);
+ }
+
+ /* If it was allocated, free it */
+ if (Allocated)
+ {
+ ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxDispatchToWorkerThread(
+ IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ IN WORK_QUEUE_TYPE WorkQueueType,
+ IN PRX_WORKERTHREAD_ROUTINE Routine,
+ IN PVOID pContext)
+{
+ NTSTATUS Status;
+ PRX_WORK_DISPATCH_ITEM DispatchItem;
+
+ /* Allocate a bit of context */
+ DispatchItem = ExAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
+ if (DispatchItem == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
+ DispatchItem->DispatchRoutine = Routine;
+ DispatchItem->DispatchRoutineParameter = pContext;
+ DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
+ DispatchItem->WorkQueueItem.Parameter = DispatchItem;
+
+ /* Insert item */
+ Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, DispatchItem);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
+ DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
+ }
+
+ DPRINT("Dispatching: %p, %p\n", Routine, pContext);
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxExclusivePrefixTableLockToShared(
+ PRX_PREFIX_TABLE Table)
+{
+ PAGED_CODE();
+
+ ExConvertExclusiveToSharedLite(&Table->TableLock);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxExtractServerName(
+ IN PUNICODE_STRING FilePathName,
+ OUT PUNICODE_STRING SrvCallName,
+ OUT PUNICODE_STRING RestOfName)
+{
+ USHORT i, Length;
+
+ PAGED_CODE();
+
+ ASSERT(SrvCallName != NULL);
+
+ /* SrvCall name will start from the begin up to the first separator */
+ SrvCallName->Buffer = FilePathName->Buffer;
+ for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
+ {
+ if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ break;
+ }
+ }
+
+ /* Compute length */
+ Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
+ SrvCallName->MaximumLength = Length;
+ SrvCallName->Length = Length;
+
+ /* Return the rest if asked */
+ if (RestOfName != NULL)
+ {
+ Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
+ RestOfName->Buffer = &FilePathName->Buffer[i];
+ RestOfName->MaximumLength = Length;
+ RestOfName->Length = Length;
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFcbTableInsertFcb(
+ IN OUT PRX_FCB_TABLE FcbTable,
+ IN OUT PFCB Fcb)
+{
+ PAGED_CODE();
+
+ /* We deal with the table, make sure it's locked */
+ ASSERT(RxIsFcbTableLockExclusive(FcbTable));
+
+ /* Compute the hash */
+ Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
+
+ RxReferenceNetFcb(Fcb);
+
+ /* If no length, it will be our null entry */
+ if (Fcb->FcbTableEntry.Path.Length == 0)
+ {
+ FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
+ }
+ /* Otherwise, insert in the appropriate bucket */
+ else
+ {
+ InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
+ &Fcb->FcbTableEntry.HashLinks);
+ }
+
+ /* Propagate the change by incrementing the version number */
+ InterlockedIncrement((volatile long *)&FcbTable->Version);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+PFCB
+RxFcbTableLookupFcb(
+ IN PRX_FCB_TABLE FcbTable,
+ IN PUNICODE_STRING Path)
+{
+ PFCB Fcb;
+ PRX_FCB_TABLE_ENTRY TableEntry;
+
+ PAGED_CODE();
+
+ /* No path - easy, that's null entry */
+ if (Path == NULL)
+ {
+ TableEntry = FcbTable->TableEntryForNull;
+ }
+ else
+ {
+ ULONG Hash;
+ PLIST_ENTRY HashBucket, ListEntry;
+
+ /* Otherwise, compute the hash value and find the associated bucket */
+ Hash = RxTableComputePathHashValue(Path);
+ HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
+ /* If the bucket is empty, it means there's no entry yet */
+ if (IsListEmpty(HashBucket))
+ {
+ TableEntry = NULL;
+ }
+ else
+ {
+ /* Otherwise, browse all the entry */
+ for (ListEntry = HashBucket->Flink;
+ ListEntry != HashBucket;
+ ListEntry = ListEntry->Flink)
+ {
+ TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
+ InterlockedIncrement(&FcbTable->Compares);
+
+ /* If entry hash and string are equal, thatt's the one! */
+ if (TableEntry->HashValue == Hash &&
+ TableEntry->Path.Length == Path->Length &&
+ RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
+ {
+ break;
+ }
+ }
+
+ /* We reached the end? Not found */
+ if (ListEntry == HashBucket)
+ {
+ TableEntry = NULL;
+ }
+ }
+ }
+
+ InterlockedIncrement(&FcbTable->Lookups);
+
+ /* If table entry isn't null, return the FCB */
+ if (TableEntry != NULL)
+ {
+ Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
+ RxReferenceNetFcb(Fcb);
+ }
+ else
+ {
+ Fcb = NULL;
+ InterlockedIncrement(&FcbTable->FailedLookups);
+ }
+
+ return Fcb;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFcbTableRemoveFcb(
+ IN OUT PRX_FCB_TABLE FcbTable,
+ IN OUT PFCB Fcb)
+{
+ PAGED_CODE();
+
+ ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
+
+ /* If no path, then remove entry for null */
+ if (Fcb->FcbTableEntry.Path.Length == 0)
+ {
+ FcbTable->TableEntryForNull = NULL;
+ }
+ /* Otherwise, remove from the bucket */
+ else
+ {
+ RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
+ }
+
+ /* Reset its list entry */
+ InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
+
+ /* Propagate the change by incrementing the version number */
+ InterlockedIncrement((volatile long *)&FcbTable->Version);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeNetFcb(
+ OUT PFCB ThisFcb,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize,
+ IN LONG ReferenceCount)
+{
+ PAGED_CODE();
+
+ DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
+ DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
+
+ /* Make sure we have an exclusively acquired FCB */
+ ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+
+ /* We shouldn't force finalization... */
+ ASSERT(!ForceFinalize);
+
+ /* If recurisve, finalize all the associated SRV_OPEN */
+ if (RecursiveFinalize)
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = ThisFcb->SrvOpenList.Flink;
+ ListEntry != &ThisFcb->SrvOpenList;
+ ListEntry = ListEntry->Flink)
+ {
+ PSRV_OPEN SrvOpen;
+
+ SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
+ RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
+ }
+ }
+ /* If FCB is still in use, that's over */
+ else
+ {
+ if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
+ {
+ ASSERT(ReferenceCount > 0);
+
+ return FALSE;
+ }
+ }
+
+ ASSERT(ReferenceCount >= 1);
+
+ /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
+ if (ReferenceCount != 1 && !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
+
+ DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
+
+ /* If finalization was not already initiated, go ahead */
+ if (!ThisFcb->UpperFinalizationDone)
+ {
+ /* Free any FCB_LOCK */
+ if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
+
+ while (ThisFcb->BufferedLocks.List != NULL)
+ {
+ PFCB_LOCK Entry;
+
+ Entry = ThisFcb->BufferedLocks.List;
+ ThisFcb->BufferedLocks.List = Entry->Next;
+
+ ExFreePool(Entry);
+ }
+ }
+
+ /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
+ if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
+
+ ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
+ /* So, remove it */
+ if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
+ {
+ RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
+ }
+ }
+
+ ThisFcb->UpperFinalizationDone = TRUE;
+ }
+
+ ASSERT(ReferenceCount >= 1);
+
+ /* Even if forced, don't allow broken free */
+ if (ReferenceCount != 1)
+ {
+ return FALSE;
+ }
+
+ /* Now, release everything */
+ if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
+ {
+ ExFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
+ }
+
+ if (ThisFcb->MRxDispatch != NULL)
+ {
+ ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
+ }
+
+ ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
+ ExDeleteResourceLite(ThisFcb->Header.Resource);
+ ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
+
+ InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
+ RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
+
+ ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
+ ASSERT(!ThisFcb->fMiniInited);
+
+ /* And free the object */
+ RxFreeFcbObject(ThisFcb);
+
+ return TRUE;
+}
+
+BOOLEAN
+RxFinalizeNetRoot(
+ OUT PNET_ROOT ThisNetRoot,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize
+ )
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOLEAN
+RxFinalizeSrvCall(
+ OUT PSRV_CALL ThisSrvCall,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOLEAN
+RxFinalizeSrvOpen(
+ OUT PSRV_OPEN ThisSrvOpen,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+NTSTATUS
+RxFindOrConstructVirtualNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PUNICODE_STRING CanonicalName,
+ IN NET_ROOT_TYPE NetRootType,
+ IN PUNICODE_STRING RemainingName)
+{
+ ULONG Flags;
+ NTSTATUS Status;
+ PVOID Container;
+ BOOLEAN Construct;
+ PV_NET_ROOT VNetRoot;
+ RX_CONNECTION_ID ConnectionID;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ LOCK_HOLDING_STATE LockHoldingState;
+
+ PAGED_CODE();
+
+ RxDeviceObject = RxContext->RxDeviceObject;
+ ASSERT(RxDeviceObject->Dispatch != NULL);
+ ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
+
+ /* Ask the mini-rdr for connection ID */
+ ConnectionID.SessionID = 0;
+ if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
+ {
+ Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
+ if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
+ {
+ /* mini-rdr is expected not to fail - unless it's not implemented */
+ DPRINT1("Failed to initialize connection ID\n");
+ ASSERT(FALSE);
+ }
+ }
+
+ RxContext->Create.NetNamePrefixEntry = NULL;
+
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
+ LockHoldingState = LHS_SharedLockHeld;
+ Construct = TRUE;
+ Flags = 0;
+
+ /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
+ while (TRUE)
+ {
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT SavedVNetRoot;
+
+ /* Look in prefix table */
+ Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
+ if (Container != NULL)
+ {
+ /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
+ if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
+ {
+ ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
+ RxDereferenceSrvCall(Container, LockHoldingState);
+ }
+ else
+ {
+ VNetRoot = Container;
+ NetRoot = VNetRoot->NetRoot;
+
+ /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
+ if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
+ NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
+ {
+ Status = STATUS_BAD_NETWORK_PATH;
+ SavedVNetRoot = NULL;
+ }
+ else
+ {
+ LUID LogonId;
+ ULONG SessionId;
+ PUNICODE_STRING UserName, UserDomain, Password;
+
+ /* We can reuse if we use same credentials */
+ Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
+ &SessionId, &UserName,
+ &UserDomain, &Password,
+ &Flags);
+ if (NT_SUCCESS(Status))
+ {
+ SavedVNetRoot = VNetRoot;
+ Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
+ &LogonId, UserName,
+ UserDomain, Password,
+ Flags);
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = NetRoot->VirtualNetRoots.Flink;
+ ListEntry != &NetRoot->VirtualNetRoots;
+ ListEntry = ListEntry->Flink)
+ {
+ SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
+ Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
+ &LogonId, UserName,
+ UserDomain, Password,
+ Flags);
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ break;
+ }
+ }
+
+ if (ListEntry == &NetRoot->VirtualNetRoots)
+ {
+ SavedVNetRoot = NULL;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ SavedVNetRoot = NULL;
+ }
+
+ RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
+ }
+ }
+
+ /* We'll fail, if we had referenced a VNetRoot, dereference it */
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
+ {
+ if (SavedVNetRoot == NULL)
+ {
+ RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
+ }
+ }
+ /* Reference VNetRoot we'll keep, and dereference current */
+ else if (SavedVNetRoot != VNetRoot)
+ {
+ RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
+ if (SavedVNetRoot != NULL)
+ {
+ RxReferenceVNetRoot(SavedVNetRoot);
+ }
+ }
+ }
+
+ /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ Construct = FALSE;
+ break;
+ }
+ }
+
+ /* If we're locked exclusive, we won't loop again, it was the second pass */
+ if (LockHoldingState != LHS_SharedLockHeld)
+ {
+ break;
+ }
+
+ /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
+ if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
+ {
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ LockHoldingState = LHS_ExclusiveLockHeld;
+ break;
+ }
+
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
+ LockHoldingState = LHS_ExclusiveLockHeld;
+ }
+
+ /* We didn't fail, and didn't find any VNetRoot, construct one */
+ if (Construct)
+ {
+ ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
+
+ Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
+ ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
+ DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
+ ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
+
+ RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
+ RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
+ RemainingName->MaximumLength = RemainingName->Length;
+
+ if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
+ {
+ DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
+ }
+ VNetRoot->Flags |= Flags;
+ }
+ }
+
+ /* Release the prefix table - caller expects it to be released */
+ if (LockHoldingState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ }
+
+ /* If we failed creating, quit */
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
+ return Status;
+ }
+
+ /* Otherwise, wait until the VNetRoot is stable */
+ DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
+ RxWaitForStableVNetRoot(VNetRoot, RxContext);
+ /* It's all good, update the RX_CONTEXT with all our structs */
+ if (VNetRoot->Condition == Condition_Good)
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = VNetRoot->NetRoot;
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
+ }
+ else
+ {
+ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
+ RxContext->Create.pVNetRoot = NULL;
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFindOrCreateConnections(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _Out_ PUNICODE_STRING LocalNetRootName,
+ _Out_ PUNICODE_STRING FilePathName,
+ _Inout_ PLOCK_HOLDING_STATE LockState,
+ _In_ PRX_CONNECTION_ID RxConnectionId)
+{
+ PVOID Container;
+ PSRV_CALL SrvCall;
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT VNetRoot;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PRX_PREFIX_TABLE PrefixTable;
+ UNICODE_STRING RemainingName, NetRootName;
+
+ PAGED_CODE();
+
+ DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
+ RxContext, CanonicalName, NetRootType, LocalNetRootName,
+ FilePathName, LockState, RxConnectionId);
+
+ *FilePathName = *CanonicalName;
+ LocalNetRootName->Length = 0;
+ LocalNetRootName->MaximumLength = 0;
+ LocalNetRootName->Buffer = CanonicalName->Buffer;
+
+ /* UNC path, split it */
+ if (FilePathName->Buffer[1] == ';')
+ {
+ BOOLEAN Slash;
+ USHORT i, Length;
+
+ Slash = FALSE;
+ for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
+ {
+ if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ Slash = TRUE;
+ break;
+ }
+ }
+
+ if (!Slash)
+ {
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ FilePathName->Buffer = &FilePathName->Buffer[i];
+ Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
+ LocalNetRootName->Length = Length;
+ LocalNetRootName->MaximumLength = Length;
+ FilePathName->Length -= Length;
+
+ DPRINT("CanonicalName: %wZ\n", CanonicalName);
+ DPRINT(" -> FilePathName: %wZ\n", FilePathName);
+ DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
+ }
+
+ Container = NULL;
+ PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
+
+ _SEH2_TRY
+ {
+RetryLookup:
+ ASSERT(*LockState != LHS_LockNotHeld);
+
+ /* If previous lookup left something, dereference it */
+ if (Container != NULL)
+ {
+ switch (NodeType(Container))
+ {
+ case RDBSS_NTC_SRVCALL:
+ RxDereferenceSrvCall(Container, *LockState);
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ RxDereferenceNetRoot(Container, *LockState);
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ RxDereferenceVNetRoot(Container, *LockState);
+ break;
+
+ default:
+ /* Should never happen */
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ /* Look for our NetRoot in prefix table */
+ Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
+ DPRINT("Container %p for path %wZ\n", Container, FilePathName);
+
+ while (TRUE)
+ {
+ UNICODE_STRING SrvCallName;
+
+ SrvCall = NULL;
+ NetRoot = NULL;
+ VNetRoot = NULL;
+
+ /* Assume we didn't succeed */
+ RxContext->Create.pVNetRoot = NULL;
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pSrvCall = NULL;
+ RxContext->Create.Type = NetRootType;
+
+ /* If we found something */
+ if (Container != NULL)
+ {
+ /* A VNetRoot */
+ if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
+ {
+ VNetRoot = Container;
+ /* Use its NetRoot */
+ NetRoot = VNetRoot->NetRoot;
+
+ /* If it's not stable, wait for it to be stable */
+ if (NetRoot->Condition == Condition_InTransition)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ DPRINT("Waiting for stable condition for: %p\n", NetRoot);
+ RxWaitForStableNetRoot(NetRoot, RxContext);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+
+ /* Now that's it's ok, retry lookup to find what we want */
+ if (NetRoot->Condition == Condition_Good)
+ {
+ goto RetryLookup;
+ }
+ }
+
+ /* Is the associated netroot good? */
+ if (NetRoot->Condition == Condition_Good)
+ {
+ SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
+
+ /* If it is, and SrvCall as well, then, we have our active connection */
+ if (SrvCall->Condition == Condition_Good &&
+ SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
+ {
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
+
+ Status = STATUS_CONNECTION_ACTIVE;
+ _SEH2_LEAVE;
+ }
+ }
+
+ /* If VNetRoot was well constructed, it means the connection is active */
+ if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
+ {
+ Status = STATUS_CONNECTION_ACTIVE;
+ }
+ else
+ {
+ Status = VNetRoot->ConstructionStatus;
+ }
+
+ RxDereferenceVNetRoot(VNetRoot, *LockState);
+ _SEH2_LEAVE;
+ }
+ /* Can only be a SrvCall */
+ else
+ {
+ ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
+ SrvCall = Container;
+
+ /* Wait for the SRV_CALL to be stable */
+ if (SrvCall->Condition == Condition_InTransition)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ DPRINT("Waiting for stable condition for: %p\n", SrvCall);
+ RxWaitForStableSrvCall(SrvCall, RxContext);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+
+ /* It went good, loop again to find what we look for */
+ if (SrvCall->Condition == Condition_Good)
+ {
+ goto RetryLookup;
+ }
+ }
+
+ /* If it's not good... */
+ if (SrvCall->Condition != Condition_Good)
+ {
+ /* But SRV_CALL was well constructed, assume a connection was active */
+ if (SrvCall->Status == STATUS_SUCCESS)
+ {
+ Status = STATUS_CONNECTION_ACTIVE;
+ }
+ else
+ {
+ Status = SrvCall->Status;
+ }
+
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ _SEH2_LEAVE;
+ }
+ }
+ }
+
+ /* If we found a SRV_CALL not matching our DO, quit */
+ if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
+ SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
+ {
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ Status = STATUS_BAD_NETWORK_NAME;
+ _SEH2_LEAVE;
+ }
+
+ /* Now, we want exclusive lock */
+ if (*LockState == LHS_SharedLockHeld)
+ {
+ if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+ goto RetryLookup;
+ }
+
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockState = LHS_ExclusiveLockHeld;
+ }
+
+ ASSERT(*LockState == LHS_ExclusiveLockHeld);
+
+ /* If we reach that point, we found something, no need to create something */
+ if (Container != NULL)
+ {
+ break;
+ }
+
+ /* Get the name for the SRV_CALL */
+ RxExtractServerName(FilePathName, &SrvCallName, NULL);
+ DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
+ /* And create the SRV_CALL */
+ SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
+ if (SrvCall == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+
+ /* Reset RX_CONTEXT, so far, connection creation isn't a success */
+ RxReferenceSrvCall(SrvCall);
+ RxContext->Create.pVNetRoot = NULL;
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pSrvCall = NULL;
+ RxContext->Create.Type = NetRootType;
+ Container = SrvCall;
+
+ /* Construct SRV_CALL, ie, use mini-rdr */
+ Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
+ ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ RxReleasePrefixTableLock(PrefixTable);
+ _SEH2_LEAVE;
+ }
+
+ /* Loop again to make use of SRV_CALL stable condition wait */
+ }
+
+ /* At that point, we have a stable SRV_CALL (either found or constructed) */
+ ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
+ ASSERT(NetRoot == NULL && VNetRoot == NULL);
+ ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
+
+ /* Call mini-rdr to get NetRoot name */
+ SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
+ /* And create the NetRoot with that name */
+ NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
+ if (NetRoot == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+ NetRoot->Type = NetRootType;
+
+ RxDereferenceSrvCall(SrvCall, *LockState);
+
+ /* Finally, create the associated VNetRoot */
+ VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
+ if (VNetRoot == NULL)
+ {
+ RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+ RxReferenceVNetRoot(VNetRoot);
+
+ /* We're get closer! */
+ NetRoot->Condition = Condition_InTransition;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+
+ /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
+ Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
+ if (!NT_SUCCESS(Status))
+ {
+ RxTransitionVNetRoot(VNetRoot, Condition_Bad);
+ DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
+ RxDereferenceVNetRoot(VNetRoot, *LockState);
+
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pVNetRoot = NULL;
+ }
+ else
+ {
+ PIO_STACK_LOCATION Stack;
+
+ ASSERT(*LockState == LHS_ExclusiveLockHeld);
+
+ Stack = RxContext->CurrentIrpSp;
+ if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
+ {
+ RxExclusivePrefixTableLockToShared(PrefixTable);
+ *LockState = LHS_SharedLockHeld;
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
+ {
+ if (*LockState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockState = LHS_LockNotHeld;
+ }
+ }
+ }
+ _SEH2_END;
+
+ DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxFinishFcbInitialization(
+ IN OUT PMRX_FCB Fcb,
+ IN RX_FILE_TYPE FileType,
+ IN PFCB_INIT_PACKET InitPacket OPTIONAL)
+{
+ NODE_TYPE_CODE OldType;
+
+ PAGED_CODE();
+
+ DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
+
+ OldType = Fcb->Header.NodeTypeCode;
+ Fcb->Header.NodeTypeCode = FileType;
+ /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
+ {
+ FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
+ else if (InitPacket != NULL)
+ {
+ FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
+ InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
+ InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
+ InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
+ InitPacket->pValidDataLength->QuadPart);
+ }
+
+ if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
+ FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ /* If our FCB newly points to a file, initiliaz everything related */
+ if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
+ !OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
+ FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
+ &RxUnlockOperation);
+
+ ((PFCB)Fcb)->BufferedLocks.List = NULL;
+ ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
+
+ Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+ }
+ else
+ {
+ ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFinishSrvCallConstruction(
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown)
+{
+ NTSTATUS Status;
+ PSRV_CALL SrvCall;
+ PRX_CONTEXT Context;
+ RX_BLOCK_CONDITION Condition;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
+
+ SrvCall = (PSRV_CALL)Calldown->SrvCall;
+ Context = Calldown->RxContext;
+ PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
+
+ /* We have a winner, notify him */
+ if (Calldown->BestFinisher != NULL)
+ {
+ DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
+
+ ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
+
+ MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
+ MRxSrvCallWinnerNotify,
+ ((PMRX_SRV_CALL)SrvCall, TRUE,
+ Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
+ if (Status != STATUS_SUCCESS)
+ {
+ Condition = Condition_Bad;
+ }
+ else
+ {
+ Condition = Condition_Good;
+ }
+ }
+ /* Otherwise, just fail our SRV_CALL */
+ else
+ {
+ Status = Calldown->CallbackContexts[0].Status;
+ Condition = Condition_Bad;
+ }
+
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ RxTransitionSrvCall(SrvCall, Condition);
+ ExFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
+
+ /* If async, finish it here, otherwise, caller has already finished the stuff */
+ if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
+ {
+ DPRINT("Finishing async call\n");
+
+ RxReleasePrefixTableLock(PrefixTable);
+
+ /* Make sure we weren't cancelled in-between */
+ if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
+ {
+ Status = STATUS_CANCELLED;
+ }
+
+ /* In case that was a create, context can be reused */
+ if (Context->MajorFunction == IRP_MJ_CREATE)
+ {
+ RxpPrepareCreateContextForReuse(Context);
+ }
+
+ /* If that's a failure, reset everything and return failure */
+ if (Status != STATUS_SUCCESS)
+ {
+ Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
+ if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ {
+ if (Context->Info.Buffer != NULL)
+ {
+ ExFreePool(Context->Info.Buffer);
+ Context->Info.Buffer = NULL;
+ }
+ }
+ Context->CurrentIrp->IoStatus.Information = 0;
+ Context->CurrentIrp->IoStatus.Status = Status;
+ RxCompleteRequest(Context, Status);
+ }
+ /* Otherwise, call resume routine and done! */
+ else
+ {
+ Status = Context->ResumeRoutine(Context);
+ if (Status != STATUS_PENDING)
+ {
+ RxCompleteRequest(Context, Status);
+ }
+
+ DPRINT("Not completing, pending\n");
+ }
+ }
+
+ RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxFinishSrvCallConstructionDispatcher(
+ IN PVOID Context)
+{
+ KIRQL OldIrql;
+ BOOLEAN Direct, KeepLoop;
+
+ DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
+
+ /* In case of failure of starting dispatcher, context is not set
+ * We keep track of it to fail associated SRV_CALL
+ */
+ Direct = (Context == NULL);
+
+ /* Separated thread, loop forever */
+ while (TRUE)
+ {
+ PLIST_ENTRY ListEntry;
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown;
+
+ /* If there are no SRV_CALL to finalize left, just finish thread */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ if (IsListEmpty(&RxSrvCalldownList))
+ {
+ KeepLoop = FALSE;
+ RxSrvCallConstructionDispatcherActive = FALSE;
+ }
+ /* Otherwise, get the SRV_CALL to finish construction */
+ else
+ {
+ ListEntry = RemoveHeadList(&RxSrvCalldownList);
+ KeepLoop = TRUE;
+ }
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* Nothing to do */
+ if (!KeepLoop)
+ {
+ break;
+ }
+
+ /* If direct is set, reset the finisher to avoid electing a winner
+ * and fail SRV_CALL (see upper comment)
+ */
+ Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
+ if (Direct)
+ {
+ Calldown->BestFinisher = NULL;
+ }
+ /* Finish SRV_CALL construction */
+ RxFinishSrvCallConstruction(Calldown);
+ }
+}
+
+VOID
+RxFreeFcbObject(
+ PVOID Object)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxFreeObject(
+ PVOID pObject)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxGetFileSizeWithLock(
+ IN PFCB Fcb,
+ OUT PLONGLONG FileSize)
+{
+ PAGED_CODE();
+
+ *FileSize = Fcb->Header.FileSize.QuadPart;
+}
+
+/*
+ * @implemented
+ */
+PEPROCESS
+NTAPI
+RxGetRDBSSProcess(
+ VOID)
+{
+ return RxData.OurProcess;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeBufferingManager(
+ PSRV_CALL SrvCall)
+{
+ KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
+ InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
+ InitializeListHead(&SrvCall->BufferingManager.HandlerList);
+ InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
+ SrvCall->BufferingManager.DispatcherActive = FALSE;
+ SrvCall->BufferingManager.HandlerInactive = FALSE;
+ SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
+ SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
+ InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
+ ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxInitializeContext(
+ IN PIRP Irp,
+ IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ IN ULONG InitialContextFlags,
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PIO_STACK_LOCATION Stack;
+
+ /* Initialize our various fields */
+ RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
+ RxContext->NodeByteSize = sizeof(RX_CONTEXT);
+ RxContext->ReferenceCount = 1;
+ RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
+ RxContext->RxDeviceObject = RxDeviceObject;
+ KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
+ RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
+ InitializeListHead(&RxContext->BlockedOperations);
+ RxContext->MRxCancelRoutine = NULL;
+ RxContext->ResumeRoutine = NULL;
+ RxContext->Flags |= InitialContextFlags;
+ RxContext->CurrentIrp = Irp;
+ RxContext->LastExecutionThread = PsGetCurrentThread();
+ RxContext->OriginalThread = RxContext->LastExecutionThread;
+
+ /* If've got no IRP, mark RX_CONTEXT */
+ if (Irp == NULL)
+ {
+ RxContext->CurrentIrpSp = NULL;
+ RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
+ RxContext->MinorFunction = 0;
+ }
+ else
+ {
+ /* Otherwise, first determine whether we are performing async operation */
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->FileObject != NULL)
+ {
+ PFCB Fcb;
+
+ Fcb = Stack->FileObject->FsContext;
+ if (!IoIsOperationSynchronous(Irp) ||
+ ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
+ (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
+ (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+ }
+
+ if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+ if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+
+ /* Set proper flags if TopLevl IRP/Device */
+ if (!RxIsThisTheTopLevelIrp(Irp))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
+ }
+ if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
+ }
+
+ /* Copy stack information */
+ RxContext->MajorFunction = Stack->MajorFunction;
+ RxContext->MinorFunction = Stack->MinorFunction;
+ ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
+ RxContext->CurrentIrpSp = Stack;
+
+ /* If we have a FO associated, learn for more */
+ if (Stack->FileObject != NULL)
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+
+ /* Get the FCB and CCB (FOBX) */
+ Fcb = Stack->FileObject->FsContext;
+ Fobx = Stack->FileObject->FsContext2;
+ RxContext->pFcb = (PMRX_FCB)Fcb;
+ if (Fcb != NULL && NodeTypeIsFcb(Fcb))
+ {
+ RxContext->NonPagedFcb = Fcb->NonPaged;
+ }
+
+ /* We have a FOBX, this not a DFS opening, keep track of it */
+ if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
+ {
+ RxContext->pFobx = (PMRX_FOBX)Fobx;
+ RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
+ if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
+ {
+ RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
+ }
+ }
+ else
+ {
+ RxContext->pFobx = NULL;
+ }
+
+ /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
+ if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
+ Fobx != NULL)
+ {
+ PV_NET_ROOT VNetRoot = NULL;
+
+ if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
+ {
+ VNetRoot = Fcb->VNetRoot;
+ }
+ else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
+ {
+ VNetRoot = (PV_NET_ROOT)Fobx;
+ }
+
+ if (VNetRoot != NULL)
+ {
+ RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ }
+ }
+
+ /* Remember if that's a write through file */
+ RxContext->RealDevice = Stack->FileObject->DeviceObject;
+ if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
+ }
+ }
+ }
+
+ if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
+ {
+ DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
+ RxContext, RxContext->MinorFunction, Irp,
+ PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
+ RxContext->SerialNumber);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxInitializeDispatcher(
+ VOID)
+{
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+
+ PAGED_CODE();
+
+ RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
+ RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
+
+ /* Set appropriate timeouts: 10s & 60s */
+ RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
+
+ RxDispatcher.NumberOfProcessors = 1;
+ RxDispatcher.OwnerProcess = IoGetCurrentProcess();
+ RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
+
+ /* Initialize our dispatchers */
+ Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* And start them */
+ RxDispatcher.State = RxDispatcherActive;
+ InitializeListHead(&RxDispatcher.SpinUpRequests);
+ KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
+ KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
+ KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
+ Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
+ NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
+ if (NT_SUCCESS(Status))
+ {
+ ZwClose(ThreadHandle);
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializeFcbTable(
+ IN OUT PRX_FCB_TABLE FcbTable,
+ IN BOOLEAN CaseInsensitiveMatch)
+{
+ USHORT i;
+
+ PAGED_CODE();
+
+ FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
+ FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
+
+ ExInitializeResourceLite(&FcbTable->TableLock);
+ FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
+ FcbTable->Version = 0;
+ FcbTable->TableEntryForNull = NULL;
+
+ FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
+ for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
+ {
+ InitializeListHead(&FcbTable->HashBuckets[i]);
+ }
+
+ FcbTable->Lookups = 0;
+ FcbTable->FailedLookups = 0;
+ FcbTable->Compares = 0;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxInitializeLowIoContext(
+ OUT PLOWIO_CONTEXT LowIoContext,
+ IN ULONG Operation)
+{
+ PRX_CONTEXT RxContext;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
+ ASSERT(LowIoContext = &RxContext->LowIoContext);
+
+ Stack = RxContext->CurrentIrpSp;
+
+ KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
+ RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
+ RxContext->LowIoContext.Operation = Operation;
+
+ switch (Operation)
+ {
+ case LOWIO_OP_READ:
+ case LOWIO_OP_WRITE:
+ /* In case of RW, set a canary, to make sure these fields are properly set
+ * they will be asserted when lowio request will be submit to mini-rdr
+ * See LowIoSubmit()
+ */
+ RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
+ RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
+
+ /* Keep track of paging IOs */
+ if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
+ {
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
+ }
+ else
+ {
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
+ }
+
+ break;
+
+ case LOWIO_OP_FSCTL:
+ case LOWIO_OP_IOCTL:
+ /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
+ RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
+ RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
+ RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
+ break;
+
+ /* Nothing to do for these */
+ case LOWIO_OP_SHAREDLOCK:
+ case LOWIO_OP_EXCLUSIVELOCK:
+ case LOWIO_OP_UNLOCK:
+ case LOWIO_OP_UNLOCK_MULTIPLE:
+ case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
+ case LOWIO_OP_CLEAROUT:
+ break;
+
+ default:
+ /* Should never happen */
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializeLowIoPerFcbInfo(
+ PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
+{
+ PAGED_CODE();
+
+ InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
+ InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeMRxDispatcher(
+ IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
+{
+ PAGED_CODE();
+
+ pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
+ pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializePrefixTable(
+ IN OUT PRX_PREFIX_TABLE ThisTable,
+ IN ULONG TableSize OPTIONAL,
+ IN BOOLEAN CaseInsensitiveMatch)
+{
+ PAGED_CODE();
+
+ if (TableSize == 0)
+ {
+ TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
+ }
+
+ ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
+ ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
+ InitializeListHead(&ThisTable->MemberQueue);
+ ThisTable->Version = 0;
+ ThisTable->TableEntryForNull = NULL;
+ ThisTable->IsNetNameTable = FALSE;
+ ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
+ ThisTable->TableSize = TableSize;
+
+ if (TableSize > 0)
+ {
+ USHORT i;
+
+ for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
+ {
+ InitializeListHead(&ThisTable->HashBuckets[i]);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializePurgeSyncronizationContext(
+ PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
+{
+ PAGED_CODE();
+
+ InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
+ PurgeSyncronizationContext->PurgeInProgress = FALSE;
+}
+
+NTSTATUS
+RxInitializeSrvCallParameters(
+ IN PRX_CONTEXT RxContext,
+ IN OUT PSRV_CALL SrvCall)
+{
+ PAGED_CODE();
+
+ SrvCall->pPrincipalName = NULL;
+
+ /* We only have stuff to initialize for file opening from DFS */
+ if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ ASSERT(RxContext->Create.EaBuffer != NULL);
+
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxInitializeVNetRootParameters(
+ PRX_CONTEXT RxContext,
+ OUT LUID *LogonId,
+ OUT PULONG SessionId,
+ OUT PUNICODE_STRING *UserNamePtr,
+ OUT PUNICODE_STRING *UserDomainNamePtr,
+ OUT PUNICODE_STRING *PasswordPtr,
+ OUT PULONG Flags)
+{
+ NTSTATUS Status;
+ PACCESS_TOKEN Token;
+
+ PAGED_CODE();
+
+ DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
+ LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
+
+ *UserNamePtr = NULL;
+ *UserDomainNamePtr = NULL;
+ *PasswordPtr = NULL;
+ /* By default, that's not CSC instance */
+ *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
+
+ Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
+ if (SeTokenIsRestricted(Token))
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ /* Get LogonId */
+ Status = SeQueryAuthenticationIdToken(Token, LogonId);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* And SessionId */
+ Status = SeQuerySessionIdToken(Token, SessionId);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ if (RxContext->Create.UserName.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
+
+ /* Deal with connection credentials */
+ if (RxContext->Create.UserDomainName.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
+
+ if (RxContext->Create.Password.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
+
+Leave:
+ if (NT_SUCCESS(Status))
+ {
+ /* If that's a CSC instance, mark it as such */
+ if (RxIsThisACscAgentOpen(RxContext))
+ {
+ *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
+ }
+ return Status;
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializeWorkQueue(
+ PRX_WORK_QUEUE WorkQueue,
+ WORK_QUEUE_TYPE WorkQueueType,
+ ULONG MaximumNumberOfWorkerThreads,
+ ULONG MinimumNumberOfWorkerThreads)
+{
+ PAGED_CODE();
+
+ WorkQueue->Type = WorkQueueType;
+ WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
+ WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
+
+ WorkQueue->State = RxWorkQueueActive;
+ WorkQueue->SpinUpRequestPending = FALSE;
+ WorkQueue->pRundownContext = NULL;
+ WorkQueue->NumberOfWorkItemsDispatched = 0;
+ WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
+ WorkQueue->CumulativeQueueLength = 0;
+ WorkQueue->NumberOfSpinUpRequests = 0;
+ WorkQueue->NumberOfActiveWorkerThreads = 0;
+ WorkQueue->NumberOfIdleWorkerThreads = 0;
+ WorkQueue->NumberOfFailedSpinUpRequests = 0;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
+
+ KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
+ KeInitializeSpinLock(&WorkQueue->SpinLock);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeWorkQueueDispatcher(
+ PRX_WORK_QUEUE_DISPATCHER Dispatcher)
+{
+ NTSTATUS Status;
+ ULONG MaximumNumberOfWorkerThreads;
+
+ PAGED_CODE();
+
+ /* Number of threads will depend on system capacity */
+ if (MmQuerySystemSize() != MmLargeSystem)
+ {
+ MaximumNumberOfWorkerThreads = 5;
+ }
+ else
+ {
+ MaximumNumberOfWorkerThreads = 10;
+ }
+
+ /* Initialize the work queues */
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
+ MaximumNumberOfWorkerThreads, 1);
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
+
+ /* And start the worker threads */
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[CriticalWorkQueue]);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[DelayedWorkQueue]);
+ return Status;
+}
+
+VOID
+RxInitiateSrvOpenKeyAssociation (
+ IN OUT PSRV_OPEN SrvOpen
+ )
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInsertWorkQueueItem(
+ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ WORK_QUEUE_TYPE WorkQueueType,
+ PRX_WORK_DISPATCH_ITEM DispatchItem)
+{
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN SpinUpThreads;
+ PRX_WORK_QUEUE WorkQueue;
+
+ /* No dispatcher, nothing to insert */
+ if (RxDispatcher.State != RxDispatcherActive)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Get the work queue */
+ WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
+
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ /* Only insert if the work queue is in decent state */
+ if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ SpinUpThreads = FALSE;
+ DispatchItem->WorkQueueItem.pDeviceObject = pMRxDeviceObject;
+ InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
+ WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
+ InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
+
+ /* If required (and possible!), spin up a new worker thread */
+ if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
+ WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
+ !WorkQueue->SpinUpRequestPending)
+ {
+ WorkQueue->SpinUpRequestPending = TRUE;
+ SpinUpThreads = TRUE;
+ }
+
+ Status = STATUS_SUCCESS;
+ }
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+
+ /* If we failed, return and still not insert item */
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* All fine, insert the item */
+ KeInsertQueue(&WorkQueue->Queue, &DispatchItem->WorkQueueItem.List);
+
+ /* And start a new worker thread if needed */
+ if (SpinUpThreads)
+ {
+ RxSpinUpWorkerThreads(WorkQueue);
+ }
+
+ return Status;
+}
+
+BOOLEAN
+RxIsThisACscAgentOpen(
+ IN PRX_CONTEXT RxContext)
+{
+ BOOLEAN CscAgent;
+
+ CscAgent = FALSE;
+
+ /* Client Side Caching is DFS stuff - we don't support it */
+ if (RxContext->Create.EaLength != 0)
+ {
+ UNIMPLEMENTED;
+ }
+
+ if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
+ ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
+ {
+ CscAgent = TRUE;
+ }
+
+ return CscAgent;
+}
+
+VOID
+RxLockUserBuffer(
+ IN PRX_CONTEXT RxContext,
+ IN LOCK_OPERATION Operation,
+ IN ULONG BufferLength)
+{
+ PIRP Irp;
+ PMDL Mdl = NULL;
+
+ PAGED_CODE();
+
+ _SEH2_TRY
+ {
+ Irp = RxContext->CurrentIrp;
+ /* If we already have a MDL, make sure it's locked */
+ if (Irp->MdlAddress != NULL)
+ {
+ ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
+ }
+ else
+ {
+ /* That likely means the driver asks for buffered IOs - we don't support it! */
+ ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
+
+ /* If we have a real length */
+ if (BufferLength > 0)
+ {
+ /* Allocate a MDL and lock it */
+ Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
+ if (Mdl == NULL)
+ {
+ RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ NTSTATUS Status;
+
+ Status = _SEH2_GetExceptionCode();
+
+ /* Free the possible MDL we have allocated */
+ IoFreeMdl(Mdl);
+ Irp->MdlAddress = NULL;
+
+ RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
+
+ /* Fix status */
+ if (!FsRtlIsNtstatusExpected(Status))
+ {
+ Status = STATUS_INVALID_USER_BUFFER;
+ }
+
+ RxContext->IoStatusBlock.Status = Status;
+ ExRaiseStatus(Status);
+ }
+ _SEH2_END;
+}
+
+NTSTATUS
+RxLowIoCompletionTail(
+ IN PRX_CONTEXT RxContext)
+{
+ NTSTATUS Status;
+ USHORT Operation;
+
+ PAGED_CODE();
+
+ DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
+
+ /* Only continue if we're at APC_LEVEL or lower */
+ if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
+ !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
+ {
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* Call the completion routine */
+ DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
+ Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
+ {
+ return Status;
+ }
+
+ /* If it was a RW operation, for a paging file ... */
+ Operation = RxContext->LowIoContext.Operation;
+ if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
+ {
+ if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else
+ {
+ /* Sanity check: we had known operation */
+ ASSERT(Operation < LOWIO_OP_MAXIMUM);
+ }
+
+ /* If not sync operation, complete now. Otherwise, caller has already completed */
+ if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
+ {
+ RxCompleteRequest(RxContext, Status);
+ }
+
+ DPRINT("Status: %x\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxLowIoPopulateFsctlInfo(
+ IN PRX_CONTEXT RxContext)
+{
+ PMDL Mdl;
+ PIRP Irp;
+ UCHAR Method;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
+
+ Irp = RxContext->CurrentIrp;
+ Stack = RxContext->CurrentIrpSp;
+
+ /* Copy stack parameters */
+ RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
+ RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
+ RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
+ RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
+ Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
+
+ /* Same buffer in case of buffered */
+ if (Method == METHOD_BUFFERED)
+ {
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Two buffers for neither */
+ if (Method == METHOD_NEITHER)
+ {
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Only IN/OUT remain */
+ ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
+
+ /* Use system buffer for input */
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ /* And MDL for output */
+ Mdl = Irp->MdlAddress;
+ if (Mdl != NULL)
+ {
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+ if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RxLowIoSubmit(
+ IN PRX_CONTEXT RxContext,
+ IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
+{
+ NTSTATUS Status;
+ USHORT Operation;
+ BOOLEAN Synchronous;
+ PLOWIO_CONTEXT LowIoContext;
+
+ DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
+
+ PAGED_CODE();
+
+ LowIoContext = &RxContext->LowIoContext;
+ Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+
+ LowIoContext->CompletionRoutine = CompletionRoutine;
+
+ Status = STATUS_SUCCESS;
+ Operation = LowIoContext->Operation;
+ switch (Operation)
+ {
+ case LOWIO_OP_READ:
+ case LOWIO_OP_WRITE:
+ /* Check that the parameters were properly set by caller
+ * See comment in RxInitializeLowIoContext()
+ */
+ ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
+ ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
+
+ /* Lock the buffer */
+ RxLockUserBuffer(RxContext,
+ (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
+ LowIoContext->ParamsFor.ReadWrite.ByteCount);
+ if (RxNewMapUserBuffer(RxContext) == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
+
+ /* If that's a paging IO, initialize serial operation */
+ if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
+ {
+ PFCB Fcb;
+
+ Fcb = (PFCB)RxContext->pFcb;
+
+ ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
+ if (Operation == LOWIO_OP_READ)
+ {
+ InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
+ }
+ else
+ {
+ InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
+ }
+
+ ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ }
+
+ break;
+
+ case LOWIO_OP_FSCTL:
+ case LOWIO_OP_IOCTL:
+ /* Set FSCTL/IOCTL parameters */
+ Status = RxLowIoPopulateFsctlInfo(RxContext);
+ /* Check whether we're consistent: a length means a buffer */
+ if (NT_SUCCESS(Status))
+ {
+ if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
+ LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
+ (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
+ LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ /* Nothing to do */
+ case LOWIO_OP_SHAREDLOCK:
+ case LOWIO_OP_EXCLUSIVELOCK:
+ case LOWIO_OP_UNLOCK:
+ case LOWIO_OP_UNLOCK_MULTIPLE:
+ case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
+ case LOWIO_OP_CLEAROUT:
+ break;
+
+ default:
+ ASSERT(FALSE);
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* No need to perform extra init in case of posting */
+ RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
+
+ /* Preflight checks were OK, time to submit */
+ if (NT_SUCCESS(Status))
+ {
+ PMINIRDR_DISPATCH Dispatch;
+
+ if (!Synchronous)
+ {
+ InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
+ /* If not synchronous, we're likely to return before the operation is finished */
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
+ {
+ IoMarkIrpPending(RxContext->CurrentIrp);
+ }
+ }
+
+ Dispatch = RxContext->RxDeviceObject->Dispatch;
+ if (Dispatch != NULL)
+ {
+ /* We'll try to execute until the mini-rdr doesn't return pending */
+ do
+ {
+ RxContext->IoStatusBlock.Information = 0;
+
+ MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
+ if (Status == STATUS_PENDING)
+ {
+ /* Unless it's not synchronous, caller will be happy with pending op */
+ if (!Synchronous)
+ {
+ return Status;
+ }
+
+ RxWaitSync(RxContext);
+ Status = RxContext->IoStatusBlock.Status;
+ }
+ else
+ {
+ if (!Synchronous)
+ {
+ /* We had marked the IRP pending, whereas the operation finished, drop that */
+ if (Status != STATUS_RETRY)
+ {
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
+ {
+ RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
+ }
+
+ InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
+ }
+ }
+ }
+ } while (Status == STATUS_PENDING);
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Call completion and return */
+ RxContext->IoStatusBlock.Status = Status;
+ LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
+ return RxLowIoCompletionTail(RxContext);
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxMapSystemBuffer(
+ IN PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ Irp = RxContext->CurrentIrp;
+ /* We should have a MDL (buffered IOs are not supported!) */
+ if (Irp->MdlAddress != NULL)
+ {
+ ASSERT(FALSE);
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ }
+
+ /* Just return system buffer */
+ return Irp->AssociatedIrp.SystemBuffer;
+}
+
+VOID
+RxMarkFobxOnCleanup(
+ PFOBX pFobx,
+ PBOOLEAN NeedPurge)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxMarkFobxOnClose(
+ PFOBX Fobx)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxNewMapUserBuffer(
+ PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ Irp = RxContext->CurrentIrp;
+ if (Irp->MdlAddress != NULL)
+ {
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ }
+
+ return Irp->UserBuffer;
+}
+
+BOOLEAN
+NTAPI
+RxNoOpAcquire(
+ IN PVOID Fcb,
+ IN BOOLEAN Wait)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+VOID
+NTAPI
+RxNoOpRelease(
+ IN PVOID Fcb)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxOrphanThisFcb(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockShared(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
+
+ DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
+
+ return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockExclusive(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
+
+ DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
+
+ return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpDereferenceAndFinalizeNetFcb(
+ OUT PFCB ThisFcb,
+ IN PRX_CONTEXT RxContext,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ NTSTATUS Status;
+ ULONG References;
+ PNET_ROOT NetRoot;
+ BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
+
+ PAGED_CODE();
+
+ ASSERT(!ForceFinalize);
+ ASSERT(NodeTypeIsFcb(ThisFcb));
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+
+ /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
+ References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
+ if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
+ {
+ return FALSE;
+ }
+
+ Freed = FALSE;
+ Status = STATUS_SUCCESS;
+ NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
+ ResourceAcquired = FALSE;
+ NetRootReferenced = FALSE;
+ /* If FCB isn't orphaned, it still have context attached */
+ if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ /* Don't let NetRoot go away before we're done */
+ RxReferenceNetRoot(NetRoot);
+ NetRootReferenced = TRUE;
+
+ /* Try to acquire the table lock exclusively */
+ if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
+ {
+ RxReferenceNetFcb(ThisFcb);
+
+ if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
+ {
+ if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
+ }
+
+ RxReleaseFcb(RxContext, ThisFcb);
+
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+
+ Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
+ }
+
+ References = RxDereferenceNetFcb(ThisFcb);
+
+ ResourceAcquired = TRUE;
+ }
+ }
+
+ /* If locking was OK (or not needed!), attempt finalization */
+ if (NT_SUCCESS(Status))
+ {
+ Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
+ }
+
+ /* Release table lock if acquired */
+ if (ResourceAcquired)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+
+ /* We don't need the NetRoot anylonger */
+ if (NetRootReferenced)
+ {
+ RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
+ }
+
+ return Freed;
+}
+
+LONG
+RxpDereferenceNetFcb(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+ return 0;
+}
+
+/*
+ * @implemented
+ */
+PRX_PREFIX_ENTRY
+RxPrefixTableInsertName(
+ IN OUT PRX_PREFIX_TABLE ThisTable,
+ IN OUT PRX_PREFIX_ENTRY ThisEntry,
+ IN PVOID Container,
+ IN PULONG ContainerRefCount,
+ IN USHORT CaseInsensitiveLength,
+ IN PRX_CONNECTION_ID ConnectionId
+ )
+{
+ PAGED_CODE();
+
+ DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
+
+ ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
+ ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
+
+ /* Copy parameters and compute hash */
+ ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
+ ThisEntry->ContainingRecord = Container;
+ ThisEntry->ContainerRefCount = ContainerRefCount;
+ InterlockedIncrement((volatile long *)ContainerRefCount);
+ ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
+ DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
+
+ /* If no path length: this is entry for null path */
+ if (ThisEntry->Prefix.Length == 0)
+ {
+ ThisTable->TableEntryForNull = ThisEntry;
+ }
+ /* Otherwise, insert in the appropriate bucket */
+ else
+ {
+ InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
+ }
+
+ /* If we had a connection ID, keep track of it */
+ if (ConnectionId != NULL)
+ {
+ ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
+ }
+ else
+ {
+ ThisEntry->ConnectionId.Luid.LowPart = 0;
+ ThisEntry->ConnectionId.Luid.HighPart = 0;
+ }
+
+ InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
+ /* Reflect the changes */
+ ++ThisTable->Version;
+
+ DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
+
+ return ThisEntry;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxPrefixTableLookupName(
+ IN PRX_PREFIX_TABLE ThisTable,
+ IN PUNICODE_STRING CanonicalName,
+ OUT PUNICODE_STRING RemainingName,
+ IN PRX_CONNECTION_ID ConnectionId)
+{
+ PVOID Container;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
+ ASSERT(CanonicalName->Length > 0);
+
+ /* Call the internal helper */
+ Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
+ if (Container == NULL)
+ {
+ return NULL;
+ }
+
+ /* Reference our container before returning it */
+ if (RdbssReferenceTracingValue != 0)
+ {
+ NODE_TYPE_CODE Type;
+
+ Type = NodeType(Container);
+ switch (Type)
+ {
+ case RDBSS_NTC_SRVCALL:
+ RxReferenceSrvCall(Container);
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ RxReferenceNetRoot(Container);
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ RxReferenceVNetRoot(Container);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+ else
+ {
+ RxReference(Container);
+ }
+
+ return Container;
+}
+
+LONG
+RxpReferenceNetFcb(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+ return 0;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpReleasePrefixTableLock(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
+
+ DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
+
+ ExReleaseResourceLite(&pTable->TableLock);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxPrepareContextForReuse(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PAGED_CODE();
+
+ /* When we reach that point, make sure mandatory parts are null-ed */
+ if (RxContext->MajorFunction == IRP_MJ_CREATE)
+ {
+ ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
+ RxContext->Create.RdrFlags = 0;
+ }
+ else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
+ {
+ ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
+ ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
+ }
+
+ RxContext->ReferenceCount = 0;
+}
+
+VOID
+RxProcessFcbChangeBufferingStateRequest(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+}
+
+BOOLEAN
+RxpTrackDereference(
+ _In_ ULONG TraceType,
+ _In_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+VOID
+RxpTrackReference(
+ _In_ ULONG TraceType,
+ _In_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxpUndoScavengerFinalizationMarking(
+ PVOID Instance)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+RxPurgeFcbInSystemCache(
+ IN PFCB Fcb,
+ IN PLARGE_INTEGER FileOffset OPTIONAL,
+ IN ULONG Length,
+ IN BOOLEAN UninitializeCacheMaps,
+ IN BOOLEAN FlushFile)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpWorkerThreadDispatcher(
+ IN PRX_WORK_QUEUE WorkQueue,
+ IN PLARGE_INTEGER WaitInterval)
+{
+ NTSTATUS Status;
+ PVOID Parameter;
+ PETHREAD CurrentThread;
+ BOOLEAN KillThread, Dereference;
+ PRX_WORK_QUEUE_ITEM WorkQueueItem;
+ PWORKER_THREAD_ROUTINE WorkerRoutine;
+
+ InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
+
+ /* Reference ourselves */
+ CurrentThread = PsGetCurrentThread();
+ Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, PsThreadType, KernelMode);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Infinite loop for worker */
+ KillThread = FALSE;
+ Dereference = FALSE;
+ do
+ {
+ KIRQL OldIrql;
+ PLIST_ENTRY ListEntry;
+
+ /* Remove an entry from the work queue */
+ ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
+ if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
+ {
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
+
+ InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
+ InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+
+ /* Get the parameters, and null-them in the struct */
+ WorkerRoutine = WorkQueueItem->WorkerRoutine;
+ Parameter = WorkQueueItem->Parameter;
+ DeviceObject = WorkQueueItem->pDeviceObject;
+
+ WorkQueueItem->List.Flink = NULL;
+ WorkQueueItem->WorkerRoutine = NULL;
+ WorkQueueItem->Parameter = NULL;
+ WorkQueueItem->pDeviceObject = NULL;
+
+ /* Call the routine */
+ DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
+ WorkerRoutine(Parameter);
+
+ /* Are we going down now? */
+ if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
+ {
+ PKEVENT TearDownEvent;
+
+ TearDownEvent = InterlockedExchangePointer((volatile PVOID)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
+ if (TearDownEvent != NULL)
+ {
+ KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
+ }
+ }
+
+ InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+
+ /* Shall we shutdown... */
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ switch (WorkQueue->State)
+ {
+ /* Our queue is active, kill it if we have no more items to dispatch
+ * and more threads than the required minimum
+ */
+ case RxWorkQueueActive:
+ if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
+ {
+ ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
+ if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
+ {
+ KillThread = TRUE;
+ Dereference = TRUE;
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ }
+
+ if (KillThread)
+ {
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ }
+ break;
+
+ /* The queue is inactive: kill it we have more threads than the required minimum */
+ case RxWorkQueueInactive:
+ ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
+ if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
+ {
+ KillThread = TRUE;
+ Dereference = TRUE;
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ }
+
+ if (KillThread)
+ {
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ break;
+
+ /* Rundown in progress..., kill it for sure! */
+ case RxWorkQueueRundownInProgress:
+ {
+ PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
+
+ ASSERT(WorkQueue->pRundownContext != NULL);
+
+ RundownContext = WorkQueue->pRundownContext;
+ RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
+
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ KillThread = TRUE;
+ Dereference = FALSE;
+
+ if (WorkQueue->NumberOfActiveWorkerThreads == 0)
+ {
+ KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ break;
+
+ default:
+ break;
+ }
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+ } while (!KillThread);
+
+ DPRINT("Killed worker thread\n");
+
+ /* Do we have to dereference ourselves? */
+ if (Dereference)
+ {
+ ObDereferenceObject(CurrentThread);
+ }
+
+ /* Dump last executed routine */
+ if (DumpDispatchRoutine)
+ {
+ DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+VOID
+RxReference(
+ IN OUT PVOID Instance)
+{
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+
+ PAGED_CODE();
+
+ RxAcquireScavengerMutex();
+
+ /* We can only reference a few structs */
+ NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
+ ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
+ (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
+ (NodeType == RDBSS_NTC_FOBX));
+
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
+
+ /* And that's not implemented! (yay, we leak :-D) */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ case RDBSS_NTC_NETROOT:
+ case RDBSS_NTC_V_NETROOT:
+ case RDBSS_NTC_SRVOPEN:
+ case RDBSS_NTC_FOBX:
+ UNIMPLEMENTED;
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ RxpUndoScavengerFinalizationMarking(Instance);
+ RxReleaseScavengerMutex();
+}
+
+VOID
+NTAPI
+RxResumeBlockedOperations_Serially(
+ IN OUT PRX_CONTEXT RxContext,
+ IN OUT PLIST_ENTRY BlockingIoQ)
+{
+ PAGED_CODE();
+
+ RxAcquireSerializationMutex();
+
+ /* This can only happen on pipes */
+ if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ {
+ RxReleaseSerializationMutex();
+ return;
+ }
+
+ UNIMPLEMENTED;
+
+ RxReleaseSerializationMutex();
+}
+
+BOOLEAN
+RxScavengeRelatedFobxs(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOLEAN
+RxScavengeVNetRoots(
+ PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxSpinUpRequestsDispatcher(
+ PVOID Dispatcher)
+{
+ NTSTATUS Status;
+ PRX_DISPATCHER RxDispatcher;
+
+ Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, PsThreadType, KernelMode);
+ if (!NT_SUCCESS(Status))
+ {
+ PsTerminateSystemThread(STATUS_SUCCESS);
+ }
+
+ RxDispatcher = Dispatcher;
+
+ do
+ {
+ KIRQL OldIrql;
+ PLIST_ENTRY ListEntry;
+
+ Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
+ KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
+ ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
+
+ KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
+ if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
+ {
+ ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
+ }
+ else
+ {
+ ListEntry = &RxDispatcher->SpinUpRequests;
+ }
+ KeResetEvent(&RxDispatcher->SpinUpRequestsEvent);
+ KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
+
+ while (ListEntry != &RxDispatcher->SpinUpRequests)
+ {
+ PWORK_QUEUE_ITEM WorkItem;
+ PRX_WORK_QUEUE WorkQueue;
+
+ WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
+ WorkQueue = WorkItem->Parameter;
+
+ InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
+
+ DPRINT1("WORKQ:SR %lx %lx\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
+ WorkItem->WorkerRoutine(WorkItem->Parameter);
+ }
+ } while (RxDispatcher->State == RxDispatcherActive);
+
+ KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxSpinUpWorkerThread(
+ PRX_WORK_QUEUE WorkQueue,
+ PRX_WORKERTHREAD_ROUTINE Routine,
+ PVOID Parameter)
+{
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+
+ PAGED_CODE();
+
+ /* If work queue is inactive, that cannot work */
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ if (WorkQueue->State != RxWorkQueueActive)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
+ }
+ else
+ {
+ ++WorkQueue->NumberOfActiveWorkerThreads;
+ Status = STATUS_SUCCESS;
+ }
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+
+ /* Quit on failure */
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Spin up the worker thread */
+ Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
+ if (NT_SUCCESS(Status))
+ {
+ ZwClose(ThreadHandle);
+ return Status;
+ }
+ /* Read well: we reached that point because it failed! */
+ DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
+
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ --WorkQueue->NumberOfActiveWorkerThreads;
+ ++WorkQueue->NumberOfFailedSpinUpRequests;
+
+ /* Rundown, no more active threads, set the event! */
+ if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
+ WorkQueue->State == RxWorkQueueRundownInProgress)
+ {
+ KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
+
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+
+ return Status;
+}
+
+VOID
+RxSpinUpWorkerThreads(
+ PRX_WORK_QUEUE WorkQueue)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxSynchronizeWithScavenger(
+ IN PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+RxTableComputeHashValue(
+ IN PUNICODE_STRING Name)
+{
+ ULONG Hash;
+ SHORT Loops[8];
+ USHORT MaxChar, i;
+
+ PAGED_CODE();
+
+ MaxChar = Name->Length / sizeof(WCHAR);
+
+ Loops[0] = 1;
+ Loops[1] = MaxChar - 1;
+ Loops[2] = MaxChar - 2;
+ Loops[3] = MaxChar - 3;
+ Loops[4] = MaxChar - 4;
+ Loops[5] = MaxChar / 4;
+ Loops[6] = 2 * MaxChar / 4;
+ Loops[7] = 3 * MaxChar / 4;
+
+ Hash = 0;
+ for (i = 0; i < 8; ++i)
+ {
+ SHORT Idx;
+
+ Idx = Loops[i];
+ if (Idx >= 0 && Idx < MaxChar)
+ {
+ Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
+ }
+ }
+
+ return Hash;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+RxTableComputePathHashValue(
+ IN PUNICODE_STRING Name)
+{
+ ULONG Hash;
+ SHORT Loops[8];
+ USHORT MaxChar, i;
+
+ PAGED_CODE();
+
+ MaxChar = Name->Length / sizeof(WCHAR);
+
+ Loops[0] = 1;
+ Loops[1] = MaxChar - 1;
+ Loops[2] = MaxChar - 2;
+ Loops[3] = MaxChar - 3;
+ Loops[4] = MaxChar - 4;
+ Loops[5] = MaxChar / 4;
+ Loops[6] = 2 * MaxChar / 4;
+ Loops[7] = 3 * MaxChar / 4;
+
+ Hash = 0;
+ for (i = 0; i < 8; ++i)
+ {
+ SHORT Idx;
+
+ Idx = Loops[i];
+ if (Idx >= 0 && Idx < MaxChar)
+ {
+ Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
+ }
+ }
+
+ return Hash;
+}
+
+PVOID
+RxTableLookupName(
+ IN PRX_PREFIX_TABLE ThisTable,
+ IN PUNICODE_STRING Name,
+ OUT PUNICODE_STRING RemainingName,
+ IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
+{
+ PVOID Container;
+ USHORT i, MaxChar;
+ PRX_PREFIX_ENTRY Entry;
+ RX_CONNECTION_ID NullId;
+ UNICODE_STRING LookupString;
+
+ PAGED_CODE();
+
+ /* If caller didn't provide a connection ID, setup one */
+ if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
+ {
+ NullId.Luid.LowPart = 0;
+ NullId.Luid.HighPart = 0;
+ RxConnectionId = &NullId;
+ }
+
+ /* Validate name */
+ ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
+
+ Entry = NULL;
+ Container = NULL;
+ LookupString.Buffer = Name->Buffer;
+ MaxChar = Name->Length / sizeof(WCHAR);
+ /* We'll perform the lookup, path component after another */
+ for (i = 1; i < MaxChar; ++i)
+ {
+ ULONG Hash;
+ PRX_PREFIX_ENTRY CurEntry;
+
+ /* Don't cut in the middle of a path element */
+ if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
+ {
+ continue;
+ }
+
+ /* Perform lookup in the table */
+ LookupString.Length = i * sizeof(WCHAR);
+ Hash = RxTableComputeHashValue(&LookupString);
+ CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
+#if DBG
+ ++ThisTable->Lookups;
+#endif
+ /* Entry not found, move to the next component */
+ if (CurEntry == NULL)
+ {
+#if DBG
+ ++ThisTable->FailedLookups;
+#endif
+ continue;
+ }
+
+ Entry = CurEntry;
+ ASSERT(Entry->ContainingRecord != NULL);
+ Container = Entry->ContainingRecord;
+
+ /* Need to handle NetRoot specific case... */
+ if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
+ {
+ UNIMPLEMENTED;
+ break;
+ }
+ else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
+ {
+ break;
+ }
+ else
+ {
+ ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
+ }
+ }
+
+ /* Entry was found */
+ if (Entry != NULL)
+ {
+ DPRINT("Found\n");
+
+ ASSERT(Name->Length >= Entry->Prefix.Length);
+
+ /* Setup remaining name */
+ RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
+ RemainingName->Length = Name->Length - Entry->Prefix.Length;
+ RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
+ }
+ else
+ {
+ /* Otherwise, that's the whole name */
+ RemainingName = Name;
+ }
+
+ return Container;
+}
+
+/*
+ * @implemented
+ */
+PRX_PREFIX_ENTRY
+RxTableLookupName_ExactLengthMatch(
+ IN PRX_PREFIX_TABLE ThisTable,
+ IN PUNICODE_STRING Name,
+ IN ULONG HashValue,
+ IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
+{
+ PLIST_ENTRY ListEntry, HashBucket;
+
+ PAGED_CODE();
+
+ ASSERT(RxConnectionId != NULL);
+
+ /* Select the right bucket */
+ HashBucket = HASH_BUCKET(ThisTable, HashValue);
+ DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
+ /* If bucket is empty, no match */
+ if (IsListEmpty(HashBucket))
+ {
+ return NULL;
+ }
+
+ /* Browse all the entries in the bucket */
+ for (ListEntry = HashBucket->Flink;
+ ListEntry != HashBucket;
+ ListEntry = ListEntry->Flink)
+ {
+ PVOID Container;
+ PRX_PREFIX_ENTRY Entry;
+ BOOLEAN CaseInsensitive;
+ PUNICODE_STRING CmpName, CmpPrefix;
+ UNICODE_STRING InsensitiveName, InsensitivePrefix;
+
+ Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
+ ++ThisTable->Considers;
+ ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
+
+ Container = Entry->ContainingRecord;
+ ASSERT(Container != NULL);
+
+ /* Not the same hash, not the same length, move on */
+ if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
+ {
+ continue;
+ }
+
+ ++ThisTable->Compares;
+ /* If we have to perform a case insensitive compare on a portion... */
+ if (Entry->CaseInsensitiveLength != 0)
+ {
+ ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
+
+ /* Perform the case insensitive check on the asked length */
+ InsensitiveName.Buffer = Name->Buffer;
+ InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
+ InsensitiveName.Length = Entry->CaseInsensitiveLength;
+ InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
+ /* No match, move to the next entry */
+ if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
+ {
+ continue;
+ }
+
+ /* Was the case insensitive covering the whole name? */
+ if (Name->Length == Entry->CaseInsensitiveLength)
+ {
+ /* If connection ID also matches, that a complete match! */
+ if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
+ {
+ return Entry;
+ }
+ }
+
+ /* Otherwise, we have to continue with the sensitive match.... */
+ InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
+ InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
+ InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
+ InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
+
+ CmpName = &InsensitiveName;
+ CmpPrefix = &InsensitivePrefix;
+ CaseInsensitive = FALSE;
+ }
+ else
+ {
+ CmpName = Name;
+ CmpPrefix = &Entry->Prefix;
+ CaseInsensitive = ThisTable->CaseInsensitiveMatch;
+ }
+
+ /* Perform the compare, if there's a match, also check for connection ID */
+ if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
+ {
+ if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
+ {
+ return Entry;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+VOID
+RxTrackerUpdateHistory(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb,
+ _In_ ULONG Operation,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+RxTrackPagingIoResource(
+ _Inout_ PVOID Instance,
+ _In_ ULONG Type,
+ _In_ ULONG Line,
+ _In_ PCSTR File)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxUninitializeVNetRootParameters(
+ IN PUNICODE_STRING UserName,
+ IN PUNICODE_STRING UserDomainName,
+ IN PUNICODE_STRING Password,
+ OUT PULONG Flags)
+{
+ PAGED_CODE();
+
+ /* Only free what could have been allocated */
+ if (UserName != NULL)
+ {
+ ExFreePool(UserName);
+ }
+
+ if (UserDomainName != NULL)
+ {
+ ExFreePool(UserDomainName);
+ }
+
+ if (Password != NULL)
+ {
+ ExFreePool(Password);
+ }
+
+ /* And remove the possibly set CSC agent flag */
+ if (Flags != NULL)
+ {
+ (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxUpdateCondition(
+ IN RX_BLOCK_CONDITION NewConditionValue,
+ OUT PRX_BLOCK_CONDITION Condition,
+ IN OUT PLIST_ENTRY TransitionWaitList)
+{
+ PRX_CONTEXT Context;
+ LIST_ENTRY SerializationQueue;
+
+ PAGED_CODE();
+
+ DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
+
+ /* Set the new condition */
+ RxAcquireSerializationMutex();
+ ASSERT(NewConditionValue != Condition_InTransition);
+ *Condition = NewConditionValue;
+ /* And get the serialization queue for treatment */
+ RxTransferList(&SerializationQueue, TransitionWaitList);
+ RxReleaseSerializationMutex();
+
+ /* Handle the serialization queue */
+ Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
+ while (Context != NULL)
+ {
+ /* If the caller asked for post, post the request */
+ if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
+ {
+ Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
+ RxFsdPostRequest(Context);
+ }
+ /* Otherwise, wake up sleeping waiters */
+ else
+ {
+ RxSignalSynchronousWaiter(Context);
+ }
+
+ Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
+ }
+}
+
+VOID
+RxVerifyOperationIsLegal(
+ IN PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxWaitForStableCondition(
+ IN PRX_BLOCK_CONDITION Condition,
+ IN OUT PLIST_ENTRY TransitionWaitList,
+ IN OUT PRX_CONTEXT RxContext,
+ OUT NTSTATUS *AsyncStatus OPTIONAL)
+{
+ BOOLEAN Wait;
+ NTSTATUS LocalStatus;
+
+ PAGED_CODE();
+
+ /* Make sure to always get status */
+ if (AsyncStatus == NULL)
+ {
+ AsyncStatus = &LocalStatus;
+ }
+
+ /* By default, it's a success */
+ *AsyncStatus = STATUS_SUCCESS;
+
+ Wait = FALSE;
+ /* If it's not stable, we've to wait */
+ if (!StableCondition(*Condition))
+ {
+ /* Lock the mutex */
+ RxAcquireSerializationMutex();
+ /* Still not stable? */
+ if (!StableCondition(*Condition))
+ {
+ /* Insert us in the wait list for processing on stable condition */
+ RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
+
+ /* If we're asked to post on stable, don't wait, and just return pending */
+ if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
+ {
+ *AsyncStatus = STATUS_PENDING;
+ }
+ else
+ {
+ Wait = TRUE;
+ }
+ }
+ RxReleaseSerializationMutex();
+
+ /* We don't post on stable, so, just wait... */
+ if (Wait)
+ {
+ RxWaitSync(RxContext);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxWorkItemDispatcher(
+ PVOID Context)
+{
+ PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
+
+ DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
+
+ DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
+
+ ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
+}
+
+NTSTATUS
+__RxAcquireFcb(
+ _Inout_ PFCB Fcb,
+ _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
+ _In_ ULONG Mode
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
+
+ PAGED_CODE();
+
+ DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
+
+ SpecialContext = FALSE;
+ ContextIsPresent = FALSE;
+ /* Check for special context */
+ if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
+ {
+ SpecialContext = TRUE;
+ }
+
+ /* We don't handle buffering state change yet... */
+ if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
+ BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Nor special contexts */
+ if (SpecialContext)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Nor missing contexts... */
+ if (RxContext == NULL)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* That said: we have a real context! */
+ ContextIsPresent = TRUE;
+
+ /* If we've been cancelled in between, give up */
+ Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Can we wait? */
+ CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+
+ while (TRUE)
+ {
+ /* Assume we cannot lock */
+ Status = STATUS_LOCK_NOT_GRANTED;
+
+ /* Lock according to what the caller asked */
+ switch (Mode)
+ {
+ case FCB_MODE_EXCLUSIVE:
+ Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
+ break;
+
+ case FCB_MODE_SHARED:
+ Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
+ break;
+
+ case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
+ Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
+ break;
+
+ default:
+ ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
+ Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
+ break;
+ }
+
+ /* Lock granted! */
+ if (Acquired)
+ {
+ Status = STATUS_SUCCESS;
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ /* Handle paging write - not implemented */
+ if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
+ {
+ UNIMPLEMENTED;
+ }
+ }
+
+ /* And break, that cool! */
+ if (Acquired)
+ {
+ break;
+ }
+
+ /* If it failed, return immediately */
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+
+ /* If we don't have to check for valid operation, job done, nothing more to do */
+ if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
+ {
+ if (NT_SUCCESS(Status))
+ {
+ RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
+ }
+
+ return Status;
+ }
+
+ /* Verify operation */
+ _SEH2_TRY
+ {
+ RxVerifyOperationIsLegal(RxContext);
+ }
+ _SEH2_FINALLY
+ {
+ /* If it failed, release lock and fail */
+ if (_SEH2_AbnormalTermination())
+ {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ Status = STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+ _SEH2_END;
+
+ if (NT_SUCCESS(Status))
+ {
+ RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
+ }
+
+ DPRINT("Status: %x\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+__RxItsTheSameContext(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ ULONG CapturedRxContextSerialNumber,
+ _In_ ULONG Line,
+ _In_ PCSTR File)
+{
+ /* Check we have a context with the same serial number */
+ if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
+ RxContext->SerialNumber != CapturedRxContextSerialNumber)
+ {
+ /* Just be noisy */
+ DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
+ }
+}
+
+VOID
+__RxReleaseFcb(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ )
+{
+ BOOLEAN IsExclusive, BufferingPending;
+
+ RxAcquireSerializationMutex();
+
+ BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
+ IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+
+ /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
+ * then just release the FCB
+ */
+ if (!BufferingPending || !IsExclusive)
+ {
+ RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
+ LineNumber, FileName, SerialNumber);
+ ExReleaseResourceLite(MrxFcb->Header.Resource);
+ }
+
+ RxReleaseSerializationMutex();
+
+ /* And finally leave */
+ if (!BufferingPending || !IsExclusive)
+ {
+ return;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
+
+ /* Otherwise, handle buffering state and release */
+ RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
+
+ RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
+ ExReleaseResourceLite(MrxFcb->Header.Resource);
+}
+
+VOID
+__RxReleaseFcbForThread(
+ _Inout_opt_ PRX_CONTEXT RxContext,
+ _Inout_ PMRX_FCB MrxFcb,
+ _In_ ERESOURCE_THREAD ResourceThreadId
+#ifdef RDBSS_TRACKER
+ ,
+ _In_ ULONG LineNumber,
+ _In_ PCSTR FileName,
+ _In_ ULONG SerialNumber
+#endif
+ )
+{
+ BOOLEAN IsExclusive, BufferingPending;
+
+ RxAcquireSerializationMutex();
+
+ BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
+ IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+
+ /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
+ * then just release the FCB
+ */
+ if (!BufferingPending || !IsExclusive)
+ {
+ RxTrackerUpdateHistory(RxContext, MrxFcb,
+ (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
+ LineNumber, FileName, SerialNumber);
+ ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
+ }
+
+ RxReleaseSerializationMutex();
+
+ /* And finally leave */
+ if (!BufferingPending || !IsExclusive)
+ {
+ return;
+ }
+
+ /* Otherwise, handle buffering state and release */
+ RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
+ RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
+ ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
+}