3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_DISPATCH_ITEM DispatchItem
);
65 PRX_CONTEXT RxContext
);
74 _RxAllocatePoolWithTag(
75 _In_ POOL_TYPE PoolType
,
76 _In_ SIZE_T NumberOfBytes
,
90 extern ULONG ReadAheadGranularity
;
92 volatile LONG RxNumberOfActiveFcbs
= 0;
93 ULONG SerialNumber
= 1;
95 volatile ULONG RxContextSerialNumberCounter
;
96 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
97 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
98 LIST_ENTRY RxSrvCalldownList
;
99 RX_SPIN_LOCK RxStrucSupSpinLock
;
100 ULONG RdbssReferenceTracingValue
;
101 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
102 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
103 RX_DISPATCHER RxDispatcher
;
104 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
105 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
106 BOOLEAN RxContinueFromAssert
= TRUE
;
107 ULONG RxExplodePoolTags
= 1;
109 BOOLEAN DumpDispatchRoutine
= TRUE
;
111 BOOLEAN DumpDispatchRoutine
= FALSE
;
119 #define ASSERT(exp) \
122 RxAssert(#exp, __FILE__, __LINE__, NULL); \
127 #undef RxAllocatePool
128 #undef RxAllocatePoolWithTag
131 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
132 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
133 #define RxFreePool _RxFreePool
134 #define RxFreePoolWithTag _RxFreePoolWithTag
137 /* FUNCTIONS ****************************************************************/
143 RxAddVirtualNetRootToNetRoot(
145 PV_NET_ROOT VNetRoot
)
149 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
151 /* Insert in the VNetRoot list - make sure lock is held */
152 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
154 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
155 ++NetRoot
->NumberOfVirtualNetRoots
;
156 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
164 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
165 NODE_TYPE_CODE NodeType
,
168 PVOID AlreadyAllocatedObject
)
173 PVOID Buffer
, PAPNBuffer
;
174 PNON_PAGED_FCB NonPagedFcb
;
175 PMINIRDR_DISPATCH Dispatch
;
176 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
180 Dispatch
= RxDeviceObject
->Dispatch
;
193 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
194 if (NodeType
== RDBSS_NTC_FOBX
)
196 FobxSize
= sizeof(FOBX
);
197 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
199 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
202 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
203 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
205 SrvOpenSize
= sizeof(SRV_OPEN
);
206 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
208 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
211 FobxSize
= sizeof(FOBX
);
212 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
214 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
217 /* Otherwise, we're asked to allocate a FCB */
220 /* So, allocate the FCB and its extension if asked */
221 FcbSize
= sizeof(FCB
);
222 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
224 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
227 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
228 * Otherwise, it will be allocated later on, specifically
230 if (PoolType
== NonPagedPool
)
232 NonPagedSize
= sizeof(NON_PAGED_FCB
);
235 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
236 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
238 SrvOpenSize
= sizeof(SRV_OPEN
);
239 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
241 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
244 FobxSize
= sizeof(FOBX
);
245 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
247 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
252 /* If we already have a buffer, go ahead */
253 if (AlreadyAllocatedObject
!= NULL
)
255 Buffer
= AlreadyAllocatedObject
;
257 /* Otherwise, allocate it */
260 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
267 /* Now, get the pointers - FOBX is easy */
268 if (NodeType
== RDBSS_NTC_FOBX
)
272 /* SRV_OPEN first, FOBX next */
273 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
276 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
278 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
284 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
286 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
288 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
289 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
292 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
293 if (PoolType
!= NonPagedPool
)
295 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
296 if (NonPagedFcb
== NULL
)
298 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
302 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
304 /* Otherwise, just point at the right place in what has been allocated previously */
307 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
308 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
312 /* If we have allocated a SRV_OPEN, initialize it */
315 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
317 if (NodeType
== RDBSS_NTC_SRVOPEN
)
319 SrvOpen
->InternalFobx
= Fobx
;
323 SrvOpen
->InternalFobx
= NULL
;
324 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
327 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
329 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
332 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
335 /* If we have allocated a FOBX, initialize it */
338 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
340 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
342 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
346 /* If we have allocated a FCB, initialize it */
349 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
351 Fcb
->NonPaged
= NonPagedFcb
;
352 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
353 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
354 NonPagedFcb
->FcbBackPointer
= Fcb
;
356 Fcb
->InternalSrvOpen
= SrvOpen
;
357 Fcb
->InternalFobx
= Fobx
;
359 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
360 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
361 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
363 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
365 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
368 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
370 InterlockedIncrement(&RxNumberOfActiveFcbs
);
371 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
373 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
374 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
385 NODE_TYPE_CODE NodeType
,
386 PMINIRDR_DISPATCH MRxDispatch
,
389 ULONG Tag
, ObjectSize
;
390 PVOID Object
, *Extension
;
391 PRX_PREFIX_ENTRY PrefixEntry
;
392 USHORT StructSize
, ExtensionSize
;
396 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
400 case RDBSS_NTC_SRVCALL
:
401 Tag
= RX_SRVCALL_POOLTAG
;
402 StructSize
= sizeof(SRV_CALL
);
403 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
405 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
409 case RDBSS_NTC_NETROOT
:
410 Tag
= RX_NETROOT_POOLTAG
;
411 StructSize
= sizeof(NET_ROOT
);
412 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
414 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
418 case RDBSS_NTC_V_NETROOT
:
419 Tag
= RX_V_NETROOT_POOLTAG
;
420 StructSize
= sizeof(V_NET_ROOT
);
421 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
423 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
432 /* Now, allocate the object */
433 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
434 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
440 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
442 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
445 case RDBSS_NTC_SRVCALL
:
446 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
447 Extension
= &((PSRV_CALL
)Object
)->Context
;
448 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
451 case RDBSS_NTC_NETROOT
:
452 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
453 Extension
= &((PNET_ROOT
)Object
)->Context
;
454 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
457 case RDBSS_NTC_V_NETROOT
:
458 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
459 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
467 /* Set the prefix table unicode string */
468 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
469 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
470 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
471 PrefixEntry
->Prefix
.Length
= NameLength
;
472 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
473 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
475 /* Return the extension if we are asked to manage it */
476 if (ExtensionSize
!= 0)
478 *Extension
= Add2Ptr(Object
, StructSize
);
497 /* If we're not asked to continue, just stop the system */
498 if (!RxContinueFromAssert
)
500 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
503 /* Otherwise, capture context to offer the user to dump it */
504 RtlCaptureContext(&Context
);
506 /* Loop until the user hits 'i' */
509 /* If no file provided, use empty name */
515 /* If no message provided, use empty one */
521 /* Display the message */
522 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
523 /* And ask the user */
524 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
525 /* If he asks for ignore, quit
526 * In case of invalid input, ask again
528 if (Response
[0] != 'B' && Response
[0] != 'b')
530 if (Response
[0] == 'I' || Response
[0] == 'i')
538 /* Break: offer the user to dump the context and break */
539 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
542 /* Continue looping, so that after dump, execution can continue (with ignore) */
551 RxBootstrapWorkerThreadDispatcher(
554 PRX_WORK_QUEUE RxWorkQueue
;
558 RxWorkQueue
= WorkQueue
;
559 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
563 RxCheckVNetRootCredentials(
564 PRX_CONTEXT RxContext
,
565 PV_NET_ROOT VNetRoot
,
567 PUNICODE_STRING UserName
,
568 PUNICODE_STRING UserDomain
,
569 PUNICODE_STRING Password
,
574 /* If that's a UNC name, there's nothing to process */
575 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
576 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
579 return STATUS_MORE_PROCESSING_REQUIRED
;
582 /* Compare the logon ID in the VNetRoot with the one provided */
583 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
585 return STATUS_MORE_PROCESSING_REQUIRED
;
588 /* No credential provided? That's OK */
589 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
591 return STATUS_SUCCESS
;
596 return STATUS_NOT_IMPLEMENTED
;
608 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
610 ASSERT(Context
!= NULL
);
611 ASSERT(Context
->CurrentIrp
!= NULL
);
612 Irp
= Context
->CurrentIrp
;
614 /* Debug what the caller asks for */
615 if (Context
->LoudCompletionString
!= NULL
)
617 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
618 /* Does the user asks to stop on failed completion */
619 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
621 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
625 /* Complete for real */
626 Context
->CurrentIrp
= NULL
;
627 RxCompleteRequest_Real(Context
, Irp
, Status
);
629 DPRINT("Status: %lx\n", Status
);
637 RxCompleteRequest_Real(
638 IN PRX_CONTEXT RxContext
,
644 PIO_STACK_LOCATION Stack
;
646 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
648 /* Nothing to complete, just free context */
651 DPRINT("NULL IRP for %p\n", RxContext
);
652 if (RxContext
!= NULL
)
654 RxDereferenceAndDeleteRxContext_Real(RxContext
);
660 /* Remove cancel routine */
661 IoAcquireCancelSpinLock(&OldIrql
);
662 IoSetCancelRoutine(Irp
, NULL
);
663 IoReleaseCancelSpinLock(OldIrql
);
665 /* Select the boost, given the success/paging operation */
666 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
668 Boost
= IO_DISK_INCREMENT
;
672 Irp
->IoStatus
.Information
= 0;
673 Boost
= IO_NO_INCREMENT
;
675 Irp
->IoStatus
.Status
= Status
;
677 if (RxContext
!= NULL
)
679 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
680 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
682 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
683 RxContext
->MinorFunction
, RxContext
, Irp
,
684 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
688 /* If that's an opening, there might be a canonical name allocated,
689 * if completion isn't pending, release it
691 Stack
= IoGetCurrentIrpStackLocation(Irp
);
692 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
695 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
697 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
700 RxpPrepareCreateContextForReuse(RxContext
);
701 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
704 /* If it's a write, validate the correct behavior of the operation */
705 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
707 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
709 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
713 /* If it's pending, make sure IRP is marked as such */
714 if (RxContext
!= NULL
)
716 if (RxContext
->PendingReturned
)
718 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
723 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
724 IoCompleteRequest(Irp
, Boost
);
726 /* If there's a context, dereference it */
727 if (RxContext
!= NULL
)
729 RxDereferenceAndDeleteRxContext_Real(RxContext
);
734 RxCompleteSrvOpenKeyAssociation(
735 IN OUT PSRV_OPEN SrvOpen
)
745 IN PRX_CONTEXT RxContext
,
746 IN PSRV_CALL SrvCall
,
747 IN PNET_ROOT NetRoot
,
748 IN PV_NET_ROOT VirtualNetRoot
,
749 OUT PLOCK_HOLDING_STATE LockHoldingState
)
752 PRX_PREFIX_TABLE PrefixTable
;
753 PMRX_CREATENETROOT_CONTEXT Context
;
754 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
758 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
759 VirtualNetRoot
, LockHoldingState
);
761 /* Validate the lock is exclusively held */
762 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
763 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
765 /* Allocate the context */
766 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
769 return STATUS_INSUFFICIENT_RESOURCES
;
772 /* We can release lock now */
773 RxReleasePrefixTableLock(PrefixTable
);
774 *LockHoldingState
= LHS_LockNotHeld
;
776 RootCondition
= Condition_Bad
;
777 VRootCondition
= Condition_Bad
;
779 /* Initialize the context */
780 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
781 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
782 Context
->RxContext
= RxContext
;
783 Context
->pVNetRoot
= VirtualNetRoot
;
784 Context
->Callback
= RxCreateNetRootCallBack
;
786 /* And call the mini-rdr */
787 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
788 if (Status
== STATUS_PENDING
)
790 /* Wait for the mini-rdr to be done */
791 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
792 /* Update the structures condition according to mini-rdr return */
793 if (NT_SUCCESS(Context
->NetRootStatus
))
795 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
797 RootCondition
= Condition_Good
;
798 VRootCondition
= Condition_Good
;
799 Status
= STATUS_SUCCESS
;
803 RootCondition
= Condition_Good
;
804 Status
= Context
->VirtualNetRootStatus
;
809 Status
= Context
->VirtualNetRootStatus
;
810 if (NT_SUCCESS(Status
))
812 Status
= Context
->NetRootStatus
;
818 /* It has to return STATUS_PENDING! */
822 /* Acquire lock again - for caller lock status will remain unchanged */
823 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
824 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
825 *LockHoldingState
= LHS_ExclusiveLockHeld
;
827 /* Do the transition to the condition got from mini-rdr */
828 RxTransitionNetRoot(NetRoot
, RootCondition
);
829 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
831 /* Context is not longer needed */
832 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
834 DPRINT("Status: %x\n", Status
);
844 IN PRX_CONTEXT RxContext
,
845 IN PSRV_CALL SrvCall
,
846 OUT PLOCK_HOLDING_STATE LockHoldingState
)
849 PRX_PREFIX_TABLE PrefixTable
;
850 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
851 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
852 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
856 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
858 /* Validate the lock is exclusively held */
859 RxDeviceObject
= RxContext
->RxDeviceObject
;
860 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
861 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
863 /* Allocate the context for mini-rdr */
864 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
865 if (Calldown
== NULL
)
867 SrvCall
->Context
= NULL
;
868 SrvCall
->Condition
= Condition_Bad
;
869 RxReleasePrefixTableLock(PrefixTable
);
870 *LockHoldingState
= LHS_LockNotHeld
;
871 return STATUS_INSUFFICIENT_RESOURCES
;
875 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
877 SrvCall
->Context
= NULL
;
878 SrvCall
->Condition
= Condition_InTransition
;
880 RxReleasePrefixTableLock(PrefixTable
);
881 *LockHoldingState
= LHS_LockNotHeld
;
883 CallbackContext
= &Calldown
->CallbackContexts
[0];
884 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
885 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
886 CallbackContext
->SrvCalldownStructure
= Calldown
;
887 CallbackContext
->CallbackContextOrdinal
= 0;
888 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
890 RxReferenceSrvCall(SrvCall
);
892 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
893 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
895 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
899 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
902 Calldown
->NumberToWait
= 1;
903 Calldown
->NumberRemaining
= 1;
904 Calldown
->RxContext
= RxContext
;
905 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
906 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
907 Calldown
->BestFinisher
= NULL
;
908 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
909 InitializeListHead(&Calldown
->SrvCalldownList
);
911 /* Call the mini-rdr */
912 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
913 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
914 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
915 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
916 /* It has to return STATUS_PENDING! */
917 ASSERT(Status
== STATUS_PENDING
);
919 /* No async, start completion */
920 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
922 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
924 /* Finish construction - we'll notify mini-rdr it's the winner */
925 Status
= RxFinishSrvCallConstruction(Calldown
);
926 if (!NT_SUCCESS(Status
))
928 RxReleasePrefixTableLock(PrefixTable
);
929 *LockHoldingState
= LHS_LockNotHeld
;
933 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
934 *LockHoldingState
= LHS_ExclusiveLockHeld
;
938 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
946 RxConstructVirtualNetRoot(
947 IN PRX_CONTEXT RxContext
,
948 IN PUNICODE_STRING CanonicalName
,
949 IN NET_ROOT_TYPE NetRootType
,
950 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
951 OUT PLOCK_HOLDING_STATE LockHoldingState
,
952 OUT PRX_CONNECTION_ID RxConnectionId
)
955 PV_NET_ROOT VNetRoot
;
956 RX_BLOCK_CONDITION Condition
;
957 UNICODE_STRING LocalNetRootName
, FilePathName
;
961 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
964 Condition
= Condition_Bad
;
965 /* Before creating the VNetRoot, try to find the appropriate connection */
966 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
967 &LocalNetRootName
, &FilePathName
,
968 LockHoldingState
, RxConnectionId
);
969 /* Found and active */
970 if (Status
== STATUS_CONNECTION_ACTIVE
)
972 /* We need a new VNetRoot */
973 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
974 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
975 if (VNetRoot
!= NULL
)
977 RxReferenceVNetRoot(VNetRoot
);
980 /* Dereference previous VNetRoot */
981 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
982 /* Reset and start construct (new structures will replace old ones) */
983 RxContext
->Create
.pSrvCall
= NULL
;
984 RxContext
->Create
.pNetRoot
= NULL
;
985 RxContext
->Create
.pVNetRoot
= NULL
;
987 /* Construct new NetRoot */
988 if (VNetRoot
!= NULL
)
990 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
991 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
992 if (NT_SUCCESS(Status
))
994 Condition
= Condition_Good
;
999 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1004 /* If it failed creating the connection, leave */
1005 if (Status
!= STATUS_SUCCESS
)
1007 if (*LockHoldingState
!= LHS_LockNotHeld
)
1009 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1010 *LockHoldingState
= LHS_LockNotHeld
;
1013 *VirtualNetRootPointer
= VNetRoot
;
1014 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1018 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1020 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1021 Condition
= Condition_Good
;
1024 /* We have a non stable VNetRoot - transition it */
1025 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1027 RxTransitionVNetRoot(VNetRoot
, Condition
);
1030 /* If recreation failed */
1031 if (Status
!= STATUS_SUCCESS
)
1033 /* Dereference potential VNetRoot */
1034 if (VNetRoot
!= NULL
)
1036 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1037 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1042 if (*LockHoldingState
!= LHS_LockNotHeld
)
1044 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1045 *LockHoldingState
= LHS_LockNotHeld
;
1049 *VirtualNetRootPointer
= VNetRoot
;
1053 /* Return the allocated VNetRoot */
1054 *VirtualNetRootPointer
= VNetRoot
;
1063 IN PRX_CONTEXT RxContext
,
1064 IN PV_NET_ROOT VNetRoot
,
1065 IN PUNICODE_STRING Name
)
1071 NODE_TYPE_CODE NodeType
;
1072 PIO_STACK_LOCATION Stack
;
1073 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1077 /* We need a decent VNetRoot */
1078 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1080 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1081 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1082 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1084 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1085 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1087 Stack
= RxContext
->CurrentIrpSp
;
1089 /* Do we need to create a fake FCB? Like for renaming */
1090 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1091 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1092 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1094 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1095 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1097 /* Allocate the FCB */
1098 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1099 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1105 /* Initialize the FCB */
1106 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1107 Fcb
->RxDeviceObject
= RxDeviceObject
;
1108 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1109 Fcb
->VNetRoot
= VNetRoot
;
1110 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1112 InitializeListHead(&Fcb
->SrvOpenList
);
1113 Fcb
->SrvOpenListVersion
= 0;
1115 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1116 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1117 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1118 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1119 NetRoot
->InnerNamePrefix
.Length
);
1120 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1122 /* Copy back parameters from RxContext */
1123 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1125 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1128 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1130 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1132 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1135 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1137 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1140 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1141 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1143 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1144 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1146 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1147 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1149 /* Fake FCB doesn't go in prefix table */
1152 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1153 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1154 DPRINT("Fake FCB: %p\n", Fcb
);
1158 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1161 RxReferenceVNetRoot(VNetRoot
);
1162 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1164 Fcb
->ulFileSizeVersion
= 0;
1166 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1167 RxReferenceNetFcb(Fcb
);
1178 OUT PRX_CONTEXT RxContext
,
1179 IN PMRX_SRV_OPEN MrxSrvOpen
)
1190 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1191 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1192 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1193 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1196 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1197 /* Can we use pre-allocated FOBX? */
1198 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1200 Fobx
= Fcb
->InternalFobx
;
1201 /* Call allocate to initialize the FOBX */
1202 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1203 /* Mark it used now */
1204 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1205 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1207 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1209 Fobx
= SrvOpen
->InternalFobx
;
1210 /* Call allocate to initialize the FOBX */
1211 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1212 /* Mark it used now */
1213 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1214 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1218 /* Last case, we cannot, allocate a FOBX */
1219 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1223 /* Allocation failed! */
1230 Fobx
->Flags
= Flags
;
1232 /* Initialize throttling */
1233 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1234 if (NetRoot
!= NULL
)
1236 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1238 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1239 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1240 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1242 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1244 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1245 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1246 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1250 /* Propagate flags fron RxContext */
1251 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1253 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1256 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1258 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1262 Fobx
->FobxSerialNumber
= 0;
1263 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1264 Fobx
->NodeReferenceCount
= 1;
1265 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1267 RxReferenceSrvOpen(SrvOpen
);
1268 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1270 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1271 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1272 InitializeListHead(&Fobx
->ClosePendingList
);
1274 Fobx
->CloseTime
.QuadPart
= 0;
1275 Fobx
->fOpenCountDecremented
= FALSE
;
1277 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1279 return (PMRX_FOBX
)Fobx
;
1287 IN PSRV_CALL SrvCall
,
1288 IN PUNICODE_STRING Name
,
1289 IN ULONG NetRootFlags
,
1290 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1293 USHORT CaseInsensitiveLength
;
1294 PRX_PREFIX_TABLE PrefixTable
;
1296 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1300 /* We need a SRV_CALL */
1301 ASSERT(SrvCall
!= NULL
);
1303 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1304 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1306 /* Get name length */
1307 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1308 if (CaseInsensitiveLength
> MAXUSHORT
)
1313 /* Allocate the NetRoot */
1314 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1315 CaseInsensitiveLength
);
1316 if (NetRoot
== NULL
)
1321 /* Construct name */
1322 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1323 Name
->Buffer
, Name
->Length
);
1324 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1326 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1327 SrvCall
->PrefixEntry
.Prefix
.Length
);
1330 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1332 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1334 /* Inisert in prefix table */
1335 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1336 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1339 /* Prepare the FCB table */
1340 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1342 InitializeListHead(&NetRoot
->TransitionWaitList
);
1343 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1344 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1346 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1348 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1349 NetRoot
->Flags
|= NetRootFlags
;
1350 NetRoot
->DiskParameters
.ClusterSize
= 1;
1351 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1352 NetRoot
->SrvCall
= SrvCall
;
1354 RxReferenceSrvCall(SrvCall
);
1356 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1365 RxCreateNetRootCallBack(
1366 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1370 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1380 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1381 IN ULONG InitialContextFlags
)
1384 PRX_CONTEXT Context
;
1386 ASSERT(RxDeviceObject
!= NULL
);
1388 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1390 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1391 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1393 /* Allocate the context from our lookaside list */
1394 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1395 if (Context
== NULL
)
1400 /* And initialize it */
1401 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1402 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1403 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1405 /* Add it to our global list */
1406 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1407 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1408 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1410 DPRINT("Context: %p\n", Context
);
1419 IN PRX_CONTEXT RxContext
,
1420 IN PUNICODE_STRING Name
,
1421 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1422 IN PRX_CONNECTION_ID RxConnectionId
)
1429 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1431 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1433 /* Get the name length */
1434 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1435 if (InnerNamePrefix
!= NULL
)
1437 NameLength
+= InnerNamePrefix
->Length
;
1440 /* Allocate the object */
1441 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1442 if (SrvCall
== NULL
)
1448 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1449 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1450 RxInitializeBufferingManager(SrvCall
);
1451 InitializeListHead(&SrvCall
->TransitionWaitList
);
1452 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1453 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1454 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1455 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1456 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1457 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1458 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1459 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1461 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1470 RxCreateSrvCallCallBack(
1471 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1475 PRX_CONTEXT RxContext
;
1476 ULONG NumberRemaining
;
1477 BOOLEAN StartDispatcher
;
1478 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1480 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1482 /* Get our context structures */
1483 Calldown
= Context
->SrvCalldownStructure
;
1484 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1486 /* If it is a success, that's the winner */
1487 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1488 if (Context
->Status
== STATUS_SUCCESS
)
1490 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1491 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1493 NumberRemaining
= --Calldown
->NumberRemaining
;
1494 SrvCall
->Status
= Context
->Status
;
1495 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1497 /* Still some to ask, keep going */
1498 if (NumberRemaining
!= 0)
1503 /* If that's not async, signal we're done */
1504 RxContext
= Calldown
->RxContext
;
1505 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1507 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1510 /* If that's a mailslot, finish construction, no more to do */
1511 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1513 RxFinishSrvCallConstruction(Calldown
);
1517 /* Queue our finish call for delayed completion */
1518 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1519 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1520 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1521 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1522 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1524 /* If we have to start dispatcher, go ahead */
1525 if (StartDispatcher
)
1529 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1530 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1531 if (!NT_SUCCESS(Status
))
1533 /* It failed - run it manually.... */
1534 RxFinishSrvCallConstructionDispatcher(NULL
);
1544 IN PV_NET_ROOT VNetRoot
,
1553 ASSERT(NodeTypeIsFcb(Fcb
));
1554 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1556 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1560 SrvOpen
= Fcb
->InternalSrvOpen
;
1561 /* Check whethet we have to allocate a new SRV_OPEN */
1562 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1563 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1564 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1567 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1568 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1573 /* Otherwise, just use internal one and initialize it */
1574 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1575 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1576 Fcb
->InternalSrvOpen
);
1577 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1578 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1581 /* If SrvOpen was properly allocated, initialize it */
1582 if (SrvOpen
!= NULL
)
1584 SrvOpen
->Flags
= Flags
;
1585 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1586 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1587 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1588 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1589 SrvOpen
->NodeReferenceCount
= 1;
1591 RxReferenceVNetRoot(VNetRoot
);
1592 RxReferenceNetFcb(Fcb
);
1594 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1595 ++Fcb
->SrvOpenListVersion
;
1597 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1598 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1599 InitializeListHead(&SrvOpen
->FobxList
);
1600 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1605 if (_SEH2_AbnormalTermination())
1607 if (SrvOpen
!= NULL
)
1609 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1615 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1628 IN PRX_CONTEXT RxContext
,
1629 IN PNET_ROOT NetRoot
,
1630 IN PUNICODE_STRING CanonicalName
,
1631 IN PUNICODE_STRING LocalNetRootName
,
1632 IN PUNICODE_STRING FilePath
,
1633 IN PRX_CONNECTION_ID RxConnectionId
)
1636 PV_NET_ROOT VNetRoot
;
1637 USHORT CaseInsensitiveLength
;
1641 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1642 LocalNetRootName
, FilePath
, RxConnectionId
);
1644 /* Lock must be held exclusively */
1645 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1647 /* Check for overflow */
1648 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1653 /* Get name length and allocate VNetRoot */
1654 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1655 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1656 CaseInsensitiveLength
);
1657 if (VNetRoot
== NULL
)
1662 /* Initialize its connection parameters */
1663 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1664 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1665 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1666 if (!NT_SUCCESS(Status
))
1668 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1669 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1670 RxFreeObject(VNetRoot
);
1676 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1678 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1679 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1680 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1681 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1683 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1684 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1686 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1690 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1692 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1696 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1699 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1701 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1707 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1710 /* Insert in prefix table */
1711 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1712 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1715 RxReferenceNetRoot(NetRoot
);
1716 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1719 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1720 VNetRoot
->UpperFinalizationDone
= FALSE
;
1721 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1722 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1724 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1725 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1732 IN OUT PVOID Instance
,
1733 IN LOCK_HOLDING_STATE LockHoldingState
)
1736 NODE_TYPE_CODE NodeType
;
1737 PNODE_TYPE_AND_SIZE Node
;
1741 RxAcquireScavengerMutex();
1743 /* Check we have a node we can handle */
1744 NodeType
= NodeType(Instance
);
1745 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1746 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1747 (NodeType
== RDBSS_NTC_FOBX
));
1749 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1750 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1751 ASSERT(RefCount
>= 0);
1753 /* Trace refcount */
1756 case RDBSS_NTC_SRVCALL
:
1757 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
1760 case RDBSS_NTC_NETROOT
:
1761 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
1764 case RDBSS_NTC_V_NETROOT
:
1765 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
1768 case RDBSS_NTC_SRVOPEN
:
1769 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
1772 case RDBSS_NTC_FOBX
:
1773 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
1781 /* No need to free - still in use */
1784 RxReleaseScavengerMutex();
1788 /* We have to be locked exclusively */
1789 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
1792 RxReleaseScavengerMutex();
1796 RxReleaseScavengerMutex();
1798 /* TODO: Really deallocate stuff - we're leaking as hell! */
1801 case RDBSS_NTC_SRVCALL
:
1805 SrvCall
= (PSRV_CALL
)Instance
;
1807 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
1808 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
1809 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
1813 case RDBSS_NTC_NETROOT
:
1817 case RDBSS_NTC_V_NETROOT
:
1821 case RDBSS_NTC_SRVOPEN
:
1825 case RDBSS_NTC_FOBX
:
1836 RxDereferenceAndDeleteRxContext_Real(
1837 IN PRX_CONTEXT RxContext
)
1842 PRX_CONTEXT StopContext
= NULL
;
1844 /* Make sure we really have a context */
1845 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1846 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
1847 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
1848 /* If refcount is 0, start releasing stuff that needs spinlock held */
1851 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1853 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1855 /* If that's stop context from DO, remove it */
1856 RxDeviceObject
= RxContext
->RxDeviceObject
;
1857 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
1859 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
1863 /* Remove it from the list */
1864 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
1865 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
1866 RemoveEntryList(&RxContext
->ContextListEntry
);
1868 /* If that was the last active context, save the stop context */
1869 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
1871 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
1873 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
1878 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1880 /* Now, deal with what can be done without spinlock held */
1883 /* Refcount shouldn't have changed */
1884 ASSERT(RxContext
->ReferenceCount
== 0);
1885 /* Reset everything that can be */
1886 RxPrepareContextForReuse(RxContext
);
1888 #ifdef RDBSS_TRACKER
1889 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
1891 /* If that was the last active, set the event */
1892 if (StopContext
!= NULL
)
1894 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
1895 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
1898 /* Is ShadowCrit still owned? Shouldn't happen! */
1899 if (RxContext
->ShadowCritOwner
!= 0)
1901 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
1905 /* If it was allocated, free it */
1908 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
1918 RxDispatchToWorkerThread(
1919 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
1920 IN WORK_QUEUE_TYPE WorkQueueType
,
1921 IN PRX_WORKERTHREAD_ROUTINE Routine
,
1925 PRX_WORK_DISPATCH_ITEM DispatchItem
;
1927 /* Allocate a bit of context */
1928 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
1929 if (DispatchItem
== NULL
)
1931 return STATUS_INSUFFICIENT_RESOURCES
;
1934 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1935 DispatchItem
->DispatchRoutine
= Routine
;
1936 DispatchItem
->DispatchRoutineParameter
= pContext
;
1937 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
1938 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
1941 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, DispatchItem
);
1942 if (!NT_SUCCESS(Status
))
1944 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
1945 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
1948 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
1957 RxExclusivePrefixTableLockToShared(
1958 PRX_PREFIX_TABLE Table
)
1962 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
1969 RxExtractServerName(
1970 IN PUNICODE_STRING FilePathName
,
1971 OUT PUNICODE_STRING SrvCallName
,
1972 OUT PUNICODE_STRING RestOfName
)
1978 ASSERT(SrvCallName
!= NULL
);
1980 /* SrvCall name will start from the begin up to the first separator */
1981 SrvCallName
->Buffer
= FilePathName
->Buffer
;
1982 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
1984 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
1990 /* Compute length */
1991 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
1992 SrvCallName
->MaximumLength
= Length
;
1993 SrvCallName
->Length
= Length
;
1995 /* Return the rest if asked */
1996 if (RestOfName
!= NULL
)
1998 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
1999 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2000 RestOfName
->MaximumLength
= Length
;
2001 RestOfName
->Length
= Length
;
2009 RxFcbTableInsertFcb(
2010 IN OUT PRX_FCB_TABLE FcbTable
,
2015 /* We deal with the table, make sure it's locked */
2016 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2018 /* Compute the hash */
2019 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2021 RxReferenceNetFcb(Fcb
);
2023 /* If no length, it will be our null entry */
2024 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2026 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2028 /* Otherwise, insert in the appropriate bucket */
2031 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2032 &Fcb
->FcbTableEntry
.HashLinks
);
2035 /* Propagate the change by incrementing the version number */
2036 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2038 return STATUS_SUCCESS
;
2045 RxFcbTableLookupFcb(
2046 IN PRX_FCB_TABLE FcbTable
,
2047 IN PUNICODE_STRING Path
)
2050 PRX_FCB_TABLE_ENTRY TableEntry
;
2054 /* No path - easy, that's null entry */
2057 TableEntry
= FcbTable
->TableEntryForNull
;
2062 PLIST_ENTRY HashBucket
, ListEntry
;
2064 /* Otherwise, compute the hash value and find the associated bucket */
2065 Hash
= RxTableComputePathHashValue(Path
);
2066 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2067 /* If the bucket is empty, it means there's no entry yet */
2068 if (IsListEmpty(HashBucket
))
2074 /* Otherwise, browse all the entry */
2075 for (ListEntry
= HashBucket
->Flink
;
2076 ListEntry
!= HashBucket
;
2077 ListEntry
= ListEntry
->Flink
)
2079 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2080 InterlockedIncrement(&FcbTable
->Compares
);
2082 /* If entry hash and string are equal, thatt's the one! */
2083 if (TableEntry
->HashValue
== Hash
&&
2084 TableEntry
->Path
.Length
== Path
->Length
&&
2085 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2091 /* We reached the end? Not found */
2092 if (ListEntry
== HashBucket
)
2099 InterlockedIncrement(&FcbTable
->Lookups
);
2101 /* If table entry isn't null, return the FCB */
2102 if (TableEntry
!= NULL
)
2104 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2105 RxReferenceNetFcb(Fcb
);
2110 InterlockedIncrement(&FcbTable
->FailedLookups
);
2120 RxFcbTableRemoveFcb(
2121 IN OUT PRX_FCB_TABLE FcbTable
,
2126 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2128 /* If no path, then remove entry for null */
2129 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2131 FcbTable
->TableEntryForNull
= NULL
;
2133 /* Otherwise, remove from the bucket */
2136 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2139 /* Reset its list entry */
2140 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2142 /* Propagate the change by incrementing the version number */
2143 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2145 return STATUS_SUCCESS
;
2154 IN BOOLEAN RecursiveFinalize
,
2155 IN BOOLEAN ForceFinalize
,
2156 IN LONG ReferenceCount
)
2160 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2161 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2163 /* Make sure we have an exclusively acquired FCB */
2164 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2165 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2167 /* We shouldn't force finalization... */
2168 ASSERT(!ForceFinalize
);
2170 /* If recurisve, finalize all the associated SRV_OPEN */
2171 if (RecursiveFinalize
)
2173 PLIST_ENTRY ListEntry
;
2175 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2176 ListEntry
!= &ThisFcb
->SrvOpenList
;
2177 ListEntry
= ListEntry
->Flink
)
2181 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2182 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2185 /* If FCB is still in use, that's over */
2188 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2190 ASSERT(ReferenceCount
> 0);
2196 ASSERT(ReferenceCount
>= 1);
2198 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2199 if (ReferenceCount
!= 1 && !ForceFinalize
)
2204 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2206 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb
->OpenCount
, ForceFinalize
);
2208 /* If finalization was not already initiated, go ahead */
2209 if (!ThisFcb
->UpperFinalizationDone
)
2211 /* Free any FCB_LOCK */
2212 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2214 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2216 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2220 Entry
= ThisFcb
->BufferedLocks
.List
;
2221 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2227 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2228 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2232 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2234 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2236 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2238 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2242 ThisFcb
->UpperFinalizationDone
= TRUE
;
2245 ASSERT(ReferenceCount
>= 1);
2247 /* Even if forced, don't allow broken free */
2248 if (ReferenceCount
!= 1)
2253 /* Now, release everything */
2254 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2256 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2259 if (ThisFcb
->MRxDispatch
!= NULL
)
2261 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2264 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2265 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2266 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2268 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2269 RxDereferenceNetRoot(ThisFcb
->pNetRoot
, LHS_LockNotHeld
);
2271 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2272 ASSERT(!ThisFcb
->fMiniInited
);
2274 /* And free the object */
2275 RxFreeFcbObject(ThisFcb
);
2282 OUT PNET_ROOT ThisNetRoot
,
2283 IN BOOLEAN RecursiveFinalize
,
2284 IN BOOLEAN ForceFinalize
2293 OUT PSRV_CALL ThisSrvCall
,
2294 IN BOOLEAN RecursiveFinalize
,
2295 IN BOOLEAN ForceFinalize
)
2303 OUT PSRV_OPEN ThisSrvOpen
,
2304 IN BOOLEAN RecursiveFinalize
,
2305 IN BOOLEAN ForceFinalize
)
2312 RxFindOrConstructVirtualNetRoot(
2313 IN PRX_CONTEXT RxContext
,
2314 IN PUNICODE_STRING CanonicalName
,
2315 IN NET_ROOT_TYPE NetRootType
,
2316 IN PUNICODE_STRING RemainingName
)
2322 PV_NET_ROOT VNetRoot
;
2323 RX_CONNECTION_ID ConnectionID
;
2324 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2325 LOCK_HOLDING_STATE LockHoldingState
;
2329 RxDeviceObject
= RxContext
->RxDeviceObject
;
2330 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
2331 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
2333 /* Ask the mini-rdr for connection ID */
2334 ConnectionID
.SessionID
= 0;
2335 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
2337 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
2338 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
2340 /* mini-rdr is expected not to fail - unless it's not implemented */
2341 DPRINT1("Failed to initialize connection ID\n");
2346 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
2348 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2349 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2350 LockHoldingState
= LHS_SharedLockHeld
;
2354 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2358 PV_NET_ROOT SavedVNetRoot
;
2360 /* Look in prefix table */
2361 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
2362 if (Container
!= NULL
)
2364 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2365 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
2367 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2368 RxDereferenceSrvCall(Container
, LockHoldingState
);
2372 VNetRoot
= Container
;
2373 NetRoot
= VNetRoot
->NetRoot
;
2375 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2376 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
2377 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2379 Status
= STATUS_BAD_NETWORK_PATH
;
2380 SavedVNetRoot
= NULL
;
2386 PUNICODE_STRING UserName
, UserDomain
, Password
;
2388 /* We can reuse if we use same credentials */
2389 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
2390 &SessionId
, &UserName
,
2391 &UserDomain
, &Password
,
2393 if (NT_SUCCESS(Status
))
2395 SavedVNetRoot
= VNetRoot
;
2396 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
2398 UserDomain
, Password
,
2400 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
2402 PLIST_ENTRY ListEntry
;
2404 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
2405 ListEntry
!= &NetRoot
->VirtualNetRoots
;
2406 ListEntry
= ListEntry
->Flink
)
2408 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
2409 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
2411 UserDomain
, Password
,
2413 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2419 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
2421 SavedVNetRoot
= NULL
;
2425 if (!NT_SUCCESS(Status
))
2427 SavedVNetRoot
= NULL
;
2430 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
2434 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2435 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
2437 if (SavedVNetRoot
== NULL
)
2439 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2442 /* Reference VNetRoot we'll keep, and dereference current */
2443 else if (SavedVNetRoot
!= VNetRoot
)
2445 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2446 if (SavedVNetRoot
!= NULL
)
2448 RxReferenceVNetRoot(SavedVNetRoot
);
2453 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2454 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2461 /* If we're locked exclusive, we won't loop again, it was the second pass */
2462 if (LockHoldingState
!= LHS_SharedLockHeld
)
2467 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2468 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
2470 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2471 LockHoldingState
= LHS_ExclusiveLockHeld
;
2475 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2476 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2477 LockHoldingState
= LHS_ExclusiveLockHeld
;
2480 /* We didn't fail, and didn't find any VNetRoot, construct one */
2483 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
2485 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
2486 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
2488 if (Status
== STATUS_SUCCESS
)
2490 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
2491 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2492 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
2494 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2495 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
2496 RemainingName
->MaximumLength
= RemainingName
->Length
;
2498 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
2500 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
2502 VNetRoot
->Flags
|= Flags
;
2506 /* Release the prefix table - caller expects it to be released */
2507 if (LockHoldingState
!= LHS_LockNotHeld
)
2509 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2512 /* If we failed creating, quit */
2513 if (Status
!= STATUS_SUCCESS
)
2515 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
2519 /* Otherwise, wait until the VNetRoot is stable */
2520 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
2521 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
2522 /* It's all good, update the RX_CONTEXT with all our structs */
2523 if (VNetRoot
->Condition
== Condition_Good
)
2527 NetRoot
= VNetRoot
->NetRoot
;
2528 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2529 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2530 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
2534 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2535 RxContext
->Create
.pVNetRoot
= NULL
;
2536 Status
= STATUS_BAD_NETWORK_PATH
;
2546 RxFindOrCreateConnections(
2547 _In_ PRX_CONTEXT RxContext
,
2548 _In_ PUNICODE_STRING CanonicalName
,
2549 _In_ NET_ROOT_TYPE NetRootType
,
2550 _Out_ PUNICODE_STRING LocalNetRootName
,
2551 _Out_ PUNICODE_STRING FilePathName
,
2552 _Inout_ PLOCK_HOLDING_STATE LockState
,
2553 _In_ PRX_CONNECTION_ID RxConnectionId
)
2558 PV_NET_ROOT VNetRoot
;
2559 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
2560 PRX_PREFIX_TABLE PrefixTable
;
2561 UNICODE_STRING RemainingName
, NetRootName
;
2565 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2566 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
2567 FilePathName
, LockState
, RxConnectionId
);
2569 *FilePathName
= *CanonicalName
;
2570 LocalNetRootName
->Length
= 0;
2571 LocalNetRootName
->MaximumLength
= 0;
2572 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
2574 /* UNC path, split it */
2575 if (FilePathName
->Buffer
[1] == ';')
2581 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2583 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2592 return STATUS_OBJECT_NAME_INVALID
;
2595 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
2596 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
2597 LocalNetRootName
->Length
= Length
;
2598 LocalNetRootName
->MaximumLength
= Length
;
2599 FilePathName
->Length
-= Length
;
2601 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
2602 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
2603 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
2607 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
2612 ASSERT(*LockState
!= LHS_LockNotHeld
);
2614 /* If previous lookup left something, dereference it */
2615 if (Container
!= NULL
)
2617 switch (NodeType(Container
))
2619 case RDBSS_NTC_SRVCALL
:
2620 RxDereferenceSrvCall(Container
, *LockState
);
2623 case RDBSS_NTC_NETROOT
:
2624 RxDereferenceNetRoot(Container
, *LockState
);
2627 case RDBSS_NTC_V_NETROOT
:
2628 RxDereferenceVNetRoot(Container
, *LockState
);
2632 /* Should never happen */
2638 /* Look for our NetRoot in prefix table */
2639 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
2640 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
2644 UNICODE_STRING SrvCallName
;
2650 /* Assume we didn't succeed */
2651 RxContext
->Create
.pVNetRoot
= NULL
;
2652 RxContext
->Create
.pNetRoot
= NULL
;
2653 RxContext
->Create
.pSrvCall
= NULL
;
2654 RxContext
->Create
.Type
= NetRootType
;
2656 /* If we found something */
2657 if (Container
!= NULL
)
2660 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
2662 VNetRoot
= Container
;
2663 /* Use its NetRoot */
2664 NetRoot
= VNetRoot
->NetRoot
;
2666 /* If it's not stable, wait for it to be stable */
2667 if (NetRoot
->Condition
== Condition_InTransition
)
2669 RxReleasePrefixTableLock(PrefixTable
);
2670 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
2671 RxWaitForStableNetRoot(NetRoot
, RxContext
);
2672 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2673 *LockState
= LHS_ExclusiveLockHeld
;
2675 /* Now that's it's ok, retry lookup to find what we want */
2676 if (NetRoot
->Condition
== Condition_Good
)
2682 /* Is the associated netroot good? */
2683 if (NetRoot
->Condition
== Condition_Good
)
2685 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
2687 /* If it is, and SrvCall as well, then, we have our active connection */
2688 if (SrvCall
->Condition
== Condition_Good
&&
2689 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
2691 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2692 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2693 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2695 Status
= STATUS_CONNECTION_ACTIVE
;
2700 /* If VNetRoot was well constructed, it means the connection is active */
2701 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
2703 Status
= STATUS_CONNECTION_ACTIVE
;
2707 Status
= VNetRoot
->ConstructionStatus
;
2710 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2713 /* Can only be a SrvCall */
2716 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2717 SrvCall
= Container
;
2719 /* Wait for the SRV_CALL to be stable */
2720 if (SrvCall
->Condition
== Condition_InTransition
)
2722 RxReleasePrefixTableLock(PrefixTable
);
2723 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
2724 RxWaitForStableSrvCall(SrvCall
, RxContext
);
2725 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2726 *LockState
= LHS_ExclusiveLockHeld
;
2728 /* It went good, loop again to find what we look for */
2729 if (SrvCall
->Condition
== Condition_Good
)
2735 /* If it's not good... */
2736 if (SrvCall
->Condition
!= Condition_Good
)
2738 /* But SRV_CALL was well constructed, assume a connection was active */
2739 if (SrvCall
->Status
== STATUS_SUCCESS
)
2741 Status
= STATUS_CONNECTION_ACTIVE
;
2745 Status
= SrvCall
->Status
;
2748 RxDereferenceSrvCall(SrvCall
, *LockState
);
2754 /* If we found a SRV_CALL not matching our DO, quit */
2755 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
2756 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2758 RxDereferenceSrvCall(SrvCall
, *LockState
);
2759 Status
= STATUS_BAD_NETWORK_NAME
;
2763 /* Now, we want exclusive lock */
2764 if (*LockState
== LHS_SharedLockHeld
)
2766 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
2768 RxReleasePrefixTableLock(PrefixTable
);
2769 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2770 *LockState
= LHS_ExclusiveLockHeld
;
2774 RxReleasePrefixTableLock(PrefixTable
);
2775 *LockState
= LHS_ExclusiveLockHeld
;
2778 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2780 /* If we reach that point, we found something, no need to create something */
2781 if (Container
!= NULL
)
2786 /* Get the name for the SRV_CALL */
2787 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
2788 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
2789 /* And create the SRV_CALL */
2790 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
2791 if (SrvCall
== NULL
)
2793 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2797 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2798 RxReferenceSrvCall(SrvCall
);
2799 RxContext
->Create
.pVNetRoot
= NULL
;
2800 RxContext
->Create
.pNetRoot
= NULL
;
2801 RxContext
->Create
.pSrvCall
= NULL
;
2802 RxContext
->Create
.Type
= NetRootType
;
2803 Container
= SrvCall
;
2805 /* Construct SRV_CALL, ie, use mini-rdr */
2806 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
2807 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
2808 if (Status
!= STATUS_SUCCESS
)
2810 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
2811 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2812 RxDereferenceSrvCall(SrvCall
, *LockState
);
2813 RxReleasePrefixTableLock(PrefixTable
);
2817 /* Loop again to make use of SRV_CALL stable condition wait */
2820 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2821 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
2822 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
2823 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
2825 /* Call mini-rdr to get NetRoot name */
2826 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
2827 /* And create the NetRoot with that name */
2828 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
2829 if (NetRoot
== NULL
)
2831 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2834 NetRoot
->Type
= NetRootType
;
2836 RxDereferenceSrvCall(SrvCall
, *LockState
);
2838 /* Finally, create the associated VNetRoot */
2839 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
2840 if (VNetRoot
== NULL
)
2842 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2843 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2846 RxReferenceVNetRoot(VNetRoot
);
2848 /* We're get closer! */
2849 NetRoot
->Condition
= Condition_InTransition
;
2850 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2851 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2852 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2854 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2855 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
2856 if (!NT_SUCCESS(Status
))
2858 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
2859 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
2860 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2862 RxContext
->Create
.pNetRoot
= NULL
;
2863 RxContext
->Create
.pVNetRoot
= NULL
;
2867 PIO_STACK_LOCATION Stack
;
2869 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2871 Stack
= RxContext
->CurrentIrpSp
;
2872 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2874 RxExclusivePrefixTableLockToShared(PrefixTable
);
2875 *LockState
= LHS_SharedLockHeld
;
2881 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
2883 if (*LockState
!= LHS_LockNotHeld
)
2885 RxReleasePrefixTableLock(PrefixTable
);
2886 *LockState
= LHS_LockNotHeld
;
2892 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
2901 RxFinishFcbInitialization(
2902 IN OUT PMRX_FCB Fcb
,
2903 IN RX_FILE_TYPE FileType
,
2904 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
2906 NODE_TYPE_CODE OldType
;
2910 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
2912 OldType
= Fcb
->Header
.NodeTypeCode
;
2913 Fcb
->Header
.NodeTypeCode
= FileType
;
2914 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2915 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
2917 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2919 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2920 else if (InitPacket
!= NULL
)
2922 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
2923 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
2924 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
2925 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
2926 InitPacket
->pValidDataLength
->QuadPart
);
2929 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2930 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2932 /* If our FCB newly points to a file, initiliaz everything related */
2933 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
&&
2934 !OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
2936 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
2937 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, &RxLockOperationCompletion
,
2938 &RxUnlockOperation
);
2940 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
2941 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
2943 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
2947 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
2956 RxFinishSrvCallConstruction(
2957 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
2961 PRX_CONTEXT Context
;
2962 RX_BLOCK_CONDITION Condition
;
2963 PRX_PREFIX_TABLE PrefixTable
;
2965 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
2967 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
2968 Context
= Calldown
->RxContext
;
2969 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
2971 /* We have a winner, notify him */
2972 if (Calldown
->BestFinisher
!= NULL
)
2974 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
2976 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
2978 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
2979 MRxSrvCallWinnerNotify
,
2980 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
2981 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
2982 if (Status
!= STATUS_SUCCESS
)
2984 Condition
= Condition_Bad
;
2988 Condition
= Condition_Good
;
2991 /* Otherwise, just fail our SRV_CALL */
2994 Status
= Calldown
->CallbackContexts
[0].Status
;
2995 Condition
= Condition_Bad
;
2998 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2999 RxTransitionSrvCall(SrvCall
, Condition
);
3000 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
3002 /* If async, finish it here, otherwise, caller has already finished the stuff */
3003 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
3005 DPRINT("Finishing async call\n");
3007 RxReleasePrefixTableLock(PrefixTable
);
3009 /* Make sure we weren't cancelled in-between */
3010 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
3012 Status
= STATUS_CANCELLED
;
3015 /* In case that was a create, context can be reused */
3016 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
3018 RxpPrepareCreateContextForReuse(Context
);
3021 /* If that's a failure, reset everything and return failure */
3022 if (Status
!= STATUS_SUCCESS
)
3024 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
3025 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3027 if (Context
->Info
.Buffer
!= NULL
)
3029 RxFreePool(Context
->Info
.Buffer
);
3030 Context
->Info
.Buffer
= NULL
;
3033 Context
->CurrentIrp
->IoStatus
.Information
= 0;
3034 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
3035 RxCompleteRequest(Context
, Status
);
3037 /* Otherwise, call resume routine and done! */
3040 Status
= Context
->ResumeRoutine(Context
);
3041 if (Status
!= STATUS_PENDING
)
3043 RxCompleteRequest(Context
, Status
);
3046 DPRINT("Not completing, pending\n");
3050 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3059 RxFinishSrvCallConstructionDispatcher(
3063 BOOLEAN Direct
, KeepLoop
;
3065 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
3067 /* In case of failure of starting dispatcher, context is not set
3068 * We keep track of it to fail associated SRV_CALL
3070 Direct
= (Context
== NULL
);
3072 /* Separated thread, loop forever */
3075 PLIST_ENTRY ListEntry
;
3076 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
3078 /* If there are no SRV_CALL to finalize left, just finish thread */
3079 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
3080 if (IsListEmpty(&RxSrvCalldownList
))
3083 RxSrvCallConstructionDispatcherActive
= FALSE
;
3085 /* Otherwise, get the SRV_CALL to finish construction */
3088 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
3091 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
3099 /* If direct is set, reset the finisher to avoid electing a winner
3100 * and fail SRV_CALL (see upper comment)
3102 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
3105 Calldown
->BestFinisher
= NULL
;
3107 /* Finish SRV_CALL construction */
3108 RxFinishSrvCallConstruction(Calldown
);
3130 RxGetFileSizeWithLock(
3132 OUT PLONGLONG FileSize
)
3136 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
3147 return RxData
.OurProcess
;
3154 RxInitializeBufferingManager(
3157 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
3158 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
3159 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
3160 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
3161 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
3162 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
3163 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
3164 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
3165 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
3166 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
3168 return STATUS_SUCCESS
;
3176 RxInitializeContext(
3178 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
3179 IN ULONG InitialContextFlags
,
3180 IN OUT PRX_CONTEXT RxContext
)
3182 PIO_STACK_LOCATION Stack
;
3184 /* Initialize our various fields */
3185 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
3186 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
3187 RxContext
->ReferenceCount
= 1;
3188 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
3189 RxContext
->RxDeviceObject
= RxDeviceObject
;
3190 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
3191 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
3192 InitializeListHead(&RxContext
->BlockedOperations
);
3193 RxContext
->MRxCancelRoutine
= NULL
;
3194 RxContext
->ResumeRoutine
= NULL
;
3195 RxContext
->Flags
|= InitialContextFlags
;
3196 RxContext
->CurrentIrp
= Irp
;
3197 RxContext
->LastExecutionThread
= PsGetCurrentThread();
3198 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
3200 /* If've got no IRP, mark RX_CONTEXT */
3203 RxContext
->CurrentIrpSp
= NULL
;
3204 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
3205 RxContext
->MinorFunction
= 0;
3209 /* Otherwise, first determine whether we are performing async operation */
3210 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3211 if (Stack
->FileObject
!= NULL
)
3215 Fcb
= Stack
->FileObject
->FsContext
;
3216 if (!IoIsOperationSynchronous(Irp
) ||
3217 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
3218 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
3219 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
3221 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3225 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
3227 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3229 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3231 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3234 /* Set proper flags if TopLevl IRP/Device */
3235 if (!RxIsThisTheTopLevelIrp(Irp
))
3237 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
3239 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
3241 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
3244 /* Copy stack information */
3245 RxContext
->MajorFunction
= Stack
->MajorFunction
;
3246 RxContext
->MinorFunction
= Stack
->MinorFunction
;
3247 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
3248 RxContext
->CurrentIrpSp
= Stack
;
3250 /* If we have a FO associated, learn for more */
3251 if (Stack
->FileObject
!= NULL
)
3256 /* Get the FCB and CCB (FOBX) */
3257 Fcb
= Stack
->FileObject
->FsContext
;
3258 Fobx
= Stack
->FileObject
->FsContext2
;
3259 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
3260 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
3262 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
3265 /* We have a FOBX, this not a DFS opening, keep track of it */
3266 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
3268 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
3269 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
3270 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3272 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
3277 RxContext
->pFobx
= NULL
;
3280 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3281 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
3284 PV_NET_ROOT VNetRoot
= NULL
;
3286 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3288 VNetRoot
= Fcb
->VNetRoot
;
3290 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
3292 VNetRoot
= (PV_NET_ROOT
)Fobx
;
3295 if (VNetRoot
!= NULL
)
3297 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3301 /* Remember if that's a write through file */
3302 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;