diff --git a/reactos/sdk/include/ddk/backpack.h b/reactos/sdk/include/ddk/backpack.h new file mode 100644 index 00000000000..77ec8eea201 --- /dev/null +++ b/reactos/sdk/include/ddk/backpack.h @@ -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 index 00000000000..be4e80e1ad9 --- /dev/null +++ b/reactos/sdk/include/ddk/buffring.h @@ -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 index 00000000000..bfc6a64adb3 --- /dev/null +++ b/reactos/sdk/include/ddk/fcb.h @@ -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 index 00000000000..331b75a25d3 --- /dev/null +++ b/reactos/sdk/include/ddk/fcbtable.h @@ -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 index 00000000000..0c82a9f928a --- /dev/null +++ b/reactos/sdk/include/ddk/lowio.h @@ -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 index 00000000000..e6bb83ecd38 --- /dev/null +++ b/reactos/sdk/include/ddk/mrx.h @@ -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 index 00000000000..38f500cf859 --- /dev/null +++ b/reactos/sdk/include/ddk/mrxfcb.h @@ -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 index 00000000000..48f733fa986 --- /dev/null +++ b/reactos/sdk/include/ddk/nodetype.h @@ -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 index 00000000000..424bdf8af60 --- /dev/null +++ b/reactos/sdk/include/ddk/ntrxdef.h @@ -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 index 00000000000..c6de616b4a4 --- /dev/null +++ b/reactos/sdk/include/ddk/prefix.h @@ -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 index 00000000000..f73fc8515a3 --- /dev/null +++ b/reactos/sdk/include/ddk/rx.h @@ -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 index 00000000000..297efc06440 --- /dev/null +++ b/reactos/sdk/include/ddk/rxcontx.h @@ -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 index 00000000000..410d11cf164 --- /dev/null +++ b/reactos/sdk/include/ddk/rxdata.h @@ -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 index 00000000000..41ed3368955 --- /dev/null +++ b/reactos/sdk/include/ddk/rxlog.h @@ -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 index 00000000000..5b5352dff1c --- /dev/null +++ b/reactos/sdk/include/ddk/rxovride.h @@ -0,0 +1,3 @@ +#ifndef NO_RXOVRIDE_GLOBAL +#include +#endif diff --git a/reactos/sdk/include/ddk/rxpooltg.h b/reactos/sdk/include/ddk/rxpooltg.h new file mode 100644 index 00000000000..d76f78a86f6 --- /dev/null +++ b/reactos/sdk/include/ddk/rxpooltg.h @@ -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 index 00000000000..7038d98f7b4 --- /dev/null +++ b/reactos/sdk/include/ddk/rxprocs.h @@ -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 index 00000000000..b7c1ae933fb --- /dev/null +++ b/reactos/sdk/include/ddk/rxstruc.h @@ -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 index 00000000000..42b97673aec --- /dev/null +++ b/reactos/sdk/include/ddk/rxtimer.h @@ -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 index 00000000000..ff67ff5992a --- /dev/null +++ b/reactos/sdk/include/ddk/rxtypes.h @@ -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 index 00000000000..a0bd092632d --- /dev/null +++ b/reactos/sdk/include/ddk/rxworkq.h @@ -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 index 00000000000..04d156919f7 --- /dev/null +++ b/reactos/sdk/include/ddk/scavengr.h @@ -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 index 00000000000..8e458f22378 --- /dev/null +++ b/reactos/sdk/include/ddk/struchdr.h @@ -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 diff --git a/reactos/sdk/lib/drivers/CMakeLists.txt b/reactos/sdk/lib/drivers/CMakeLists.txt index 0c69feed4ed..9ab9eb37a4b 100644 --- a/reactos/sdk/lib/drivers/CMakeLists.txt +++ b/reactos/sdk/lib/drivers/CMakeLists.txt @@ -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 index 00000000000..7285c3a3c1f --- /dev/null +++ b/reactos/sdk/lib/drivers/rdbsslib/CMakeLists.txt @@ -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 index 00000000000..fffce15802c --- /dev/null +++ b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c @@ -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 +#include +#include +#include + +#define NDEBUG +#include + +#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 index 00000000000..f16df079569 --- /dev/null +++ b/reactos/sdk/lib/drivers/rxce/CMakeLists.txt @@ -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 index 00000000000..9cffb083ddf --- /dev/null +++ b/reactos/sdk/lib/drivers/rxce/rxce.c @@ -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 +#include +#include + +#define NDEBUG +#include + +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); +}