[RDBSS]
authorPierre Schweitzer <pierre@reactos.org>
Fri, 26 May 2017 20:52:18 +0000 (20:52 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Fri, 26 May 2017 20:52:18 +0000 (20:52 +0000)
[RXCE]
[DDK]
Add an initial implementation of the RXCE and RDBSS libraries that are used to implement mini-redirectors
The associated headers are also added to DDK

The implementation is partial (really!) and is only working for read-only operations.

It leaks memory as hell (no refcounting implemented) and thus, objects freeing is not implemented.

It was tested with NFS41 driver. With such RDBSS, it's possible for the driver to mount a remote share, to list
files, to query their properties, to query volume properties, and finally to read files (with some corruption under
specific conditions).

Please refrain from committing in this (especially for modifying whitespaces or fixing comments...), this is still WIP
and under development, it would mess with my local changes!

In itself, it doesn't bring anything to ReactOS yet, as no mini redirector is available in ReactOS source tree.
This may come later on with NFS41.

More to follow...

CORE-11327

svn path=/trunk/; revision=74674

28 files changed:
reactos/sdk/include/ddk/backpack.h [new file with mode: 0644]
reactos/sdk/include/ddk/buffring.h [new file with mode: 0644]
reactos/sdk/include/ddk/fcb.h [new file with mode: 0644]
reactos/sdk/include/ddk/fcbtable.h [new file with mode: 0644]
reactos/sdk/include/ddk/lowio.h [new file with mode: 0644]
reactos/sdk/include/ddk/mrx.h [new file with mode: 0644]
reactos/sdk/include/ddk/mrxfcb.h [new file with mode: 0644]
reactos/sdk/include/ddk/nodetype.h [new file with mode: 0644]
reactos/sdk/include/ddk/ntrxdef.h [new file with mode: 0644]
reactos/sdk/include/ddk/prefix.h [new file with mode: 0644]
reactos/sdk/include/ddk/rx.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxcontx.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxdata.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxlog.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxovride.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxpooltg.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxprocs.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxstruc.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxtimer.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxtypes.h [new file with mode: 0644]
reactos/sdk/include/ddk/rxworkq.h [new file with mode: 0644]
reactos/sdk/include/ddk/scavengr.h [new file with mode: 0644]
reactos/sdk/include/ddk/struchdr.h [new file with mode: 0644]
reactos/sdk/lib/drivers/CMakeLists.txt
reactos/sdk/lib/drivers/rdbsslib/CMakeLists.txt [new file with mode: 0644]
reactos/sdk/lib/drivers/rdbsslib/rdbss.c [new file with mode: 0644]
reactos/sdk/lib/drivers/rxce/CMakeLists.txt [new file with mode: 0644]
reactos/sdk/lib/drivers/rxce/rxce.c [new file with mode: 0644]

diff --git a/reactos/sdk/include/ddk/backpack.h b/reactos/sdk/include/ddk/backpack.h
new file mode 100644 (file)
index 0000000..77ec8ee
--- /dev/null
@@ -0,0 +1,23 @@
+#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
diff --git a/reactos/sdk/include/ddk/buffring.h b/reactos/sdk/include/ddk/buffring.h
new file mode 100644 (file)
index 0000000..be4e80e
--- /dev/null
@@ -0,0 +1,49 @@
+#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
diff --git a/reactos/sdk/include/ddk/fcb.h b/reactos/sdk/include/ddk/fcb.h
new file mode 100644 (file)
index 0000000..bfc6a64
--- /dev/null
@@ -0,0 +1,596 @@
+#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
diff --git a/reactos/sdk/include/ddk/fcbtable.h b/reactos/sdk/include/ddk/fcbtable.h
new file mode 100644 (file)
index 0000000..331b75a
--- /dev/null
@@ -0,0 +1,60 @@
+#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
diff --git a/reactos/sdk/include/ddk/lowio.h b/reactos/sdk/include/ddk/lowio.h
new file mode 100644 (file)
index 0000000..0c82a9f
--- /dev/null
@@ -0,0 +1,76 @@
+#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
diff --git a/reactos/sdk/include/ddk/mrx.h b/reactos/sdk/include/ddk/mrx.h
new file mode 100644 (file)
index 0000000..e6bb83e
--- /dev/null
@@ -0,0 +1,395 @@
+#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
diff --git a/reactos/sdk/include/ddk/mrxfcb.h b/reactos/sdk/include/ddk/mrxfcb.h
new file mode 100644 (file)
index 0000000..38f500c
--- /dev/null
@@ -0,0 +1,211 @@
+#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
diff --git a/reactos/sdk/include/ddk/nodetype.h b/reactos/sdk/include/ddk/nodetype.h
new file mode 100644 (file)
index 0000000..48f733f
--- /dev/null
@@ -0,0 +1,85 @@
+#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
diff --git a/reactos/sdk/include/ddk/ntrxdef.h b/reactos/sdk/include/ddk/ntrxdef.h
new file mode 100644 (file)
index 0000000..424bdf8
--- /dev/null
@@ -0,0 +1,28 @@
+#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
diff --git a/reactos/sdk/include/ddk/prefix.h b/reactos/sdk/include/ddk/prefix.h
new file mode 100644 (file)
index 0000000..c6de616
--- /dev/null
@@ -0,0 +1,111 @@
+#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
diff --git a/reactos/sdk/include/ddk/rx.h b/reactos/sdk/include/ddk/rx.h
new file mode 100644 (file)
index 0000000..f73fc85
--- /dev/null
@@ -0,0 +1,46 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxcontx.h b/reactos/sdk/include/ddk/rxcontx.h
new file mode 100644 (file)
index 0000000..297efc0
--- /dev/null
@@ -0,0 +1,475 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxdata.h b/reactos/sdk/include/ddk/rxdata.h
new file mode 100644 (file)
index 0000000..410d11c
--- /dev/null
@@ -0,0 +1,20 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxlog.h b/reactos/sdk/include/ddk/rxlog.h
new file mode 100644 (file)
index 0000000..41ed336
--- /dev/null
@@ -0,0 +1,36 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxovride.h b/reactos/sdk/include/ddk/rxovride.h
new file mode 100644 (file)
index 0000000..5b5352d
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef NO_RXOVRIDE_GLOBAL
+#include <struchdr.h>
+#endif
diff --git a/reactos/sdk/include/ddk/rxpooltg.h b/reactos/sdk/include/ddk/rxpooltg.h
new file mode 100644 (file)
index 0000000..d76f78a
--- /dev/null
@@ -0,0 +1,13 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxprocs.h b/reactos/sdk/include/ddk/rxprocs.h
new file mode 100644 (file)
index 0000000..7038d98
--- /dev/null
@@ -0,0 +1,679 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxstruc.h b/reactos/sdk/include/ddk/rxstruc.h
new file mode 100644 (file)
index 0000000..b7c1ae9
--- /dev/null
@@ -0,0 +1,151 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxtimer.h b/reactos/sdk/include/ddk/rxtimer.h
new file mode 100644 (file)
index 0000000..42b9767
--- /dev/null
@@ -0,0 +1,16 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxtypes.h b/reactos/sdk/include/ddk/rxtypes.h
new file mode 100644 (file)
index 0000000..ff67ff5
--- /dev/null
@@ -0,0 +1,11 @@
+#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
diff --git a/reactos/sdk/include/ddk/rxworkq.h b/reactos/sdk/include/ddk/rxworkq.h
new file mode 100644 (file)
index 0000000..a0bd092
--- /dev/null
@@ -0,0 +1,100 @@
+#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
diff --git a/reactos/sdk/include/ddk/scavengr.h b/reactos/sdk/include/ddk/scavengr.h
new file mode 100644 (file)
index 0000000..04d1569
--- /dev/null
@@ -0,0 +1,138 @@
+#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
diff --git a/reactos/sdk/include/ddk/struchdr.h b/reactos/sdk/include/ddk/struchdr.h
new file mode 100644 (file)
index 0000000..8e458f2
--- /dev/null
@@ -0,0 +1,21 @@
+#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
index 0c69fee..9ab9eb3 100644 (file)
@@ -6,5 +6,7 @@ add_subdirectory(ip)
 add_subdirectory(libusb)
 add_subdirectory(lwip)
 add_subdirectory(ntoskrnl_vista)
+add_subdirectory(rdbsslib)
 add_subdirectory(rtlver)
+add_subdirectory(rxce)
 add_subdirectory(sound)
diff --git a/reactos/sdk/lib/drivers/rdbsslib/CMakeLists.txt b/reactos/sdk/lib/drivers/rdbsslib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7285c3a
--- /dev/null
@@ -0,0 +1,10 @@
+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)
diff --git a/reactos/sdk/lib/drivers/rdbsslib/rdbss.c b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c
new file mode 100644 (file)
index 0000000..fffce15
--- /dev/null
@@ -0,0 +1,6235 @@
+/*
+ *  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;
+}
diff --git a/reactos/sdk/lib/drivers/rxce/CMakeLists.txt b/reactos/sdk/lib/drivers/rxce/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f16df07
--- /dev/null
@@ -0,0 +1,10 @@
+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)
diff --git a/reactos/sdk/lib/drivers/rxce/rxce.c b/reactos/sdk/lib/drivers/rxce/rxce.c
new file mode 100644 (file)
index 0000000..9cffb08
--- /dev/null
@@ -0,0 +1,5668 @@
+/*
+ *  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);
+}