ReactOS  0.4.13-dev-563-g0561610
rxce.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 2017 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  */
19 /*
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)
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <dfs.h>
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 VOID
37 RxAssert(
38  PVOID Assert,
39  PVOID File,
40  ULONG Line,
41  PVOID Message);
42 
43 VOID
44 NTAPI
47 
51 
52 VOID
53 NTAPI
55  IN PVOID Context);
56 
59  PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60  WORK_QUEUE_TYPE WorkQueueType,
61  PRX_WORK_QUEUE_ITEM WorkQueueItem);
62 
63 PVOID
65  PRX_CONTEXT RxContext);
66 
67 VOID
68 NTAPI
70  IN PVOID Context);
71 
72 VOID
74  PSRV_CALL SrvCall,
75  PSRV_OPEN SrvOpen,
76  PLIST_ENTRY DiscardedRequests);
77 
78 VOID
79 NTAPI
81  PVOID Context);
82 
83 VOID
84 NTAPI
86  _In_ struct _KDPC *Dpc,
90 
91 VOID
92 NTAPI
94  PVOID Context);
95 
96 PVOID
97 NTAPI
101  _In_ ULONG Tag);
102 
103 VOID
104 NTAPI
106  _In_ PVOID Buffer);
107 
108 VOID
109 NTAPI
111  _In_ PVOID Buffer,
112  _In_ ULONG Tag);
113 
115 
124 #if 0
129 #else
131 #endif
147 #if DBG
149 #else
151 #endif
152 
153 #if RDBSS_ASSERTS
154 #ifdef ASSERT
155 #undef ASSERT
156 #endif
157 
158 #define ASSERT(exp) \
159  if (!(exp)) \
160  { \
161  RxAssert(#exp, __FILE__, __LINE__, NULL); \
162  }
163 #endif
164 
165 #if RX_POOL_WRAPPER
166 #undef RxAllocatePool
167 #undef RxAllocatePoolWithTag
168 #undef RxFreePool
169 
170 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
171 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
172 #define RxFreePool _RxFreePool
173 #define RxFreePoolWithTag _RxFreePoolWithTag
174 #endif
175 
176 /* FUNCTIONS ****************************************************************/
177 
178 /*
179  * @implemented
180  */
181 NTSTATUS
182 NTAPI
185 {
187 }
188 
189 /*
190  * @implemented
191  */
192 BOOLEAN
193 NTAPI
195  PVOID Context,
196  BOOLEAN Wait)
197 {
198  PFCB Fcb;
199  BOOLEAN Ret;
200 
201  PAGED_CODE();
202 
203  Fcb = Context;
204  /* The received context is a FCB */
207  ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
208 
209  /* Acquire the paging resource (shared) */
210  Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
211  if (Ret)
212  {
213  /* Update tracker information */
214  Fcb->PagingIoResourceFile = __FILE__;
215  Fcb->PagingIoResourceLine = __LINE__;
216  /* Lazy writer thread is the current one */
217  Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
218 
219  /* There is no top level IRP */
221  /* Now, there will be! */
224  /* In case of failure, release the lock and reset everything */
225  if (!Ret)
226  {
229  ExReleaseResourceLite(Fcb->Header.PagingIoResource);
230  Fcb->Specific.Fcb.LazyWriteThread = NULL;
231  }
232  }
233 
234  return Ret;
235 }
236 
237 /*
238  * @implemented
239  */
240 BOOLEAN
241 NTAPI
243  PVOID Context,
244  BOOLEAN Wait)
245 {
246  PFCB Fcb;
247  BOOLEAN Ret;
248 
249  PAGED_CODE();
250 
251  Fcb = Context;
252  /* The received context is a FCB */
255 
256  Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
257  if (Ret)
258  {
259  /* There is no top level IRP */
261  /* Now, there will be! */
264  /* In case of failure, release the lock and reset everything */
265  if (!Ret)
266  {
267  ExReleaseResourceLite(Fcb->Header.Resource);
268  }
269  }
270 
271  return Ret;
272 }
273 
274 VOID
275 NTAPI
278 {
280 }
281 
282 NTSTATUS
283 NTAPI
287 {
289  return STATUS_NOT_IMPLEMENTED;
290 }
291 
292 /*
293  * @implemented
294  */
295 VOID
297  PNET_ROOT NetRoot,
298  PV_NET_ROOT VNetRoot)
299 {
300  PAGED_CODE();
301 
302  DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
303 
304  /* Insert in the VNetRoot list - make sure lock is held */
305  ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
306 
307  VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
308  ++NetRoot->NumberOfVirtualNetRoots;
309  InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
310 }
311 
312 /*
313  * @implemented
314  */
315 PVOID
317  PRDBSS_DEVICE_OBJECT RxDeviceObject,
320  ULONG NameSize,
321  PVOID AlreadyAllocatedObject)
322 {
323  PFCB Fcb;
324  PFOBX Fobx;
325  PSRV_OPEN SrvOpen;
326  PVOID Buffer, PAPNBuffer;
327  PNON_PAGED_FCB NonPagedFcb;
329  ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
330 
331  PAGED_CODE();
332 
333  Dispatch = RxDeviceObject->Dispatch;
334 
335  NonPagedSize = 0;
336  FobxSize = 0;
337  SrvOpenSize = 0;
338  FcbSize = 0;
339 
340  Fcb = NULL;
341  Fobx = NULL;
342  SrvOpen = NULL;
343  NonPagedFcb = NULL;
344  PAPNBuffer = NULL;
345 
346  /* If we ask for FOBX, just allocate FOBX and its extension if asked */
347  if (NodeType == RDBSS_NTC_FOBX)
348  {
349  FobxSize = sizeof(FOBX);
351  {
352  FobxSize += QuadAlign(Dispatch->MRxFobxSize);
353  }
354  }
355  /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
357  {
358  SrvOpenSize = sizeof(SRV_OPEN);
360  {
361  SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
362  }
363 
364  FobxSize = sizeof(FOBX);
366  {
367  FobxSize += QuadAlign(Dispatch->MRxFobxSize);
368  }
369  }
370  /* Otherwise, we're asked to allocate a FCB */
371  else
372  {
373  /* So, allocate the FCB and its extension if asked */
374  FcbSize = sizeof(FCB);
376  {
377  FcbSize += QuadAlign(Dispatch->MRxFcbSize);
378  }
379 
380  /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
381  * Otherwise, it will be allocated later on, specifically
382  */
383  if (PoolType == NonPagedPool)
384  {
385  NonPagedSize = sizeof(NON_PAGED_FCB);
386  }
387 
388  /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
390  {
391  SrvOpenSize = sizeof(SRV_OPEN);
393  {
394  SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
395  }
396 
397  FobxSize = sizeof(FOBX);
399  {
400  FobxSize += QuadAlign(Dispatch->MRxFobxSize);
401  }
402  }
403  }
404 
405  /* If we already have a buffer, go ahead */
406  if (AlreadyAllocatedObject != NULL)
407  {
408  Buffer = AlreadyAllocatedObject;
409  }
410  /* Otherwise, allocate it */
411  else
412  {
413  Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
414  if (Buffer == NULL)
415  {
416  return NULL;
417  }
418  }
419 
420  /* Now, get the pointers - FOBX is easy */
421  if (NodeType == RDBSS_NTC_FOBX)
422  {
423  Fobx = Buffer;
424  }
425  /* SRV_OPEN first, FOBX next */
426  else if (NodeType == RDBSS_NTC_SRVOPEN)
427  {
428  SrvOpen = Buffer;
429  Fobx = Add2Ptr(Buffer, SrvOpenSize);
430  }
432  {
433  SrvOpen = Buffer;
434  }
435  else
436  {
437  /* FCB first, and if needed, SRV_OPEN next, FOBX last */
438  Fcb = Buffer;
440  {
441  SrvOpen = Add2Ptr(Buffer, FcbSize);
442  Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
443  }
444 
445  /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
446  if (PoolType != NonPagedPool)
447  {
449  if (NonPagedFcb == NULL)
450  {
451  RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
452  return NULL;
453  }
454 
455  PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
456  }
457  /* Otherwise, just point at the right place in what has been allocated previously */
458  else
459  {
460  NonPagedFcb = Add2Ptr(Fobx, FobxSize);
461  PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
462  }
463  }
464 
465  /* If we have allocated a SRV_OPEN, initialize it */
466  if (SrvOpen != NULL)
467  {
468  ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
469 
471  {
472  SrvOpen->InternalFobx = Fobx;
473  }
474  else
475  {
476  SrvOpen->InternalFobx = NULL;
477  SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
478  }
479 
481  {
482  SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
483  }
484 
485  InitializeListHead(&SrvOpen->SrvOpenQLinks);
486  }
487 
488  /* If we have allocated a FOBX, initialize it */
489  if (Fobx != NULL)
490  {
491  ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
492 
494  {
495  Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
496  }
497  }
498 
499  /* If we have allocated a FCB, initialize it */
500  if (Fcb != NULL)
501  {
503 
504  Fcb->NonPaged = NonPagedFcb;
506 #if DBG
507  Fcb->CopyOfNonPaged = NonPagedFcb;
508  NonPagedFcb->FcbBackPointer = Fcb;
509 #endif
510 
511  Fcb->InternalSrvOpen = SrvOpen;
512  Fcb->InternalFobx = Fobx;
513 
516  Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
517 
519  {
520  Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
521  }
522 
524 
526  InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
527 
529  FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
530  }
531 
532  DPRINT("Allocated %p\n", Buffer);
533 
534  return Buffer;
535 }
536 
537 /*
538  * @implemented
539  */
540 PVOID
543  PMINIRDR_DISPATCH MRxDispatch,
544  ULONG NameLength)
545 {
546  ULONG Tag, ObjectSize;
548  PRX_PREFIX_ENTRY PrefixEntry;
549  USHORT StructSize, ExtensionSize;
550 
551  PAGED_CODE();
552 
553  /* Select the node to allocate and always deal with the fact we may have to manage its extension */
554  ExtensionSize = 0;
555  switch (NodeType)
556  {
557  case RDBSS_NTC_SRVCALL:
559  StructSize = sizeof(SRV_CALL);
560  if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
561  {
562  ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
563  }
564  break;
565 
566  case RDBSS_NTC_NETROOT:
568  StructSize = sizeof(NET_ROOT);
570  {
571  ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
572  }
573  break;
574 
575  case RDBSS_NTC_V_NETROOT:
577  StructSize = sizeof(V_NET_ROOT);
579  {
580  ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
581  }
582  break;
583 
584  default:
585  ASSERT(FALSE);
586  break;
587  }
588 
589  /* Now, allocate the object */
590  ObjectSize = ExtensionSize + StructSize + NameLength;
592  if (Object == NULL)
593  {
594  return NULL;
595  }
596  /* Initialize it */
598 
599  /* For SRV_CALL and NETROOT, the name points to the prefix table name */
600  switch (NodeType)
601  {
602  case RDBSS_NTC_SRVCALL:
603  PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
604  Extension = &((PSRV_CALL)Object)->Context;
605  ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
606  break;
607 
608  case RDBSS_NTC_NETROOT:
609  PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
610  Extension = &((PNET_ROOT)Object)->Context;
611  ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
612  break;
613 
614  case RDBSS_NTC_V_NETROOT:
615  PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
616  Extension = &((PV_NET_ROOT)Object)->Context;
617  break;
618 
619  default:
620  ASSERT(FALSE);
621  break;
622  }
623 
624  /* Set the prefix table unicode string */
625  RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
626  PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
627  PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
628  PrefixEntry->Prefix.Length = NameLength;
629  PrefixEntry->Prefix.MaximumLength = NameLength;
630  PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
631 
632  /* Return the extension if we are asked to manage it */
633  if (ExtensionSize != 0)
634  {
635  *Extension = Add2Ptr(Object, StructSize);
636  }
637 
638  return Object;
639 }
640 
641 /*
642  * @implemented
643  */
644 VOID
646  PVOID Assert,
647  PVOID File,
648  ULONG Line,
649  PVOID Message)
650 {
651  CHAR Response[2];
653 
654  /* If we're not asked to continue, just stop the system */
656  {
657  KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
658  }
659 
660  /* Otherwise, capture context to offer the user to dump it */
662 
663  /* Loop until the user hits 'i' */
664  while (TRUE)
665  {
666  /* If no file provided, use empty name */
667  if (File == NULL)
668  {
669  File = "";
670  }
671 
672  /* If no message provided, use empty one */
673  if (Message == NULL)
674  {
675  Message = "";
676  }
677 
678  /* Display the message */
679  DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
680  /* And ask the user */
681  DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
682  /* If he asks for ignore, quit
683  * In case of invalid input, ask again
684  */
685  if (Response[0] != 'B' && Response[0] != 'b')
686  {
687  if (Response[0] == 'I' || Response[0] == 'i')
688  {
689  return;
690  }
691 
692  continue;
693  }
694 
695  /* Break: offer the user to dump the context and break */
696  DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
697  DbgBreakPoint();
698 
699  /* Continue looping, so that after dump, execution can continue (with ignore) */
700  }
701 }
702 
703 /*
704  * @implemented
705  */
706 VOID
707 NTAPI
710 {
711  PRX_WORK_QUEUE RxWorkQueue;
712 
713  PAGED_CODE();
714 
715  RxWorkQueue = WorkQueue;
716  RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
717 }
718 
719 /*
720  * @implemented
721  */
722 VOID
724  IN OUT PRX_CONTEXT RxContext)
725 {
726  PFOBX Fobx;
727  BOOLEAN PostRequest;
728 
729  PAGED_CODE();
730 
731  Fobx = (PFOBX)RxContext->pFobx;
732  PostRequest = FALSE;
733 
734  /* Acquire the pipe mutex */
736 
737  /* If that's a blocking pipe operation which is not the CCB one, then handle it */
738  if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION) &&
739  RxContext->RxContextSerializationQLinks.Flink != NULL &&
740  RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.ReadSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks) &&
741  RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.WriteSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks))
742  {
743  /* Clear it! */
744  ClearFlag(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
745 
746  /* Drop it off the list */
747  RemoveEntryList(&RxContext->RxContextSerializationQLinks);
748  RxContext->RxContextSerializationQLinks.Flink = NULL;
749  RxContext->RxContextSerializationQLinks.Blink = NULL;
750 
751  /* Set we've been cancelled */
752  RxContext->IoStatusBlock.Status = STATUS_CANCELLED;
753 
754  /*
755  * If it's async, we'll post completion, otherwise, we signal to waiters
756  * it's being cancelled
757  */
758  if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
759  {
760  PostRequest = TRUE;
761  }
762  else
763  {
764  RxSignalSynchronousWaiter(RxContext);
765  }
766  }
767 
768  /* Done */
770 
771  /* Post if async */
772  if (PostRequest)
773  {
774  RxFsdPostRequest(RxContext);
775  }
776 }
777 
778 /*
779  * @implemented
780  */
781 NTSTATUS
782 NTAPI
784  PSRV_OPEN SrvOpen,
785  PVOID Context,
786  BOOLEAN ComputeNewState)
787 {
788  PFCB Fcb;
790  ULONG NewBufferingState, OldBufferingState;
791 
792  PAGED_CODE();
793 
794  DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
795 
796  Fcb = (PFCB)SrvOpen->pFcb;
798  /* First of all, mark that buffering state is changing */
800 
801  /* Assume success */
803  _SEH2_TRY
804  {
805  /* If we're asked to compute a new state, ask the mini-rdr for it */
806  if (ComputeNewState)
807  {
808  MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
809  ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
810  if (MiniStatus != STATUS_SUCCESS)
811  {
812  NewBufferingState = 0;
813  }
814  }
815  else
816  {
817  /* If not, use SRV_OPEN state */
818  NewBufferingState = SrvOpen->BufferingFlags;
819  }
820 
821  /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
822  if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
823  {
824  SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
825  }
826 
827  /* If there's a lock operation to complete, clear that flag */
828  if (Fcb->OutstandingLockOperationsCount != 0)
829  {
830  ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
831  }
832 
833  /* Get the old state */
834  OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
835  DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
836 
837  /* If we're dropping write cache, then flush the FCB */
838  if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
839  !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
840  {
841  DPRINT("Flushing\n");
842 
844  }
845 
846  /* If we're dropping read cache, then purge */
847  if (Fcb->UncleanCount == 0 ||
848  (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
849  !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
850  BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
851  {
852  DPRINT("Purging\n");
853 
854  if (!NT_SUCCESS(Status))
855  {
856  DPRINT("Previous flush failed with status: %lx\n", Status);
857  }
858 
860  }
861 
862  /* If there's already a change pending in SRV_OPEN */
863  if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
864  {
865  /* If there's a FOBX at least */
866  if (!IsListEmpty(&SrvOpen->FobxList))
867  {
868  PRX_CONTEXT RxContext;
869 
870  /* Create a fake context to pass to the mini-rdr */
872  if (RxContext != NULL)
873  {
874  PFOBX Fobx;
875 
876  RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
877 
878  /* Give the first FOBX */
879  Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
880  RxContext->pFobx = (PMRX_FOBX)Fobx;
881  RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
882 
883  /* If there was a delayed close, perform it */
884  if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
885  {
886  DPRINT("Oplock break close for %p\n", SrvOpen);
887 
888  RxCloseAssociatedSrvOpen(Fobx, RxContext);
889  }
890  /* Otherwise, inform the mini-rdr about completion */
891  else
892  {
893  MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
894  (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
895  (void)MiniStatus;
896  }
897 
899  }
900  }
901  }
902 
903  /* Set the new state */
904  Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
905  }
907  {
908  /* Job done, clear the flag */
910 
911  if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
912  {
914  }
915  }
916  _SEH2_END;
917 
918  return Status;
919 }
920 
921 NTSTATUS
923  PRX_CONTEXT RxContext,
924  PV_NET_ROOT VNetRoot,
925  PLUID LogonId,
926  PUNICODE_STRING UserName,
927  PUNICODE_STRING UserDomain,
929  ULONG Flags)
930 {
931  PAGED_CODE();
932 
933  /* If that's a UNC name, there's nothing to process */
935  (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
936  Flags != 0))
937  {
939  }
940 
941  /* Compare the logon ID in the VNetRoot with the one provided */
942  if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
943  {
945  }
946 
947  /* No credential provided? That's OK */
948  if (UserName == NULL && UserDomain == NULL && Password == NULL)
949  {
950  return STATUS_SUCCESS;
951  }
952 
953  /* Left to do! */
955  return STATUS_NOT_IMPLEMENTED;
956 }
957 
958 NTSTATUS
962 {
963  PIRP Irp;
964 
965  PAGED_CODE();
966 
967  DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
968 
969  ASSERT(Context != NULL);
970  ASSERT(Context->CurrentIrp != NULL);
971  Irp = Context->CurrentIrp;
972 
973  /* Debug what the caller asks for */
974  if (Context->LoudCompletionString != NULL)
975  {
976  DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
977  /* Does the user asks to stop on failed completion */
979  {
980  DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
981  }
982  }
983 
984  /* Complete for real */
985  Context->CurrentIrp = NULL;
987 
988  DPRINT("Status: %lx\n", Status);
989  return Status;
990 }
991 
992 /*
993  * @implemented
994  */
995 VOID
997  IN PRX_CONTEXT RxContext,
998  IN PIRP Irp,
1000 {
1001  CCHAR Boost;
1002  KIRQL OldIrql;
1003  PIO_STACK_LOCATION Stack;
1004 
1005  DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
1006 
1007  /* Nothing to complete, just free context */
1008  if (Irp == NULL)
1009  {
1010  DPRINT("NULL IRP for %p\n", RxContext);
1011  if (RxContext != NULL)
1012  {
1014  }
1015 
1016  return;
1017  }
1018 
1019  /* Remove cancel routine */
1023 
1024  /* Select the boost, given the success/paging operation */
1026  {
1027  Boost = IO_DISK_INCREMENT;
1028  }
1029  else
1030  {
1031  Irp->IoStatus.Information = 0;
1032  Boost = IO_NO_INCREMENT;
1033  }
1034  Irp->IoStatus.Status = Status;
1035 
1036  if (RxContext != NULL)
1037  {
1038  ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
1039  if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
1040  {
1041  DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
1042  RxContext->MinorFunction, RxContext, Irp,
1043  Status, Irp->IoStatus.Information, RxContext->SerialNumber);
1044  }
1045  }
1046 
1047  /* If that's an opening, there might be a canonical name allocated,
1048  * if completion isn't pending, release it
1049  */
1051  if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
1052  RxContext != NULL)
1053  {
1054  if (BooleanFlagOn(RxContext->Create.Flags, 2))
1055  {
1056  Stack->FileObject->FileName.Length += sizeof(WCHAR);
1057  }
1058 
1060  ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
1061  }
1062 
1063  /* If it's a write, validate the correct behavior of the operation */
1064  if (Stack->MajorFunction == IRP_MJ_WRITE)
1065  {
1066  if (NT_SUCCESS(Irp->IoStatus.Status))
1067  {
1068  ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
1069  }
1070  }
1071 
1072  /* If it's pending, make sure IRP is marked as such */
1073  if (RxContext != NULL)
1074  {
1075  if (RxContext->PendingReturned)
1076  {
1078  }
1079  }
1080 
1081  /* Complete now */
1082  DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
1083  IoCompleteRequest(Irp, Boost);
1084 
1085  /* If there's a context, dereference it */
1086  if (RxContext != NULL)
1087  {
1089  }
1090 }
1091 
1092 /*
1093  * @implemented
1094  */
1095 VOID
1097  IN OUT PSRV_OPEN SrvOpen)
1098 {
1099  PSRV_CALL SrvCall;
1100 
1101  SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall;
1102  /* Only handle requests if opening was a success */
1103  if (SrvOpen->Condition == Condition_Good)
1104  {
1105  KIRQL OldIrql;
1106  BOOLEAN ProcessChange;
1107  LIST_ENTRY DiscardedRequests;
1108 
1109  /* Initialize our discarded requests list */
1110  InitializeListHead(&DiscardedRequests);
1111 
1113 
1114  /* Transfer our requests in the SRV_CALL */
1115  RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList);
1116 
1117  /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1119 
1120  /* Dispatch requests and get the discarded ones */
1121  RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests);
1122 
1124 
1125  /* Is there still anything to process? */
1127  if (IsListEmpty(&SrvCall->BufferingManager.HandlerList))
1128  {
1129  ProcessChange = FALSE;
1130  }
1131  else
1132  {
1133  ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE);
1134  if (ProcessChange)
1135  {
1137  }
1138  }
1140 
1141  /* Yes? Go ahead! */
1142  if (ProcessChange)
1143  {
1144  RxReferenceSrvCall(SrvCall);
1148  }
1149 
1150  /* And discard left requests */
1151  RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
1152  }
1153  else
1154  {
1156  }
1157 }
1158 
1159 /*
1160  * @implemented
1161  */
1162 NTSTATUS
1164  IN PRX_CONTEXT RxContext,
1165  IN PSRV_CALL SrvCall,
1166  IN PNET_ROOT NetRoot,
1167  IN PV_NET_ROOT VirtualNetRoot,
1168  OUT PLOCK_HOLDING_STATE LockHoldingState)
1169 {
1170  NTSTATUS Status;
1171  PRX_PREFIX_TABLE PrefixTable;
1173  RX_BLOCK_CONDITION RootCondition, VRootCondition;
1174 
1175  PAGED_CODE();
1176 
1177  DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
1178  VirtualNetRoot, LockHoldingState);
1179 
1180  /* Validate the lock is exclusively held */
1181  PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
1182  ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1183 
1184  /* Allocate the context */
1186  if (Context == NULL)
1187  {
1189  }
1190 
1191  /* We can release lock now */
1192  RxReleasePrefixTableLock(PrefixTable);
1193  *LockHoldingState = LHS_LockNotHeld;
1194 
1195  RootCondition = Condition_Bad;
1196  VRootCondition = Condition_Bad;
1197 
1198  /* Initialize the context */
1201  Context->RxContext = RxContext;
1202  Context->pVNetRoot = VirtualNetRoot;
1203  Context->Callback = RxCreateNetRootCallBack;
1204 
1205  /* And call the mini-rdr */
1206  MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
1207  if (Status == STATUS_PENDING)
1208  {
1209  /* Wait for the mini-rdr to be done */
1211  /* Update the structures condition according to mini-rdr return */
1212  if (NT_SUCCESS(Context->NetRootStatus))
1213  {
1214  if (NT_SUCCESS(Context->VirtualNetRootStatus))
1215  {
1216  RootCondition = Condition_Good;
1217  VRootCondition = Condition_Good;
1219  }
1220  else
1221  {
1222  RootCondition = Condition_Good;
1223  Status = Context->VirtualNetRootStatus;
1224  }
1225  }
1226  else
1227  {
1228  Status = Context->VirtualNetRootStatus;
1229  if (NT_SUCCESS(Status))
1230  {
1231  Status = Context->NetRootStatus;
1232  }
1233  }
1234  }
1235  else
1236  {
1237  /* It has to return STATUS_PENDING! */
1238  ASSERT(FALSE);
1239  }
1240 
1241  /* Acquire lock again - for caller lock status will remain unchanged */
1242  ASSERT(*LockHoldingState == LHS_LockNotHeld);
1244  *LockHoldingState = LHS_ExclusiveLockHeld;
1245 
1246  /* Do the transition to the condition got from mini-rdr */
1247  RxTransitionNetRoot(NetRoot, RootCondition);
1248  RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
1249 
1250  /* Context is not longer needed */
1251  RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
1252 
1253  DPRINT("Status: %x\n", Status);
1254 
1255  return Status;
1256 }
1257 
1258 /*
1259  * @implemented
1260  */
1261 NTSTATUS
1263  IN PRX_CONTEXT RxContext,
1264  IN PSRV_CALL SrvCall,
1265  OUT PLOCK_HOLDING_STATE LockHoldingState)
1266 {
1267  NTSTATUS Status;
1268  PRX_PREFIX_TABLE PrefixTable;
1269  PRDBSS_DEVICE_OBJECT RxDeviceObject;
1270  PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1272 
1273  PAGED_CODE();
1274 
1275  DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
1276 
1277  /* Validate the lock is exclusively held */
1278  RxDeviceObject = RxContext->RxDeviceObject;
1279  PrefixTable = RxDeviceObject->pRxNetNameTable;
1280  ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1281 
1282  /* Allocate the context for mini-rdr */
1284  if (Calldown == NULL)
1285  {
1286  SrvCall->Context = NULL;
1287  SrvCall->Condition = Condition_Bad;
1288  RxReleasePrefixTableLock(PrefixTable);
1289  *LockHoldingState = LHS_LockNotHeld;
1291  }
1292 
1293  /* Initialize it */
1294  RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
1295 
1296  SrvCall->Context = NULL;
1297  SrvCall->Condition = Condition_InTransition;
1298 
1299  RxReleasePrefixTableLock(PrefixTable);
1300  *LockHoldingState = LHS_LockNotHeld;
1301 
1302  CallbackContext = &Calldown->CallbackContexts[0];
1303  DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
1304  DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
1305  CallbackContext->SrvCalldownStructure = Calldown;
1306  CallbackContext->CallbackContextOrdinal = 0;
1307  CallbackContext->RxDeviceObject = RxDeviceObject;
1308 
1309  RxReferenceSrvCall(SrvCall);
1310 
1311  /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1312  if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1313  {
1314  RxPrePostIrp(RxContext, RxContext->CurrentIrp);
1315  }
1316  else
1317  {
1319  }
1320 
1321  Calldown->NumberToWait = 1;
1322  Calldown->NumberRemaining = 1;
1323  Calldown->RxContext = RxContext;
1324  Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
1325  Calldown->CallBack = RxCreateSrvCallCallBack;
1326  Calldown->BestFinisher = NULL;
1328  InitializeListHead(&Calldown->SrvCalldownList);
1329 
1330  /* Call the mini-rdr */
1331  ASSERT(RxDeviceObject->Dispatch != NULL);
1332  ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
1333  ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
1334  Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
1335  /* It has to return STATUS_PENDING! */
1337 
1338  /* No async, start completion */
1339  if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1340  {
1342 
1343  /* Finish construction - we'll notify mini-rdr it's the winner */
1344  Status = RxFinishSrvCallConstruction(Calldown);
1345  if (!NT_SUCCESS(Status))
1346  {
1347  RxReleasePrefixTableLock(PrefixTable);
1348  *LockHoldingState = LHS_LockNotHeld;
1349  }
1350  else
1351  {
1352  ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
1353  *LockHoldingState = LHS_ExclusiveLockHeld;
1354  }
1355  }
1356 
1357  DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
1358  return Status;
1359 }
1360 
1361 /*
1362  * @implemented
1363  */
1364 NTSTATUS
1366  IN PRX_CONTEXT RxContext,
1367  IN PUNICODE_STRING CanonicalName,
1368  IN NET_ROOT_TYPE NetRootType,
1369  OUT PV_NET_ROOT *VirtualNetRootPointer,
1370  OUT PLOCK_HOLDING_STATE LockHoldingState,
1371  OUT PRX_CONNECTION_ID RxConnectionId)
1372 {
1373  NTSTATUS Status;
1374  PV_NET_ROOT VNetRoot;
1376  UNICODE_STRING LocalNetRootName, FilePathName;
1377 
1378  PAGED_CODE();
1379 
1380  ASSERT(*LockHoldingState != LHS_LockNotHeld);
1381 
1382  VNetRoot = NULL;
1384  /* Before creating the VNetRoot, try to find the appropriate connection */
1385  Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
1386  &LocalNetRootName, &FilePathName,
1387  LockHoldingState, RxConnectionId);
1388  /* Found and active */
1390  {
1391  /* We need a new VNetRoot */
1392  VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
1393  CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
1394  if (VNetRoot != NULL)
1395  {
1396  RxReferenceVNetRoot(VNetRoot);
1397  }
1398 
1399  /* Dereference previous VNetRoot */
1400  RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
1401  /* Reset and start construct (new structures will replace old ones) */
1402  RxContext->Create.pSrvCall = NULL;
1403  RxContext->Create.pNetRoot = NULL;
1404  RxContext->Create.pVNetRoot = NULL;
1405 
1406  /* Construct new NetRoot */
1407  if (VNetRoot != NULL)
1408  {
1409  Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
1410  (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
1411  if (NT_SUCCESS(Status))
1412  {
1414  }
1415  }
1416  else
1417  {
1419  }
1420  }
1421  else
1422  {
1423  /* If it failed creating the connection, leave */
1424  if (Status != STATUS_SUCCESS)
1425  {
1426  if (*LockHoldingState != LHS_LockNotHeld)
1427  {
1428  RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1429  *LockHoldingState = LHS_LockNotHeld;
1430  }
1431 
1432  *VirtualNetRootPointer = VNetRoot;
1433  DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
1434  return Status;
1435  }
1436 
1437  *LockHoldingState = LHS_ExclusiveLockHeld;
1438 
1439  VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
1441  }
1442 
1443  /* We have a non stable VNetRoot - transition it */
1444  if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
1445  {
1446  RxTransitionVNetRoot(VNetRoot, Condition);
1447  }
1448 
1449  /* If recreation failed */
1450  if (Status != STATUS_SUCCESS)
1451  {
1452  /* Dereference potential VNetRoot */
1453  if (VNetRoot != NULL)
1454  {
1455  ASSERT(*LockHoldingState != LHS_LockNotHeld);
1456  RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1457  VNetRoot = NULL;
1458  }
1459 
1460  /* Release lock */
1461  if (*LockHoldingState != LHS_LockNotHeld)
1462  {
1463  RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1464  *LockHoldingState = LHS_LockNotHeld;
1465  }
1466 
1467  /* Set NULL ptr */
1468  *VirtualNetRootPointer = VNetRoot;
1469  return Status;
1470  }
1471 
1472  /* Return the allocated VNetRoot */
1473  *VirtualNetRootPointer = VNetRoot;
1474  return Status;
1475 }
1476 
1477 /*
1478  * @implemented
1479  */
1480 PFCB
1482  IN PRX_CONTEXT RxContext,
1483  IN PV_NET_ROOT VNetRoot,
1485 {
1486  PFCB Fcb;
1487  BOOLEAN FakeFcb;
1488  PNET_ROOT NetRoot;
1491  PIO_STACK_LOCATION Stack;
1492  PRDBSS_DEVICE_OBJECT RxDeviceObject;
1493 
1494  PAGED_CODE();
1495 
1496  /* We need a decent VNetRoot */
1497  ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1498 
1499  NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1500  ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1501  ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1502 
1503  RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1504  ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1505 
1506  Stack = RxContext->CurrentIrpSp;
1507 
1508  /* Do we need to create a fake FCB? Like for renaming */
1509  FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1511  ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1512 
1515 
1516  /* Allocate the FCB */
1517  Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1518  NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1519  if (Fcb == NULL)
1520  {
1521  return NULL;
1522  }
1523 
1524  /* Initialize the FCB */
1525  Fcb->CachedNetRootType = NetRoot->Type;
1526  Fcb->RxDeviceObject = RxDeviceObject;
1527  Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1528  Fcb->VNetRoot = VNetRoot;
1529  Fcb->pNetRoot = VNetRoot->pNetRoot;
1530 
1531  InitializeListHead(&Fcb->SrvOpenList);
1532  Fcb->SrvOpenListVersion = 0;
1533 
1534  Fcb->FcbTableEntry.Path.Length = Name->Length;
1536  Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1537  RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1538  NetRoot->InnerNamePrefix.Length);
1539  RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1540 
1541  /* Copy back parameters from RxContext */
1542  if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1543  {
1545  }
1546 
1548 
1550  {
1552  }
1553 
1554  if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1555  {
1557  }
1558 
1559  Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1560  ExInitializeResourceLite(Fcb->Header.Resource);
1561 
1562  Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1563  ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1564 
1567 
1568  /* Fake FCB doesn't go in prefix table */
1569  if (FakeFcb)
1570  {
1573  DPRINT("Fake FCB: %p\n", Fcb);
1574  }
1575  else
1576  {
1577  RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1578  }
1579 
1580  RxReferenceVNetRoot(VNetRoot);
1581  InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1582 
1583  Fcb->ulFileSizeVersion = 0;
1584 
1585  DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1587 
1588  return Fcb;
1589 }
1590 
1591 /*
1592  * @implemented
1593  */
1594 PMRX_FOBX
1595 NTAPI
1597  OUT PRX_CONTEXT RxContext,
1598  IN PMRX_SRV_OPEN MrxSrvOpen)
1599 {
1600  PFCB Fcb;
1601  PFOBX Fobx;
1602  ULONG Flags;
1603  PNET_ROOT NetRoot;
1604  PSRV_OPEN SrvOpen;
1606 
1607  PAGED_CODE();
1608 
1609  SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1610  ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1611  ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1612  ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1613 
1614  Fcb = SrvOpen->Fcb;
1616  /* Can we use pre-allocated FOBX? */
1618  {
1619  Fobx = Fcb->InternalFobx;
1620  /* Call allocate to initialize the FOBX */
1622  /* Mark it used now */
1625  }
1626  else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1627  {
1628  Fobx = SrvOpen->InternalFobx;
1629  /* Call allocate to initialize the FOBX */
1631  /* Mark it used now */
1632  SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1634  }
1635  else
1636  {
1637  /* Last case, we cannot, allocate a FOBX */
1639  Flags = 0;
1640  }
1641 
1642  /* Allocation failed! */
1643  if (Fobx == NULL)
1644  {
1645  return NULL;
1646  }
1647 
1648  /* Set flags */
1649  Fobx->Flags = Flags;
1650 
1651  /* Initialize throttling */
1652  NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1653  if (NetRoot != NULL)
1654  {
1655  if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1656  {
1657  RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1658  NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1659  NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1660  }
1661  else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1662  {
1663  RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1664  NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1665  NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1666  }
1667  }
1668 
1669  /* Propagate flags fron RxContext */
1670  if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1671  {
1672  Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1673  }
1674 
1675  if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1676  {
1677  Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1678  }
1679 
1680  /* Continue init */
1681  Fobx->FobxSerialNumber = 0;
1682  Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1683  Fobx->NodeReferenceCount = 1;
1685 
1686  RxReferenceSrvOpen(SrvOpen);
1687  InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1688 
1689  InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1692 
1693  Fobx->CloseTime.QuadPart = 0;
1694  Fobx->fOpenCountDecremented = FALSE;
1695 
1696  DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1697 
1698  return (PMRX_FOBX)Fobx;
1699 }
1700 
1701 /*
1702  * @implemented
1703  */
1704 PNET_ROOT
1706  IN PSRV_CALL SrvCall,
1708  IN ULONG NetRootFlags,
1709  IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1710 {
1711  PNET_ROOT NetRoot;
1712  USHORT CaseInsensitiveLength;
1713  PRX_PREFIX_TABLE PrefixTable;
1714 
1715  DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1716 
1717  PAGED_CODE();
1718 
1719  /* We need a SRV_CALL */
1720  ASSERT(SrvCall != NULL);
1721 
1722  PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1723  ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1724 
1725  /* Get name length */
1726  CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1727  if (CaseInsensitiveLength > MAXUSHORT)
1728  {
1729  return NULL;
1730  }
1731 
1732  /* Allocate the NetRoot */
1733  NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1734  CaseInsensitiveLength);
1735  if (NetRoot == NULL)
1736  {
1737  return NULL;
1738  }
1739 
1740  /* Construct name */
1741  RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1742  Name->Buffer, Name->Length);
1743  if (SrvCall->PrefixEntry.Prefix.Length != 0)
1744  {
1745  RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1746  SrvCall->PrefixEntry.Prefix.Length);
1747  }
1748 
1750  {
1751  CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1752  }
1753  /* Inisert in prefix table */
1754  RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1755  (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1756  RxConnectionId);
1757 
1758  /* Prepare the FCB table */
1759  RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1760 
1764 
1766 
1767  NetRoot->SerialNumberForEnum = SerialNumber++;
1768  NetRoot->Flags |= NetRootFlags;
1769  NetRoot->DiskParameters.ClusterSize = 1;
1770  NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1771  NetRoot->SrvCall = SrvCall;
1772 
1773  RxReferenceSrvCall(SrvCall);
1774 
1775  DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1776  return NetRoot;
1777 }
1778 
1779 /*
1780  * @implemented
1781  */
1782 VOID
1783 NTAPI
1785  IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1786 {
1787  PAGED_CODE();
1788 
1789  KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1790 }
1791 
1792 /*
1793  * @implemented
1794  */
1796 NTAPI
1798  IN PIRP Irp,
1799  IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1800  IN ULONG InitialContextFlags)
1801 {
1802  KIRQL OldIrql;
1804 
1805  ASSERT(RxDeviceObject != NULL);
1806 
1807  DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1808 
1809 #if DBG
1811 #endif
1812  InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1813 
1814  /* Allocate the context from our lookaside list */
1815  Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1816  if (Context == NULL)
1817  {
1818  return NULL;
1819  }
1820 
1821  /* Zero it */
1822  RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1823 
1824  /* It was allocated on NP pool, keep track of it! */
1826  /* And initialize it */
1827  RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1829 
1830  /* Add it to our global list */
1832  InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1834 
1835  DPRINT("Context: %p\n", Context);
1836  return Context;
1837 }
1838 
1839 /*
1840  * @implemented
1841  */
1842 PSRV_CALL
1844  IN PRX_CONTEXT RxContext,
1846  IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1847  IN PRX_CONNECTION_ID RxConnectionId)
1848 {
1849  ULONG NameLength;
1850  PSRV_CALL SrvCall;
1851 
1852  PAGED_CODE();
1853 
1854  DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1855 
1856  ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1857 
1858  /* Get the name length */
1859  NameLength = Name->Length + 2 * sizeof(WCHAR);
1860  if (InnerNamePrefix != NULL)
1861  {
1862  NameLength += InnerNamePrefix->Length;
1863  }
1864 
1865  /* Allocate the object */
1866  SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1867  if (SrvCall == NULL)
1868  {
1869  return NULL;
1870  }
1871 
1872  /* Initialize it */
1873  SrvCall->SerialNumberForEnum = SerialNumber++;
1874  SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1879  RxInitializeSrvCallParameters(RxContext, SrvCall);
1880  RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1881  SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1882  SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1883  RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1884  SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1885 
1886  DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1887  return SrvCall;
1888 }
1889 
1890 /*
1891  * @implemented
1892  */
1893 VOID
1894 NTAPI
1897 {
1898  KIRQL OldIrql;
1899  PSRV_CALL SrvCall;
1900  PRX_CONTEXT RxContext;
1901  ULONG NumberRemaining;
1902  BOOLEAN StartDispatcher;
1903  PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1904 
1905  DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1906 
1907  /* Get our context structures */
1908  Calldown = Context->SrvCalldownStructure;
1909  SrvCall = (PSRV_CALL)Calldown->SrvCall;
1910 
1911  /* If it is a success, that's the winner */
1913  if (Context->Status == STATUS_SUCCESS)
1914  {
1915  Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1916  Calldown->BestFinisher = Context->RxDeviceObject;
1917  }
1918  NumberRemaining = --Calldown->NumberRemaining;
1919  SrvCall->Status = Context->Status;
1921 
1922  /* Still some to ask, keep going */
1923  if (NumberRemaining != 0)
1924  {
1925  return;
1926  }
1927 
1928  /* If that's not async, signal we're done */
1929  RxContext = Calldown->RxContext;
1931  {
1933  return;
1934  }
1935  /* If that's a mailslot, finish construction, no more to do */
1936  else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1937  {
1938  RxFinishSrvCallConstruction(Calldown);
1939  return;
1940  }
1941 
1942  /* Queue our finish call for delayed completion */
1943  DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1946  StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1948 
1949  /* If we have to start dispatcher, go ahead */
1950  if (StartDispatcher)
1951  {
1952  NTSTATUS Status;
1953 
1956  if (!NT_SUCCESS(Status))
1957  {
1958  /* It failed - run it manually.... */
1960  }
1961  }
1962 }
1963 
1964 /*
1965  * @implemented
1966  */
1967 PSRV_OPEN
1969  IN PV_NET_ROOT VNetRoot,
1970  IN OUT PFCB Fcb)
1971 {
1972  ULONG Flags;
1973  PSRV_OPEN SrvOpen;
1975 
1976  PAGED_CODE();
1977 
1980 
1982 
1983  _SEH2_TRY
1984  {
1985  SrvOpen = Fcb->InternalSrvOpen;
1986  /* Check whethet we have to allocate a new SRV_OPEN */
1989  !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1990  {
1991  /* Proceed */
1992  SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1994  Flags = 0;
1995  }
1996  else
1997  {
1998  /* Otherwise, just use internal one and initialize it */
1999  RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
2001  Fcb->InternalSrvOpen);
2004  }
2005 
2006  /* If SrvOpen was properly allocated, initialize it */
2007  if (SrvOpen != NULL)
2008  {
2009  SrvOpen->Flags = Flags;
2010  SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
2011  SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
2012  SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2013  SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
2014  SrvOpen->NodeReferenceCount = 1;
2015 
2016  RxReferenceVNetRoot(VNetRoot);
2018 
2019  InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
2020  ++Fcb->SrvOpenListVersion;
2021 
2024  InitializeListHead(&SrvOpen->FobxList);
2026  }
2027  }
2029  {
2031  {
2032  if (SrvOpen != NULL)
2033  {
2034  RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
2035  SrvOpen = NULL;
2036  }
2037  }
2038  else
2039  {
2040  DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
2041  }
2042  }
2043  _SEH2_END;
2044 
2045  return SrvOpen;
2046 }
2047 
2048 /*
2049  * @implemented
2050  */
2053  IN PRX_CONTEXT RxContext,
2054  IN PNET_ROOT NetRoot,
2055  IN PUNICODE_STRING CanonicalName,
2056  IN PUNICODE_STRING LocalNetRootName,
2058  IN PRX_CONNECTION_ID RxConnectionId)
2059 {
2060  NTSTATUS Status;
2061  PV_NET_ROOT VNetRoot;
2062  USHORT CaseInsensitiveLength;
2063 
2064  PAGED_CODE();
2065 
2066  DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
2067  LocalNetRootName, FilePath, RxConnectionId);
2068 
2069  /* Lock must be held exclusively */
2070  ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
2071 
2072  /* Check for overflow */
2073  if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
2074  {
2075  return NULL;
2076  }
2077 
2078  /* Get name length and allocate VNetRoot */
2079  CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2080  VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
2081  CaseInsensitiveLength);
2082  if (VNetRoot == NULL)
2083  {
2084  return NULL;
2085  }
2086 
2087  /* Initialize its connection parameters */
2088  Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
2089  &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
2090  &VNetRoot->pPassword, &VNetRoot->Flags);
2091  if (!NT_SUCCESS(Status))
2092  {
2093  RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
2094  VNetRoot->pPassword, &VNetRoot->Flags);
2095  RxFreeObject(VNetRoot);
2096 
2097  return NULL;
2098  }
2099 
2100  /* Set name */
2101  RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2102 
2103  VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2104  VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
2105  VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2106  VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2107 
2110 
2111  if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
2112  {
2113  USHORT i;
2114 
2115  if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
2116  {
2117  CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
2118  }
2119  else
2120  {
2121  CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
2122  }
2123 
2124  for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
2125  {
2126  if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
2127  {
2128  break;
2129  }
2130  }
2131 
2132  CaseInsensitiveLength += (i * sizeof(WCHAR));
2133  }
2134 
2135  /* Insert in prefix table */
2136  RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
2137  VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
2138  RxConnectionId);
2139 
2140  RxReferenceNetRoot(NetRoot);
2141  RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
2142 
2143  /* Finish init */
2144  VNetRoot->SerialNumberForEnum = SerialNumber++;
2145  VNetRoot->UpperFinalizationDone = FALSE;
2146  VNetRoot->ConnectionFinalizationDone = FALSE;
2148 
2149  DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
2150  DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
2151 
2152  return VNetRoot;
2153 }
2154 
2155 /*
2156  * @implemented
2157  */
2158 VOID
2160  IN OUT PVOID Instance,
2161  IN LOCK_HOLDING_STATE LockHoldingState)
2162 {
2163  LONG RefCount;
2166 
2167  PAGED_CODE();
2168 
2170 
2171  /* Check we have a node we can handle */
2175  (NodeType == RDBSS_NTC_FOBX));
2176 
2178  RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
2179  ASSERT(RefCount >= 0);
2180 
2181  /* Trace refcount */
2182  switch (NodeType)
2183  {
2184  case RDBSS_NTC_SRVCALL:
2185  PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
2186  break;
2187 
2188  case RDBSS_NTC_NETROOT:
2189  PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
2190  break;
2191 
2192  case RDBSS_NTC_V_NETROOT:
2193  PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
2194  break;
2195 
2196  case RDBSS_NTC_SRVOPEN:
2197  PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
2198  break;
2199 
2200  case RDBSS_NTC_FOBX:
2201  PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
2202  break;
2203 
2204  default:
2205  ASSERT(FALSE);
2206  break;
2207  }
2208 
2209  /* No need to free - still in use */
2210  if (RefCount > 1)
2211  {
2213  return;
2214  }
2215 
2216  /* We have to be locked exclusively */
2217  if (LockHoldingState != LHS_ExclusiveLockHeld)
2218  {
2219  if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
2221  {
2223  }
2224 
2226  return;
2227  }
2228  else
2229  {
2231  {
2233  }
2234  }
2235 
2237 
2238  /* Now, deallocate the memory */
2239  switch (NodeType)
2240  {
2241  case RDBSS_NTC_SRVCALL:
2242  {
2243  PSRV_CALL SrvCall;
2244 
2245  SrvCall = (PSRV_CALL)Instance;
2246 
2247  ASSERT(SrvCall->RxDeviceObject != NULL);
2248  ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
2249  RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
2250  break;
2251  }
2252 
2253  case RDBSS_NTC_NETROOT:
2254  {
2255  PNET_ROOT NetRoot;
2256 
2257  NetRoot = (PNET_ROOT)Instance;
2258 
2259  ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL);
2260  ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2261  RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2262  break;
2263  }
2264 
2265  case RDBSS_NTC_V_NETROOT:
2266  {
2267  PV_NET_ROOT VNetRoot;
2268 
2269  VNetRoot = (PV_NET_ROOT)Instance;
2270 
2271  ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL);
2272  ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2273  RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE);
2274  break;
2275  }
2276 
2277  case RDBSS_NTC_SRVOPEN:
2278  {
2279  PSRV_OPEN SrvOpen;
2280 
2281  SrvOpen = (PSRV_OPEN)Instance;
2282 
2283  ASSERT(RxIsFcbAcquired(SrvOpen->Fcb));
2284  if (SrvOpen->OpenCount == 0)
2285  {
2286  RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE);
2287  }
2288  break;
2289  }
2290 
2291  case RDBSS_NTC_FOBX:
2292  {
2293  PFOBX Fobx;
2294 
2295  Fobx = (PFOBX)Instance;
2296 
2297  ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb));
2298  RxFinalizeNetFobx(Fobx, TRUE, FALSE);
2299  break;
2300  }
2301  }
2302 }
2303 
2304 /*
2305  * @implemented
2306  */
2307 VOID
2308 NTAPI
2310  IN PRX_CONTEXT RxContext)
2311 {
2312  KIRQL OldIrql;
2313  ULONG RefCount;
2315  PRX_CONTEXT StopContext = NULL;
2316 
2317  /* Make sure we really have a context */
2319  ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
2320  RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
2321  /* If refcount is 0, start releasing stuff that needs spinlock held */
2322  if (RefCount == 0)
2323  {
2324  PRDBSS_DEVICE_OBJECT RxDeviceObject;
2325 
2326  Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
2327 
2328  /* If that's stop context from DO, remove it */
2329  RxDeviceObject = RxContext->RxDeviceObject;
2330  if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
2331  {
2332  RxDeviceObject->StartStopContext.pStopContext = NULL;
2333  }
2334  else
2335  {
2336  /* Remove it from the list */
2337  ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
2338  (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
2339  RemoveEntryList(&RxContext->ContextListEntry);
2340 
2341  /* If that was the last active context, save the stop context */
2342  if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
2343  {
2344  if (RxDeviceObject->StartStopContext.pStopContext != NULL)
2345  {
2346  StopContext = RxDeviceObject->StartStopContext.pStopContext;
2347  }
2348  }
2349  }
2350  }
2352 
2353  /* Now, deal with what can be done without spinlock held */
2354  if (RefCount == 0)
2355  {
2356  /* Refcount shouldn't have changed */
2357  ASSERT(RxContext->ReferenceCount == 0);
2358  /* Reset everything that can be */
2359  RxPrepareContextForReuse(RxContext);
2360 
2361 #ifdef RDBSS_TRACKER
2362  ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
2363 #endif
2364  /* If that was the last active, set the event */
2365  if (StopContext != NULL)
2366  {
2367  StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
2368  KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
2369  }
2370 
2371 #if DBG
2372  /* Is ShadowCrit still owned? Shouldn't happen! */
2373  if (RxContext->ShadowCritOwner != 0)
2374  {
2375  DPRINT1("ShadowCritOwner not null! %lx\n", RxContext->ShadowCritOwner);
2376  ASSERT(FALSE);
2377  }
2378 #endif
2379 
2380  /* If it was allocated, free it */
2381  if (Allocated)
2382  {
2383  ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
2384  }
2385  }
2386 }
2387 
2388 VOID
2389 NTAPI
2391  PVOID Context)
2392 {
2393  UNIMPLEMENTED;
2394 }
2395 
2396 /*
2397  * @implemented
2398  */
2399 NTSTATUS
2400 NTAPI
2402  IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
2403  IN WORK_QUEUE_TYPE WorkQueueType,
2404  IN PRX_WORKERTHREAD_ROUTINE Routine,
2405  IN PVOID pContext)
2406 {
2407  NTSTATUS Status;
2408  PRX_WORK_DISPATCH_ITEM DispatchItem;
2409 
2410  /* Allocate a bit of context */
2412  if (DispatchItem == NULL)
2413  {
2415  }
2416 
2417  /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2418  DispatchItem->DispatchRoutine = Routine;
2419  DispatchItem->DispatchRoutineParameter = pContext;
2420  DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
2421  DispatchItem->WorkQueueItem.Parameter = DispatchItem;
2422 
2423  /* Insert item */
2424  Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem);
2425  if (!NT_SUCCESS(Status))
2426  {
2427  RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
2428  DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
2429  }
2430 
2431  DPRINT("Dispatching: %p, %p\n", Routine, pContext);
2432 
2433  return Status;
2434 }
2435 
2436 /*
2437  * @implemented
2438  */
2439 VOID
2442 {
2443  PAGED_CODE();
2444 
2446 }
2447 
2448 /*
2449  * @implemented
2450  */
2451 VOID
2453  IN PUNICODE_STRING FilePathName,
2454  OUT PUNICODE_STRING SrvCallName,
2455  OUT PUNICODE_STRING RestOfName)
2456 {
2457  USHORT i, Length;
2458 
2459  PAGED_CODE();
2460 
2461  ASSERT(SrvCallName != NULL);
2462 
2463  /* SrvCall name will start from the begin up to the first separator */
2464  SrvCallName->Buffer = FilePathName->Buffer;
2465  for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
2466  {
2467  if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2468  {
2469  break;
2470  }
2471  }
2472 
2473  /* Compute length */
2474  Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
2475  SrvCallName->MaximumLength = Length;
2476  SrvCallName->Length = Length;
2477 
2478  /* Return the rest if asked */
2479  if (RestOfName != NULL)
2480  {
2481  Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
2482  RestOfName->Buffer = &FilePathName->Buffer[i];
2483  RestOfName->MaximumLength = Length;
2484  RestOfName->Length = Length;
2485  }
2486 }
2487 
2488 /*
2489  * @implemented
2490  */
2491 NTSTATUS
2493  IN OUT PRX_FCB_TABLE FcbTable,
2494  IN OUT PFCB Fcb)
2495 {
2496  PAGED_CODE();
2497 
2498  /* We deal with the table, make sure it's locked */
2499  ASSERT(RxIsFcbTableLockExclusive(FcbTable));
2500 
2501  /* Compute the hash */
2503 
2505 
2506  /* If no length, it will be our null entry */
2507  if (Fcb->FcbTableEntry.Path.Length == 0)
2508  {
2509  FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
2510  }
2511  /* Otherwise, insert in the appropriate bucket */
2512  else
2513  {
2514  InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2516  }
2517 
2518  /* Propagate the change by incrementing the version number */
2519  InterlockedIncrement((volatile long *)&FcbTable->Version);
2520 
2521  return STATUS_SUCCESS;
2522 }
2523 
2524 /*
2525  * @implemented
2526  */
2527 PFCB
2529  IN PRX_FCB_TABLE FcbTable,
2531 {
2532  PFCB Fcb;
2534 
2535  PAGED_CODE();
2536 
2537  /* No path - easy, that's null entry */
2538  if (Path == NULL)
2539  {
2540  TableEntry = FcbTable->TableEntryForNull;
2541  }
2542  else
2543  {
2544  ULONG Hash;
2545  PLIST_ENTRY HashBucket, ListEntry;
2546 
2547  /* Otherwise, compute the hash value and find the associated bucket */
2549  HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2550  /* If the bucket is empty, it means there's no entry yet */
2551  if (IsListEmpty(HashBucket))
2552  {
2553  TableEntry = NULL;
2554  }
2555  else
2556  {
2557  /* Otherwise, browse all the entry */
2558  for (ListEntry = HashBucket->Flink;
2559  ListEntry != HashBucket;
2560  ListEntry = ListEntry->Flink)
2561  {
2562  TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2563  InterlockedIncrement(&FcbTable->Compares);
2564 
2565  /* If entry hash and string are equal, thatt's the one! */
2566  if (TableEntry->HashValue == Hash &&
2567  TableEntry->Path.Length == Path->Length &&
2568  RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2569  {
2570  break;
2571  }
2572  }
2573 
2574  /* We reached the end? Not found */
2575  if (ListEntry == HashBucket)
2576  {
2577  TableEntry = NULL;
2578  }
2579  }
2580  }
2581 
2582  InterlockedIncrement(&FcbTable->Lookups);
2583 
2584  /* If table entry isn't null, return the FCB */
2585  if (TableEntry != NULL)
2586  {
2587  Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2589  }
2590  else
2591  {
2592  Fcb = NULL;
2593  InterlockedIncrement(&FcbTable->FailedLookups);
2594  }
2595 
2596  return Fcb;
2597 }
2598 
2599 /*
2600  * @implemented
2601  */
2602 NTSTATUS
2604  IN OUT PRX_FCB_TABLE FcbTable,
2605  IN OUT PFCB Fcb)
2606 {
2607  PAGED_CODE();
2608 
2610 
2611  /* If no path, then remove entry for null */
2612  if (Fcb->FcbTableEntry.Path.Length == 0)
2613  {
2614  FcbTable->TableEntryForNull = NULL;
2615  }
2616  /* Otherwise, remove from the bucket */
2617  else
2618  {
2620  }
2621 
2622  /* Reset its list entry */
2624 
2625  /* Propagate the change by incrementing the version number */
2626  InterlockedIncrement((volatile long *)&FcbTable->Version);
2627 
2628  return STATUS_SUCCESS;
2629 }
2630 
2631 /*
2632  * @implemented
2633  */
2634 NTSTATUS
2635 NTAPI
2637  IN OUT PNET_ROOT NetRoot,
2638  IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2639  IN LOGICAL ForceFilesClosed)
2640 {
2641  NTSTATUS Status;
2642  PRX_PREFIX_TABLE PrefixTable;
2643  ULONG UncleanAny, UncleanDir;
2644  LONG FilesOpen, AdditionalRef;
2645  BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
2646 
2647  PAGED_CODE();
2648 
2649  ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
2650 
2651  /* Get a BOOLEAN out of LOGICAL
2652  * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2653  */
2654  ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
2655 
2656  /* First, delete any notification change */
2658  /* If it failed, continue if forced */
2659  if (Status != STATUS_SUCCESS && !ForceFilesClosed)
2660  {
2661  return Status;
2662  }
2663  /* Reset status, in case notification deletion failed */
2665 
2666  PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2667 
2668  PrefixLocked = FALSE;
2669  FcbTableLocked = FALSE;
2670  FilesOpen = 0;
2671  AdditionalRef = 0;
2672  UncleanAny = 0;
2673  UncleanDir = 0;
2674  _SEH2_TRY
2675  {
2677  PrefixLocked = TRUE;
2678 
2679  RxReferenceNetRoot(NetRoot);
2680 
2681  RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2682  FcbTableLocked = TRUE;
2683 
2684  /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2685  if (!VNetRoot->ConnectionFinalizationDone)
2686  {
2687  USHORT Bucket;
2688  PRX_FCB_TABLE FcbTable;
2689 
2690  DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
2691 
2692  /* We'll browse all its associated FCB to check whether they're open/orphaned */
2693  FcbTable = &NetRoot->FcbTable;
2694  for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2695  {
2696  PLIST_ENTRY BucketList, Entry;
2697 
2698  BucketList = &FcbTable->HashBuckets[Bucket];
2699  Entry = BucketList->Flink;
2700  while (Entry != BucketList)
2701  {
2702  PFCB Fcb;
2703 
2704  Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
2705  Entry = Entry->Flink;
2706 
2707  /* FCB for this connection, go ahead */
2708  if (Fcb->VNetRoot == VNetRoot)
2709  {
2710  /* It's still open, and no force? Fail and keep track */
2711  if (Fcb->UncleanCount > 0 && !ForceClose)
2712  {
2715  {
2716  ++UncleanDir;
2717  }
2718  else
2719  {
2720  ++UncleanAny;
2721  }
2722  }
2723  else
2724  {
2725  /* Else, force purge */
2727 
2730 
2732 
2734  RxPurgeFcb(Fcb);
2735 
2736  /* We don't need to release FCB lock, FCB finalize will take care of it */
2737  }
2738  }
2739  }
2740  }
2741 
2742  /* No files left, our V_NET_ROOT is finalized */
2743  if (VNetRoot->NumberOfFobxs == 0)
2744  {
2745  VNetRoot->ConnectionFinalizationDone = TRUE;
2746  }
2747  }
2748 
2749  /* Keep Number of open files and track of the extra reference */
2750  FilesOpen = VNetRoot->NumberOfFobxs;
2751  AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
2752  /* If force close, caller doesn't want to keep connection alive
2753  * and wants it totally close, so drop the V_NET_ROOT too
2754  */
2755  if (ForceClose)
2756  {
2757  RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
2758  }
2759  }
2761  {
2762  /* Release what was acquired */
2763  if (FcbTableLocked)
2764  {
2765  RxReleaseFcbTableLock(&NetRoot->FcbTable);
2766  }
2767 
2768  /* If close is forced, only fix status if there are open files */
2769  if (ForceClose)
2770  {
2771  if (Status != STATUS_SUCCESS && UncleanAny != 0)
2772  {
2774  }
2775  }
2776  /* Else, fix status and fail closing if there are open files */
2777  else
2778  {
2779  if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
2780  {
2782  }
2783  }
2784 
2785  DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
2786 
2787  /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2788  * only if it was still referenced!
2789  */
2790  if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
2791  {
2792  VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2794  }
2795 
2796  if (PrefixLocked)
2797  {
2799  RxReleasePrefixTableLock(PrefixTable);
2800  }
2801  }
2802  _SEH2_END;
2803 
2804  return Status;
2805 }
2806 
2807 /*
2808  * @implemented
2809  */
2810 VOID
2812  IN OUT PRX_FCB_TABLE FcbTable)
2813 {
2814  USHORT Bucket;
2815 
2816  PAGED_CODE();
2817 
2818  /* Just delete the lock */
2819  ExDeleteResourceLite(&FcbTable->TableLock);
2820 
2821  /* And make sure (checked) that the table is really empty... */
2822  for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2823  {
2824  ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
2825  }
2826 }
2827 
2828 /*
2829  * @implemented
2830  */
2831 BOOLEAN
2833  OUT PFCB ThisFcb,
2834  IN BOOLEAN RecursiveFinalize,
2835  IN BOOLEAN ForceFinalize,
2836  IN LONG ReferenceCount)
2837 {
2838  PAGED_CODE();
2839 
2840  DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2841  DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2842 
2843  /* Make sure we have an exclusively acquired FCB */
2845  ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2846 
2847  /* We shouldn't force finalization... */
2848  ASSERT(!ForceFinalize);
2849 
2850  /* If recurisve, finalize all the associated SRV_OPEN */
2851  if (RecursiveFinalize)
2852  {
2853  PLIST_ENTRY ListEntry;
2854 
2855  for (ListEntry = ThisFcb->SrvOpenList.Flink;
2856  ListEntry != &ThisFcb->SrvOpenList;
2857  ListEntry = ListEntry->Flink)
2858  {
2859  PSRV_OPEN SrvOpen;
2860 
2861  SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2862  RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2863  }
2864  }
2865  /* If FCB is still in use, that's over */
2866  else
2867  {
2868  if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2869  {
2870  ASSERT(ReferenceCount > 0);
2871 
2872  return FALSE;
2873  }
2874  }
2875 
2876  ASSERT(ReferenceCount >= 1);
2877 
2878  /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2879  if (ReferenceCount != 1 && !ForceFinalize)
2880  {
2881  return FALSE;
2882  }
2883 
2884  ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2885 
2886  DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
2887 
2888  /* If finalization was not already initiated, go ahead */
2889  if (!ThisFcb->UpperFinalizationDone)
2890  {
2891  /* Free any FCB_LOCK */
2892  if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2893  {
2894  FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2895 
2896  while (ThisFcb->BufferedLocks.List != NULL)
2897  {
2898  PFCB_LOCK Entry;
2899 
2900  Entry = ThisFcb->BufferedLocks.List;
2901  ThisFcb->BufferedLocks.List = Entry->Next;
2902 
2903  RxFreePool(Entry);
2904  }
2905  }
2906 
2907  /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2908  if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2909  {
2910  PNET_ROOT NetRoot;
2911 
2912  NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2913 
2915  /* So, remove it */
2916  if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2917  {
2918  RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2919  }
2920  }
2921 
2922  ThisFcb->UpperFinalizationDone = TRUE;
2923  }
2924 
2925  ASSERT(ReferenceCount >= 1);
2926 
2927  /* Even if forced, don't allow broken free */
2928  if (ReferenceCount != 1)
2929  {
2930  return FALSE;
2931  }
2932 
2933  /* Now, release everything */
2934  if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2935  {
2936  RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2937  }
2938 
2939  if (ThisFcb->MRxDispatch != NULL)
2940  {
2941  ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2942  }
2943 
2944  ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2945  ExDeleteResourceLite(ThisFcb->Header.Resource);
2946  ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2947 
2948  InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2949  RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
2950 
2951  ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2952  ASSERT(!ThisFcb->fMiniInited);
2953 
2954  /* And free the object */
2955  RxFreeFcbObject(ThisFcb);
2956 
2957  return TRUE;
2958 }
2959 
2960 /*
2961  * @implemented
2962  */
2963 BOOLEAN
2965  _Out_ PFOBX ThisFobx,
2966  _In_ BOOLEAN RecursiveFinalize,
2967  _In_ BOOLEAN ForceFinalize)
2968 {
2969  PFCB Fcb;
2970  PSRV_OPEN SrvOpen;
2971 
2972  PAGED_CODE();
2973 
2974  ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
2975 
2976  /* Only finalize if forced or if there's no ref left */
2977  if (ThisFobx->NodeReferenceCount != 0 &&
2978  !ForceFinalize)
2979  {
2980  return FALSE;
2981  }
2982 
2983  DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
2984 
2985  SrvOpen = ThisFobx->SrvOpen;
2986  Fcb = SrvOpen->Fcb;
2987  /* If it wasn't finalized yet, do it */
2988  if (!ThisFobx->UpperFinalizationDone)
2989  {
2991  ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
2992 
2993  /* Remove it from the SRV_OPEN */
2994  RemoveEntryList(&ThisFobx->FobxQLinks);
2995 
2996  /* If we were used to browse a directory, free the query buffer */
2997  if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
2998  {
2999  RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
3000  }
3001 
3002  /* Notify the mini-rdr */
3004  {
3006  }
3007 
3008  /* If the SRV_OPEN wasn't closed yet, do it */
3009  if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
3010  {
3011  NTSTATUS Status;
3012 
3013  Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
3014  DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
3015  }
3016 
3017  /* Finalization done */
3018  ThisFobx->UpperFinalizationDone = TRUE;
3019  }
3020 
3021  /* If we're still referenced, don't go any further! */
3022  if (ThisFobx->NodeReferenceCount != 0)
3023  {
3024  return FALSE;
3025  }
3026 
3027  /* At that point, everything should be closed */
3028  ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
3029 
3030  /* Was the FOBX allocated with another object?
3031  * If so, mark the buffer free in said object
3032  */
3033  if (ThisFobx == Fcb->InternalFobx)
3034  {
3036  }
3037  else if (ThisFobx == SrvOpen->InternalFobx)
3038  {
3039  ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
3040  }
3041 
3042  ThisFobx->pSrvOpen = NULL;
3043 
3044  /* A FOBX less */
3045  InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
3046 
3048 
3049  /* If it wasn't allocated with another object, free the FOBX */
3050  if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
3051  {
3052  RxFreeFcbObject(ThisFobx);
3053  }
3054 
3055  return TRUE;
3056 }
3057 
3058 /*
3059  * @implemented
3060  */
3061 BOOLEAN
3063  OUT PNET_ROOT ThisNetRoot,
3064  IN BOOLEAN RecursiveFinalize,
3065  IN BOOLEAN ForceFinalize)
3066 {
3067  PSRV_CALL SrvCall;
3068  PRX_FCB_TABLE FcbTable;
3069  PRX_PREFIX_TABLE PrefixTable;
3070 
3071  PAGED_CODE();
3072 
3073  ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
3074 
3075  PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3076  ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3077 
3078  /* If sme finalization is already ongoing, leave */
3079  if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
3080  {
3081  return FALSE;
3082  }
3083 
3084  /* Mark we're finalizing */
3085  SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
3086 
3087  FcbTable = &ThisNetRoot->FcbTable;
3088  /* Did caller asked us to finalize any associated FCB? */
3089  if (RecursiveFinalize)
3090  {
3091  USHORT Bucket;
3092 
3093  /* Browse all the FCBs in our FCB table */
3095  for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
3096  {
3097  PLIST_ENTRY HashBucket, ListEntry;
3098 
3099  HashBucket = &FcbTable->HashBuckets[Bucket];
3100  ListEntry = HashBucket->Flink;
3101  while (ListEntry != HashBucket)
3102  {
3103  PFCB Fcb;
3104 
3105  Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
3107 
3108  ListEntry = ListEntry->Flink;
3109 
3110  /* If the FCB isn't orphaned, then, it's time to purge it */
3112  {
3113  NTSTATUS Status;
3114 
3117  RxPurgeFcb(Fcb);
3118  }
3119  }
3120  }
3121  RxReleaseFcbTableLock(FcbTable);
3122  }
3123 
3124  /* Only finalize if forced or if there's a single ref left */
3125  if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
3126  {
3127  return FALSE;
3128  }
3129 
3130  DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
3131 
3132  /* If we're still referenced, don't go any further! */
3133  if (ThisNetRoot->NodeReferenceCount != 1)
3134  {
3135  return FALSE;
3136  }
3137 
3138  /* Finalize the FCB table (and make sure it's empty!) */
3139  RxFinalizeFcbTable(FcbTable);
3140 
3141  /* If name wasn't remove already, do it now */
3142  if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
3143  {
3144  RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
3145  }
3146 
3147  /* Delete the object */
3148  SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
3149  RxFreeObject(ThisNetRoot);
3150 
3151  /* And dereference the associated SRV_CALL */
3152  if (SrvCall != NULL)
3153  {
3155  }
3156 
3157  return TRUE;
3158 }
3159 
3160 /*
3161  * @implemented
3162  */
3163 BOOLEAN
3165  OUT PSRV_CALL ThisSrvCall,
3166  IN BOOLEAN RecursiveFinalize,
3167  IN BOOLEAN ForceFinalize)
3168 {
3169  PRX_PREFIX_TABLE PrefixTable;
3170 
3171  PAGED_CODE();
3172 
3173  ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
3174 
3175  PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
3176  ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3177 
3178  /* Only finalize if forced or if there's a single ref left */
3179  if (ThisSrvCall->NodeReferenceCount != 1 &&
3180  !ForceFinalize)
3181  {
3182  return FALSE;
3183  }
3184 
3185  DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
3186 
3187  /* If it wasn't finalized yet, do it */
3188  if (!ThisSrvCall->UpperFinalizationDone)
3189  {
3190  BOOLEAN WillFree;
3191 
3192  /* Remove ourselves from prefix table */
3193  RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
3194 
3195  /* Remember our third arg, in case we get queued for later execution */
3196  if (ForceFinalize)
3197  {
3198  SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
3199  }
3200 
3201  /* And done */
3202  ThisSrvCall->UpperFinalizationDone = TRUE;
3203 
3204  /* Would defered execution free the object? */
3205  WillFree = (ThisSrvCall->NodeReferenceCount == 1);
3206 
3207  /* If we have a device object */
3208  if (ThisSrvCall->RxDeviceObject != NULL)
3209  {
3210  NTSTATUS Status;
3211 
3212  /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3214  {
3215  /* Extra ref, as usual */
3216  InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
3217  /* And dispatch */
3218  RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
3219 
3220  /* Return to the caller, in advance, whether we're freeing the object or not */
3221  return WillFree;
3222  }
3223 
3224  /* If in the right thread already, call the mini-rdr */
3225  MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
3226  MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
3227  (void)Status;
3228  }
3229  }
3230 
3231  /* If we're still referenced, don't go any further! */
3232  if (ThisSrvCall->NodeReferenceCount != 1)
3233  {
3234  return FALSE;
3235  }
3236 
3237  /* Don't leak */
3238  if (ThisSrvCall->pDomainName != NULL)
3239  {
3240  RxFreePool(ThisSrvCall->pDomainName);
3241  }
3242 
3243  /* And free! */
3244  RxTearDownBufferingManager(ThisSrvCall);
3245  RxFreeObject(ThisSrvCall);
3246 
3247  return TRUE;
3248 }
3249 
3250 /*
3251  * @implemented
3252  */
3253 BOOLEAN
3255  OUT PSRV_OPEN ThisSrvOpen,
3256  IN BOOLEAN RecursiveFinalize,
3257  IN BOOLEAN ForceFinalize)
3258 {
3259  PFCB Fcb;
3260 
3261  PAGED_CODE();
3262 
3263  /* We have to have a SRV_OPEN */
3264  ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
3265 
3266  /* If that's a recursive finalization, finalize any related FOBX */
3267  if (RecursiveFinalize)
3268  {
3269  PLIST_ENTRY ListEntry;
3270 
3271  ListEntry = ThisSrvOpen->FobxList.Flink;
3272  while (ListEntry != &ThisSrvOpen->FobxList)
3273  {
3274  PFOBX Fobx;
3275 
3276  Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
3277  ListEntry = ListEntry->Flink;
3278  RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
3279  }
3280  }
3281 
3282  /* If we have still references, don't finalize unless forced */
3283  if (ThisSrvOpen->NodeReferenceCount != 0 &&
3284  !ForceFinalize)
3285  {
3286  return FALSE;
3287  }
3288 
3289  DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
3290 
3291  /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3292  Fcb = (PFCB)ThisSrvOpen->pFcb;
3293  if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
3294  BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
3295  {
3296  PV_NET_ROOT VNetRoot;
3297 
3298  /* Associated FCB can't be fake one */
3301 
3302  /* Purge any pending operation */
3304 
3305  /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3307  {
3308  NTSTATUS Status;
3309 
3310  MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
3311  (void)Status;
3312  }
3313 
3314  /* Remove ourselves from the FCB */
3315  RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3316  InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
3317  ++Fcb->SrvOpenListVersion;
3318 
3319  /* If we have a V_NET_ROOT, dereference it */
3320  VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
3321  if (VNetRoot != NULL)
3322  {
3323  InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
3325  ThisSrvOpen->pVNetRoot = NULL;
3326  }
3327 
3328  /* Finalization done */
3329  ThisSrvOpen->UpperFinalizationDone = TRUE;
3330  }
3331 
3332  /* Don't free memory if still referenced */
3333  if (ThisSrvOpen->NodeReferenceCount != 0)
3334  {
3335  return FALSE;
3336  }
3337 
3338  /* No key association left */
3339  ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
3340 
3341  /* If we're still in some FCB, remove us */
3342  if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
3343  {
3344  RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3345  }
3346 
3347  /* If enclosed allocation, mark the memory zone free */
3348  if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
3349  {
3351  }
3352  /* Otherwise, free the memory */
3353  else
3354  {
3355  RxFreeFcbObject(ThisSrvOpen);
3356  }
3357 
3359 
3360  return TRUE;
3361 }
3362 
3363 /*
3364  * @implemented
3365  */
3366 BOOLEAN
3368  OUT PV_NET_ROOT ThisVNetRoot,
3369  IN BOOLEAN RecursiveFinalize,
3370  IN BOOLEAN ForceFinalize)
3371 {
3372  PNET_ROOT NetRoot;
3373  PRX_PREFIX_TABLE PrefixTable;
3374 
3375  PAGED_CODE();
3376 
3377  ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
3378 
3379  PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3380  ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3381 
3382  /* Only finalize if forced or if there's a single ref left */
3383  if (ThisVNetRoot->NodeReferenceCount != 1 &&
3384  !ForceFinalize)
3385  {
3386  return FALSE;
3387  }
3388 
3389  DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
3390 
3391  NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
3392  /* If it wasn't finalized yet, do it */
3393  if (!ThisVNetRoot->UpperFinalizationDone)
3394  {
3395  ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
3396 
3397  /* Reference the NetRoot so that it doesn't disappear */
3398  RxReferenceNetRoot(NetRoot);
3399  RxOrphanSrvOpens(ThisVNetRoot);
3400  /* Remove us from the available VNetRoot for NetRoot */
3401  RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
3402  /* Remove extra ref */
3404 
3405  /* Remove ourselves from prefix table */
3406  RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
3407 
3408  /* Finalization done */
3409  ThisVNetRoot->UpperFinalizationDone = TRUE;
3410  }
3411 
3412  /* If we're still referenced, don't go any further! */
3413  if (ThisVNetRoot->NodeReferenceCount != 1)
3414  {
3415  return FALSE;
3416  }
3417 
3418  /* If there's an associated device, notify mini-rdr */
3419  if (NetRoot->pSrvCall->RxDeviceObject != NULL)
3420  {
3421  NTSTATUS Status;
3422 
3423  MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
3424  MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
3425  (void)Status;
3426  }
3427 
3428  /* Free parameters */
3429  RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
3430  ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
3431  /* Dereference our NetRoot, we won't reference it anymore */
3433 
3434  /* And free the object! */
3435  RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
3436 
3437  return TRUE;
3438 }
3439 
3440 NTSTATUS
3442  IN PRX_CONTEXT RxContext,
3443  IN PUNICODE_STRING CanonicalName,
3444  IN NET_ROOT_TYPE NetRootType,
3446 {
3447  ULONG Flags;
3448  NTSTATUS Status;
3449  PVOID Container;
3450  BOOLEAN Construct;
3451  PV_NET_ROOT VNetRoot;
3452  RX_CONNECTION_ID ConnectionID;
3453  PRDBSS_DEVICE_OBJECT RxDeviceObject;
3454  LOCK_HOLDING_STATE LockHoldingState;
3455 
3456  PAGED_CODE();
3457 
3458  RxDeviceObject = RxContext->RxDeviceObject;
3459  ASSERT(RxDeviceObject->Dispatch != NULL);
3460  ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
3461 
3462  /* Ask the mini-rdr for connection ID */
3463  ConnectionID.SessionID = 0;
3464  if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
3465  {
3466  Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
3468  {
3469  /* mini-rdr is expected not to fail - unless it's not implemented */
3470  DPRINT1("Failed to initialize connection ID\n");
3471  ASSERT(FALSE);
3472  }
3473  }
3474 
3475  RxContext->Create.NetNamePrefixEntry = NULL;
3476 
3479  LockHoldingState = LHS_SharedLockHeld;
3480  Construct = TRUE;
3481  Flags = 0;
3482 
3483  /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3484  while (TRUE)
3485  {
3486  PNET_ROOT NetRoot;
3487  PV_NET_ROOT SavedVNetRoot;
3488 
3489  /* Look in prefix table */
3490  Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
3491  if (Container != NULL)
3492  {
3493  /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3494  if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
3495  {
3496  ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3497  RxDereferenceSrvCall(Container, LockHoldingState);
3498  }
3499  else
3500  {
3501  VNetRoot = Container;
3502  NetRoot = VNetRoot->NetRoot;
3503 
3504  /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3505  if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
3506  NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3507  {
3509  SavedVNetRoot = NULL;
3510  }
3511  else
3512  {
3513  LUID LogonId;
3514  ULONG SessionId;
3515  PUNICODE_STRING UserName, UserDomain, Password;
3516 
3517  /* We can reuse if we use same credentials */
3519  &SessionId, &UserName,
3520  &UserDomain, &Password,
3521  &Flags);
3522  if (NT_SUCCESS(Status))
3523  {
3524  SavedVNetRoot = VNetRoot;
3525  Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
3526  &LogonId, UserName,
3527  UserDomain, Password,
3528  Flags);
3530  {
3531  PLIST_ENTRY ListEntry;
3532 
3533  for (ListEntry = NetRoot->VirtualNetRoots.Flink;
3534  ListEntry != &NetRoot->VirtualNetRoots;
3535  ListEntry = ListEntry->Flink)
3536  {
3537  SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
3538  Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
3539  &LogonId, UserName,
3540  UserDomain, Password,
3541  Flags);
3543  {
3544  break;
3545  }
3546  }
3547 
3548  if (ListEntry == &NetRoot->VirtualNetRoots)
3549  {
3550  SavedVNetRoot = NULL;
3551  }
3552  }
3553 
3554  if (!NT_SUCCESS(Status))
3555  {
3556  SavedVNetRoot = NULL;
3557  }
3558 
3559  RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
3560  }
3561  }
3562 
3563  /* We'll fail, if we had referenced a VNetRoot, dereference it */
3565  {
3566  if (SavedVNetRoot == NULL)
3567  {
3568  RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3569  }
3570  }
3571  /* Reference VNetRoot we'll keep, and dereference current */
3572  else if (SavedVNetRoot != VNetRoot)
3573  {
3574  RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3575  if (SavedVNetRoot != NULL)
3576  {
3577  RxReferenceVNetRoot(SavedVNetRoot);
3578  }
3579  }
3580  }
3581 
3582  /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3584  {
3585  Construct = FALSE;
3586  break;
3587  }
3588  }
3589 
3590  /* If we're locked exclusive, we won't loop again, it was the second pass */
3591  if (LockHoldingState != LHS_SharedLockHeld)
3592  {
3593  break;
3594  }
3595 
3596  /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3598  {
3599  RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3600  LockHoldingState = LHS_ExclusiveLockHeld;
3601  break;
3602  }
3603 
3604  RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3606  LockHoldingState = LHS_ExclusiveLockHeld;
3607  }
3608 
3609  /* We didn't fail, and didn't find any VNetRoot, construct one */
3610  if (Construct)
3611  {
3612  ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
3613 
3614  Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
3615  ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
3616 
3617  if (Status == STATUS_SUCCESS)
3618  {
3619  DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
3620  DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
3621  ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
3622 
3623  RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
3624  RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
3625  RemainingName->MaximumLength = RemainingName->Length;
3626 
3628  {
3629  DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
3630  }
3631  VNetRoot->Flags |= Flags;
3632  }
3633  }
3634 
3635  /* Release the prefix table - caller expects it to be released */
3636  if (LockHoldingState != LHS_LockNotHeld)
3637  {
3638  RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3639  }
3640 
3641  /* If we failed creating, quit */
3642  if (Status != STATUS_SUCCESS)
3643  {
3644  DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
3645  return Status;
3646  }
3647 
3648  /* Otherwise, wait until the VNetRoot is stable */
3649  DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
3650  RxWaitForStableVNetRoot(VNetRoot, RxContext);
3651  /* It's all good, update the RX_CONTEXT with all our structs */
3652  if (VNetRoot->Condition == Condition_Good)
3653  {
3654  PNET_ROOT NetRoot;
3655 
3656  NetRoot = VNetRoot->NetRoot;
3657  RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3658  RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3659  RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
3660  }
3661  else
3662  {
3664  RxContext->Create.pVNetRoot = NULL;
3666  }
3667 
3668  return Status;
3669 }
3670 
3671 /*
3672  * @implemented
3673  */
3674 NTSTATUS
3676  _In_ PRX_CONTEXT RxContext,
3677  _In_ PUNICODE_STRING CanonicalName,
3678  _In_ NET_ROOT_TYPE NetRootType,
3679  _Out_ PUNICODE_STRING LocalNetRootName,
3680  _Out_ PUNICODE_STRING FilePathName,
3682  _In_ PRX_CONNECTION_ID RxConnectionId)
3683 {
3684  PVOID Container;
3685  PSRV_CALL SrvCall;
3686  PNET_ROOT NetRoot;
3687  PV_NET_ROOT VNetRoot;
3689  PRX_PREFIX_TABLE PrefixTable;
3690  UNICODE_STRING RemainingName, NetRootName;
3691 
3692  PAGED_CODE();
3693 
3694  DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3695  RxContext, CanonicalName, NetRootType, LocalNetRootName,
3696  FilePathName, LockState, RxConnectionId);
3697 
3698  *FilePathName = *CanonicalName;
3699  LocalNetRootName->Length = 0;
3700  LocalNetRootName->MaximumLength = 0;
3701  LocalNetRootName->Buffer = CanonicalName->Buffer;
3702 
3703  /* UNC path, split it */
3704  if (FilePathName->Buffer[1] == ';')
3705  {
3706  BOOLEAN Slash;
3707  USHORT i, Length;
3708 
3709  Slash = FALSE;
3710  for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
3711  {
3712  if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
3713  {
3714  Slash = TRUE;
3715  break;
3716  }
3717  }
3718 
3719  if (!Slash)
3720  {
3722  }
3723 
3724  FilePathName->Buffer = &FilePathName->Buffer[i];
3725  Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
3726  LocalNetRootName->Length = Length;
3727  LocalNetRootName->MaximumLength = Length;
3728  FilePathName->Length -= Length;
3729 
3730  DPRINT("CanonicalName: %wZ\n", CanonicalName);
3731  DPRINT(" -> FilePathName: %wZ\n", FilePathName);
3732  DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
3733  }
3734 
3735  Container = NULL;
3736  PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
3737 
3738  _SEH2_TRY
3739  {
3740 RetryLookup:
3742 
3743  /* If previous lookup left something, dereference it */
3744  if (Container != NULL)
3745  {
3746  switch (NodeType(Container))
3747  {
3748  case RDBSS_NTC_SRVCALL:
3749  RxDereferenceSrvCall(Container, *LockState);
3750  break;
3751 
3752  case RDBSS_NTC_NETROOT:
3753  RxDereferenceNetRoot(Container, *LockState);
3754  break;
3755 
3756  case RDBSS_NTC_V_NETROOT:
3757  RxDereferenceVNetRoot(Container, *LockState);
3758  break;
3759 
3760  default:
3761  /* Should never happen */
3762  ASSERT(FALSE);
3763  break;
3764  }
3765  }
3766 
3767  /* Look for our NetRoot in prefix table */
3768  Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
3769  DPRINT("Container %p for path %wZ\n", Container, FilePathName);
3770 
3771  while (TRUE)
3772  {
3773  UNICODE_STRING SrvCallName;
3774 
3775  SrvCall = NULL;
3776  NetRoot = NULL;
3777  VNetRoot = NULL;
3778 
3779  /* Assume we didn't succeed */
3780  RxContext->Create.pVNetRoot = NULL;
3781  RxContext->Create.pNetRoot = NULL;
3782  RxContext->Create.pSrvCall = NULL;
3783  RxContext->Create.Type = NetRootType;
3784 
3785  /* If we found something */
3786  if (Container != NULL)
3787  {
3788  /* A VNetRoot */
3789  if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
3790  {
3791  VNetRoot = Container;
3792  /* Use its NetRoot */
3793  NetRoot = VNetRoot->NetRoot;
3794 
3795  /* If it's not stable, wait for it to be stable */
3796  if (NetRoot->Condition == Condition_InTransition)
3797  {
3798  RxReleasePrefixTableLock(PrefixTable);
3799  DPRINT("Waiting for stable condition for: %p\n", NetRoot);
3800  RxWaitForStableNetRoot(NetRoot, RxContext);
3803 
3804  /* Now that's it's ok, retry lookup to find what we want */
3805  if (NetRoot->Condition == Condition_Good)
3806  {
3807  goto RetryLookup;
3808  }
3809  }
3810 
3811  /* Is the associated netroot good? */
3812  if (NetRoot->Condition == Condition_Good)
3813  {
3814  SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
3815 
3816  /* If it is, and SrvCall as well, then, we have our active connection */
3817  if (SrvCall->Condition == Condition_Good &&
3818  SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
3819  {
3820  RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3821  RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3822  RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3823 
3825  _SEH2_LEAVE;
3826  }
3827  }
3828 
3829  /* If VNetRoot was well constructed, it means the connection is active */
3830  if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
3831  {
3833  }
3834  else
3835  {
3836  Status = VNetRoot->ConstructionStatus;
3837  }
3838 
3839  RxDereferenceVNetRoot(VNetRoot, *LockState);
3840  _SEH2_LEAVE;
3841  }
3842  /* Can only be a SrvCall */
3843  else
3844  {
3845  ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3846  SrvCall = Container;
3847 
3848  /* Wait for the SRV_CALL to be stable */
3849  if (SrvCall->Condition == Condition_InTransition)
3850  {
3851  RxReleasePrefixTableLock(PrefixTable);
3852  DPRINT("Waiting for stable condition for: %p\n", SrvCall);
3853  RxWaitForStableSrvCall(SrvCall, RxContext);
3856 
3857  /* It went good, loop again to find what we look for */
3858  if (SrvCall->Condition == Condition_Good)
3859  {
3860  goto RetryLookup;
3861  }
3862  }
3863 
3864  /* If it's not good... */
3865  if (SrvCall->Condition != Condition_Good)
3866  {
3867  /* But SRV_CALL was well constructed, assume a connection was active */
3868  if (SrvCall->Status == STATUS_SUCCESS)
3869  {
3871  }
3872  else
3873  {
3874  Status = SrvCall->Status;
3875  }
3876 
3877  RxDereferenceSrvCall(SrvCall, *LockState);
3878  _SEH2_LEAVE;
3879  }
3880  }
3881  }
3882 
3883  /* If we found a SRV_CALL not matching our DO, quit */
3884  if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
3885  SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3886  {
3887  RxDereferenceSrvCall(SrvCall, *LockState);
3889  _SEH2_LEAVE;
3890  }
3891 
3892  /* Now, we want exclusive lock */
3893  if (*LockState == LHS_SharedLockHeld)
3894  {
3895  if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
3896  {
3897  RxReleasePrefixTableLock(PrefixTable);
3900  goto RetryLookup;
3901  }
3902 
3903  RxReleasePrefixTableLock(PrefixTable);
3905  }
3906 
3908 
3909  /* If we reach that point, we found something, no need to create something */
3910  if (Container != NULL)
3911  {
3912  break;
3913  }
3914 
3915  /* Get the name for the SRV_CALL */
3916  RxExtractServerName(FilePathName, &SrvCallName, NULL);
3917  DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
3918  /* And create the SRV_CALL */
3919  SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
3920  if (SrvCall == NULL)
3921  {
3923  _SEH2_LEAVE;
3924  }
3925 
3926  /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3927  RxReferenceSrvCall(SrvCall);
3928  RxContext->Create.pVNetRoot = NULL;
3929  RxContext->Create.pNetRoot = NULL;
3930  RxContext->Create.pSrvCall = NULL;
3931  RxContext->Create.Type = NetRootType;
3932  Container = SrvCall;
3933 
3934  /* Construct SRV_CALL, ie, use mini-rdr */
3935  Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
3937  if (Status != STATUS_SUCCESS)
3938  {
3939  DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
3941  RxDereferenceSrvCall(SrvCall, *LockState);
3942  RxReleasePrefixTableLock(PrefixTable);
3943  _SEH2_LEAVE;
3944  }
3945 
3946  /* Loop again to make use of SRV_CALL stable condition wait */
3947  }
3948 
3949  /* At that point, we have a stable SRV_CALL (either found or constructed) */
3950  ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
3951  ASSERT(NetRoot == NULL && VNetRoot == NULL);
3952  ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
3953 
3954  /* Call mini-rdr to get NetRoot name */
3955  SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
3956  /* And create the NetRoot with that name */
3957  NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
3958  if (NetRoot == NULL)
3959  {
3961  _SEH2_LEAVE;
3962  }
3963  NetRoot->Type = NetRootType;
3964 
3965  RxDereferenceSrvCall(SrvCall, *LockState);
3966 
3967  /* Finally, create the associated VNetRoot */
3968  VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
3969  if (VNetRoot == NULL)
3970  {
3971  RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
3973  _SEH2_LEAVE;
3974  }
3975  RxReferenceVNetRoot(VNetRoot);
3976 
3977  /* We're get closer! */
3978  NetRoot->Condition = Condition_InTransition;
3979  RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3980  RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3981  RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3982 
3983  /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3984  Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
3985  if (!NT_SUCCESS(Status))
3986  {
3988  DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
3989  RxDereferenceVNetRoot(VNetRoot, *LockState);
3990 
3991  RxContext->Create.pNetRoot = NULL;
3992  RxContext->Create.pVNetRoot = NULL;
3993  }
3994  else
3995  {
3996  PIO_STACK_LOCATION Stack;
3997 
3999 
4000  Stack = RxContext->CurrentIrpSp;
4002  {
4005  }
4006  }
4007  }
4009  {
4011  {
4012  if (*LockState != LHS_LockNotHeld)
4013  {
4014  RxReleasePrefixTableLock(PrefixTable);
4016  }
4017  }
4018  }
4019  _SEH2_END;
4020 
4021  DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
4022  return Status;
4023 }
4024 
4025 /*
4026  * @implemented
4027  */
4028 VOID
4029 NTAPI
4031  IN OUT PMRX_FCB Fcb,
4032  IN RX_FILE_TYPE FileType,
4033  IN PFCB_INIT_PACKET InitPacket OPTIONAL)
4034 {
4035  RX_FILE_TYPE OldType;
4036 
4037  PAGED_CODE();
4038 
4039  DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
4040 
4041  OldType = NodeType(Fcb);
4042  NodeType(Fcb) = FileType;
4043  /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
4045  {
4046  FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
4047  }
4048  /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
4049  else if (InitPacket != NULL)
4050  {
4051  FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
4052  InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
4053  InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
4054  InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
4055  InitPacket->pValidDataLength->QuadPart);
4056  }
4057 
4058  if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
4060  {
4061  /* If our FCB newly points to a file, initiliaze everything related */
4062  if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
4063 
4064  {
4065  if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
4066  {
4067  RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
4068  FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
4070 
4071  ((PFCB)Fcb)->BufferedLocks.List = NULL;
4072  ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
4073 
4074  Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
4075  }
4076  }
4077  /* If not a file, validate type */
4078  else
4079  {
4080  ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
4081  }
4082  }
4083 }
4084 
4085 /*
4086  * @implemented
4087  */
4088 NTSTATUS
4090  PMRX_SRVCALLDOWN_STRUCTURE Calldown)
4091 {
4092  NTSTATUS Status;
4093  PSRV_CALL SrvCall;
4096  PRX_PREFIX_TABLE PrefixTable;
4097 
4098  DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
4099 
4100  SrvCall = (PSRV_CALL)Calldown->SrvCall;
4101  Context = Calldown->RxContext;
4102  PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
4103 
4104  /* We have a winner, notify him */
4105  if (Calldown->BestFinisher != NULL)
4106  {
4107  DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
4108 
4109  ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
4110 
4112  MRxSrvCallWinnerNotify,
4113  ((PMRX_SRV_CALL)SrvCall, TRUE,
4115  if (Status != STATUS_SUCCESS)
4116  {
4118  }
4119  else
4120  {
4122  }
4123  }
4124  /* Otherwise, just fail our SRV_CALL */
4125  else
4126  {
4127  Status = Calldown->CallbackContexts[0].Status;
4129  }
4130 
4132  RxTransitionSrvCall(SrvCall, Condition);
4133  RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
4134 
4135  /* If async, finish it here, otherwise, caller has already finished the stuff */
4137  {
4138  DPRINT("Finishing async call\n");
4139 
4140  RxReleasePrefixTableLock(PrefixTable);
4141 
4142  /* Make sure we weren't cancelled in-between */
4144  {
4146  }
4147 
4148  /* In case that was a create, context can be reused */
4149  if (Context->MajorFunction == IRP_MJ_CREATE)
4150  {
4152  }
4153 
4154  /* If that's a failure, reset everything and return failure */
4155  if (Status != STATUS_SUCCESS)
4156  {
4157  Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
4158  if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4159  {
4160  if (Context->Info.Buffer != NULL)
4161  {
4162  RxFreePool(Context->Info.Buffer);
4163  Context->Info.Buffer = NULL;
4164  }
4165  }
4166  Context->CurrentIrp->IoStatus.Information = 0;
4167  Context->CurrentIrp->IoStatus.Status = Status;
4169  }
4170  /* Otherwise, call resume routine and done! */
4171  else
4172  {
4173  Status = Context->ResumeRoutine(Context);
4174  if (Status != STATUS_PENDING)
4175  {
4177  }
4178 
4179  DPRINT("Not completing, pending\n");
4180  }
4181  }
4182 
4184  return Status;
4185 }
4186 
4187 /*
4188  * @implemented
4189  */
4190 VOID
4191 NTAPI
4193  IN PVOID Context)
4194 {
4195  KIRQL OldIrql;
4196  BOOLEAN Direct, KeepLoop;
4197 
4198  DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
4199 
4200  /* In case of failure of starting dispatcher, context is not set
4201  * We keep track of it to fail associated SRV_CALL
4202  */
4203  Direct = (Context == NULL);
4204 
4205  /* Separated thread, loop forever */
4206  while (TRUE)
4207  {
4208  PLIST_ENTRY ListEntry;
4209  PMRX_SRVCALLDOWN_STRUCTURE Calldown;
4210 
4211  /* If there are no SRV_CALL to finalize left, just finish thread */
4214  {
4215  KeepLoop = FALSE;
4217  }
4218  /* Otherwise, get the SRV_CALL to finish construction */
4219  else
4220  {
4221  ListEntry = RemoveHeadList(&RxSrvCalldownList);
4222  KeepLoop = TRUE;
4223  }
4225 
4226  /* Nothing to do */
4227  if (!KeepLoop)
4228  {
4229  break;
4230  }
4231 
4232  /* If direct is set, reset the finisher to avoid electing a winner
4233  * and fail SRV_CALL (see upper comment)
4234  */
4235  Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
4236  if (Direct)
4237  {
4238  Calldown->BestFinisher = NULL;
4239  }
4240  /* Finish SRV_CALL construction */
4241  RxFinishSrvCallConstruction(Calldown);
4242  }
4243 }
4244 
4245 /*
4246  * @implemented
4247  */
4248 NTSTATUS
4250  IN PFCB Fcb,
4251  IN BOOLEAN SynchronizeWithLazyWriter)
4252 {
4254 
4255  PAGED_CODE();
4256 
4257  /* Deal with Cc */
4259  /* If we're asked to sync with LW, do it in case of success */
4260  if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status))
4261  {
4264  }
4265 
4266  DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status);
4267  return IoStatus.Status;
4268 }
4269 
4270 /*
4271  * @implemented
4272  */
4273 VOID
4275  PVOID Object)
4276 {
4277  PAGED_CODE();
4278 
4279  DPRINT("Freeing %p\n", Object);
4280 
4281  /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4283  {
4284  RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
4285  }
4286  /* If that's a FCB... */
4287  else if (NodeTypeIsFcb(Object))
4288  {
4289  PFCB Fcb;
4291 
4292  Fcb = (PFCB)Object;
4294 
4295  /* Delete per stream contexts */
4297 
4299 
4300  /* If there was a non-paged FCB allocated, free it */
4302  {
4303  RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
4304  }
4305 
4306  /* Free the FCB */
4307  RxFreePool(Fcb);
4308 
4309  /* Update statistics */
4311  InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
4312  }
4313 }
4314 
4315 /*
4316  * @implemented
4317  */
4318 VOID
4320  PVOID pObject)
4321 {
4322  PAGED_CODE();
4323 
4324  /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4325  if (NodeType(pObject) == RDBSS_NTC_SRVCALL)
4326  {
4327  PSRV_CALL SrvCall;
4329 
4330  SrvCall = (PSRV_CALL)pObject;
4331  DeviceObject = SrvCall->RxDeviceObject;
4332  if (DeviceObject != NULL)
4333  {
4334  if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
4335  {
4336  ASSERT(SrvCall->Context == NULL);
4337  }
4338 
4339  ASSERT(SrvCall->Context2 == NULL);
4340 
4341  SrvCall->RxDeviceObject = NULL;
4342  }
4343  }
4344  else if (NodeType(pObject) == RDBSS_NTC_NETROOT)
4345  {
4346  PNET_ROOT NetRoot;
4347 
4348  NetRoot = (PNET_ROOT)pObject;
4349  NetRoot->pSrvCall = NULL;
4350  NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000;
4351  }
4352 
4353  /* And just free the object */
4354  RxFreePool(pObject);
4355 }
4356 
4357 /*
4358  * @implemented
4359  */
4360 VOID
4362  IN OUT PSRV_CALL SrvCall,
4363  IN PSRV_OPEN SrvOpen,
4364  IN OUT PLIST_ENTRY RequestsListHead)
4365 {
4366  KIRQL OldIrql;
4367  LIST_ENTRY Discarded, *Entry;
4369 
4370  /* Dispatch any pending operation first */
4371  RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
4372 
4373  /* Then, get any entry related to our key and SRV_OPEN */
4374  KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
4375  Entry = SrvCall->BufferingManager.HandlerList.Flink;
4376  while (Entry != &SrvCall->BufferingManager.HandlerList)
4377  {
4379  Entry = Entry->Flink;
4380  if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4381  {
4382  RemoveEntryList(&Request->ListEntry);
4383  InsertTailList(RequestsListHead, &Request->ListEntry);
4384  }
4385  }
4386  KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
4387 
4388  /* Perform the same search in the last change list */
4389  Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
4390  while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
4391  {
4393  Entry = Entry->Flink;
4394  if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4395  {
4396  RemoveEntryList(&Request->ListEntry);
4397  InsertTailList(RequestsListHead, &Request->ListEntry);
4398  }
4399  }
4400 
4401  /* Discard the discarded requests */
4403 }
4404 
4405 /*
4406  * @implemented
4407  */
4410  PVOID Instance)
4411 {
4414 
4415  PAGED_CODE();
4416 
4417  /* We only handle a few object types */
4421 
4422  /* Get the device object depending on the object */
4423  switch (NodeType)
4424  {
4425  case RDBSS_NTC_FOBX:
4426  {
4427  PFOBX Fobx;
4428 
4429  Fobx = (PFOBX)Instance;
4430  DeviceObject = Fobx->RxDeviceObject;
4431  break;
4432  }
4433 
4434  case RDBSS_NTC_SRVCALL:
4435  {
4436  PSRV_CALL SrvCall;
4437 
4438  SrvCall = (PSRV_CALL)Instance;
4439  DeviceObject = SrvCall->RxDeviceObject;
4440  break;
4441  }
4442 
4443  case RDBSS_NTC_NETROOT:
4444  {
4445  PNET_ROOT NetRoot;
4446 
4447  NetRoot = (PNET_ROOT)Instance;
4448  DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
4449  break;
4450  }
4451 
4452  case RDBSS_NTC_V_NETROOT:
4453  {
4454  PV_NET_ROOT VNetRoot;
4455 
4456  VNetRoot = (PV_NET_ROOT)Instance;
4457  DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
4458  break;
4459  }
4460 
4461  case RDBSS_NTC_SRVOPEN:
4462  {
4463  PSRV_OPEN SrvOpen;
4464 
4465  SrvOpen = (PSRV_OPEN)Instance;
4466  DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
4467  break;
4468  }
4469 
4470  default:
4471  DeviceObject = NULL;
4472  break;
4473  }
4474 
4475  /* Job done */
4476  return DeviceObject;
4477 }
4478 
4479 /*
4480  * @implemented
4481  */
4482 VOID
4484  IN PFCB Fcb,
4486 {
4487  PAGED_CODE();
4488 
4489  *FileSize = Fcb->Header.FileSize.QuadPart;
4490 }
4491 
4492 /*
4493  * @implemented
4494  */
4495 PEPROCESS
4496 NTAPI
4498  VOID)
4499 {
4500  return RxData.OurProcess;
4501 }
4502 
4503 /*
4504  * @implemented
4505  */
4506 NTSTATUS
4508  PSRV_CALL SrvCall)
4509 {
4520 
4521  return STATUS_SUCCESS;
4522 }
4523 
4524 /*
4525  * @implemented
4526  */
4527 VOID
4528 NTAPI
4530  IN PIRP Irp,
4531  IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4532  IN ULONG InitialContextFlags,
4533  IN OUT PRX_CONTEXT RxContext)
4534 {
4535  PIO_STACK_LOCATION Stack;
4536 
4537  /* Initialize our various fields */
4538  RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
4539  RxContext->NodeByteSize = sizeof(RX_CONTEXT);
4540  RxContext->ReferenceCount = 1;
4541  RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
4542  RxContext->RxDeviceObject = RxDeviceObject;
4543  KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
4544  RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
4545  InitializeListHead(&RxContext->BlockedOperations);
4546  RxContext->MRxCancelRoutine = NULL;
4547  RxContext->ResumeRoutine = NULL;
4548  RxContext->Flags |= InitialContextFlags;
4549  RxContext->CurrentIrp = Irp;
4550  RxContext->LastExecutionThread = PsGetCurrentThread();
4551  RxContext->OriginalThread = RxContext->LastExecutionThread;
4552 
4553  /* If've got no IRP, mark RX_CONTEXT */
4554  if (Irp == NULL)
4555  {
4556  RxContext->CurrentIrpSp = NULL;
4557  RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
4558  RxContext->MinorFunction = 0;
4559  }
4560  else
4561  {
4562  /* Otherwise, first determine whether we are performing async operation */
4564  if (Stack->FileObject != NULL)
4565  {
4566  PFCB Fcb;
4567 
4568  Fcb = Stack->FileObject->FsContext;
4569  if (!IoIsOperationSynchronous(Irp) ||
4570  ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
4572  (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
4573  {
4574  RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4575  }
4576  }
4577 
4579  {
4580  RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4581  }
4582  if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4583  {
4584  RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4585  }
4586 
4587  /* Set proper flags if TopLevl IRP/Device */
4589  {
4590  RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
4591  }
4592  if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
4593  {
4594  RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
4595  }
4596 
4597  /* Copy stack information */
4598  RxContext->MajorFunction = Stack->MajorFunction;
4599  RxContext->MinorFunction = Stack->MinorFunction;
4600  ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4601  RxContext->CurrentIrpSp = Stack;
4602 
4603  /* If we have a FO associated, learn for more */
4604  if (Stack->FileObject != NULL)
4605  {
4606  PFCB Fcb;
4607  PFOBX Fobx;
4608 
4609  /* Get the FCB and CCB (FOBX) */
4610  Fcb = Stack->FileObject->FsContext;
4611  Fobx = Stack->FileObject->FsContext2;
4612  RxContext->pFcb = (PMRX_FCB)Fcb;
4613  if (Fcb != NULL && NodeTypeIsFcb(Fcb))
4614  {
4615  RxContext->NonPagedFcb = Fcb->NonPaged;
4616  }
4617 
4618  /* We have a FOBX, this not a DFS opening, keep track of it */
4619  if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
4620  {
4621  RxContext->pFobx = (PMRX_FOBX)Fobx;
4622  RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
4623  if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4624  {
4625  RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
4626  }
4627  }
4628  else
4629  {
4630  RxContext->pFobx = NULL;
4631  }
4632 
4633  /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4634  if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
4635  Fobx != NULL)
4636  {
4637  PV_NET_ROOT VNetRoot = NULL;
4638 
4639  if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4640  {
4641  VNetRoot = Fcb->VNetRoot;
4642  }
4643  else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
4644  {
4645  VNetRoot = (PV_NET_ROOT)Fobx;
4646  }
4647 
4648  if (VNetRoot != NULL)
4649  {
4650  RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
4651  }
4652  }
4653 
4654  /* Remember if that's a write through file */
4655  RxContext->RealDevice = Stack->FileObject->DeviceObject;
4656  if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
4657  {
4658  RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
4659  }
4660  }
4661  }
4662 
4663  if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
4664  {
4665  DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4666  RxContext, RxContext->MinorFunction, Irp,
4667  PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
4668  RxContext->SerialNumber);
4669  }
4670 }
4671 
4672 /*
4673  * @implemented
4674  */
4675 VOID
4676 NTAPI
4678  VOID)
4679 {
4680  /* Nothing to do */
4681 }
4682 
4683 /*
4684  * @implemented
4685  */
4686 NTSTATUS
4687 NTAPI
4689  VOID)
4690 {
4691  NTSTATUS Status;
4692  HANDLE ThreadHandle;
4693 
4694  PAGED_CODE();
4695 
4698 
4699  /* Set appropriate timeouts: 10s & 60s */
4700  RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4701  RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4702  RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4703  RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
4704 
4708 
4709  /* Initialize our dispatchers */
4711  if (!NT_SUCCESS(Status))
4712  {
4713  return Status;
4714  }
4715 
4717  if (!NT_SUCCESS(Status))
4718  {
4719  return Status;
4720  }
4721 
4722  /* And start them */
4730  if (NT_SUCCESS(Status))
4731  {
4732  ZwClose(ThreadHandle);
4733  }
4734 
4735  return Status;
4736 }
4737 
4738 /*
4739  * @implemented
4740  */
4741 VOID
4743  IN OUT PRX_FCB_TABLE FcbTable,
4744  IN BOOLEAN CaseInsensitiveMatch)
4745 {
4746  USHORT i;
4747 
4748  PAGED_CODE();
4749 
4750  FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
4751  FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
4752 
4753  ExInitializeResourceLite(&FcbTable->TableLock);
4754  FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4755  FcbTable->Version = 0;
4756  FcbTable->TableEntryForNull = NULL;
4757 
4758  FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
4759  for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
4760  {
4761  InitializeListHead(&FcbTable->HashBuckets[i]);
4762  }
4763 
4764  FcbTable->Lookups = 0;
4765  FcbTable->FailedLookups = 0;
4766  FcbTable->Compares = 0;
4767 }
4768 
4769 /*
4770  * @implemented
4771  */
4772 VOID
4773 NTAPI
4775  OUT PLOWIO_CONTEXT LowIoContext,
4776  IN ULONG Operation)
4777 {
4778  PRX_CONTEXT RxContext;
4779  PIO_STACK_LOCATION Stack;
4780 
4781  PAGED_CODE();
4782 
4783  RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
4784  ASSERT(LowIoContext == &RxContext->LowIoContext);
4785 
4786  Stack = RxContext->CurrentIrpSp;
4787 
4790  RxContext->LowIoContext.Operation = Operation;
4791 
4792  switch (Operation)
4793  {
4794  case LOWIO_OP_READ:
4795  case LOWIO_OP_WRITE:
4796  /* In case of RW, set a canary, to make sure these fields are properly set
4797  * they will be asserted when lowio request will be submit to mini-rdr
4798  * See LowIoSubmit()
4799  */
4800  RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
4801  RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
4802  RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
4803 
4804  /* Keep track of paging IOs */
4805  if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
4806  {
4808  }
4809  else
4810  {
4811  RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
4812  }
4813 
4814  break;
4815 
4816  case LOWIO_OP_FSCTL:
4817  case LOWIO_OP_IOCTL:
4818  /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4819  RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
4824  RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
4825  break;
4826 
4827  /* Nothing to do for these */
4828  case LOWIO_OP_SHAREDLOCK:
4830  case LOWIO_OP_UNLOCK:
4833  case LOWIO_OP_CLEAROUT:
4834  break;
4835 
4836  default:
4837  /* Should never happen */
4838  ASSERT(FALSE);
4839  break;
4840  }
4841 }
4842 
4843 /*
4844  * @implemented
4845  */
4846 VOID
4848  PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
4849 {
4850  PAGED_CODE();
4851 
4852  InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
4853  InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
4854 }
4855 
4856 /*
4857  * @implemented
4858  */
4859 NTSTATUS
4861  IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
4862 {
4863  PAGED_CODE();
4864 
4865  pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4866  pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4867 
4868  return STATUS_SUCCESS;
4869 }
4870 
4871 /*
4872  * @implemented
4873  */
4874 VOID
4876  IN OUT PRX_PREFIX_TABLE ThisTable,
4878  IN BOOLEAN CaseInsensitiveMatch)
4879 {
4880  PAGED_CODE();
4881 
4882  if (TableSize == 0)
4883  {
4885  }
4886 
4887  ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
4888  ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
4889  InitializeListHead(&ThisTable->MemberQueue);
4890  ThisTable->Version = 0;
4891  ThisTable->TableEntryForNull = NULL;
4892  ThisTable->IsNetNameTable = FALSE;
4893  ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4894  ThisTable->TableSize = TableSize;
4895 
4896  if (TableSize > 0)
4897  {
4898  USHORT i;
4899 
4900  for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
4901  {
4902  InitializeListHead(&ThisTable->HashBuckets[i]);
4903  }
4904  }
4905 }
4906 
4907 /*
4908  * @implemented
4909  */
4910 VOID
4912  PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
4913 {
4914  PAGED_CODE();
4915 
4916  InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
4917  PurgeSyncronizationContext->PurgeInProgress = FALSE;
4918 }
4919 
4920 NTSTATUS
4922  IN PRX_CONTEXT RxContext,
4923  IN OUT PSRV_CALL SrvCall)
4924 {
4925  PAGED_CODE();
4926 
4927  SrvCall->pPrincipalName = NULL;
4928 
4929  /* We only have stuff to initialize for file opening from DFS */
4930  if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
4931  {
4932  return STATUS_SUCCESS;
4933  }
4934 
4935  ASSERT(RxContext->Create.EaBuffer != NULL);
4936 
4937  UNIMPLEMENTED;
4938  return STATUS_NOT_IMPLEMENTED;
4939 }
4940 
4941 /*
4942  * @implemented
4943  */
4944 NTSTATUS
4945 NTAPI
4947  VOID)
4948 {
4949  PAGED_CODE();
4950 
4951  RxTimerInterval.QuadPart = -550000;
4957  RxTimerTickCount = 0;
4958 
4959  return STATUS_SUCCESS;
4960 }
4961 
4962 NTSTATUS
4964  PRX_CONTEXT RxContext,
4965  OUT LUID *LogonId,
4967  OUT PUNICODE_STRING *UserNamePtr,
4968  OUT PUNICODE_STRING *UserDomainNamePtr,
4969  OUT PUNICODE_STRING *PasswordPtr,
4970  OUT PULONG Flags)
4971 {
4972  NTSTATUS Status;
4974 
4975  PAGED_CODE();
4976 
4977  DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
4978  LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
4979 
4980  *UserNamePtr = NULL;
4981  *UserDomainNamePtr = NULL;
4982  *PasswordPtr = NULL;
4983  /* By default, that's not CSC instance */
4985 
4986  Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
4988  {
4989  return STATUS_ACCESS_DENIED;
4990  }
4991 
4992  /* Get LogonId */
4994  if (!NT_SUCCESS(Status))
4995  {
4996  return Status;
4997  }
4998 
4999  /* And SessionId */
5001  if (!NT_SUCCESS(Status))
5002  {
5003  return Status;
5004  }
5005 
5006  if (RxContext->Create.UserName.Buffer != NULL)
5007  {
5008  UNIMPLEMENTED;
5010  goto Leave;
5011  }
5012 
5013  /* Deal with connection credentials */
5014  if (RxContext->Create.UserDomainName.Buffer != NULL)
5015  {
5016  UNIMPLEMENTED;
5018  goto Leave;
5019  }
5020 
5021  if (RxContext->Create.Password.Buffer != NULL)
5022  {
5023  UNIMPLEMENTED;
5025  goto Leave;
5026  }
5027 
5028 Leave:
5029  if (NT_SUCCESS(Status))
5030  {
5031  /* If that's a CSC instance, mark it as such */
5032  if (RxIsThisACscAgentOpen(RxContext))
5033  {
5035  }
5036  return Status;
5037  }
5038 
5039  return Status;
5040 }
5041 
5042 /*
5043  * @implemented
5044  */
5045 VOID
5048  WORK_QUEUE_TYPE WorkQueueType,
5049  ULONG MaximumNumberOfWorkerThreads,
5050  ULONG MinimumNumberOfWorkerThreads)
5051 {
5052  PAGED_CODE();
5053 
5054  WorkQueue->Type = WorkQueueType;
5055  WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
5056  WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
5057 
5058  WorkQueue->State = RxWorkQueueActive;
5059  WorkQueue->SpinUpRequestPending = FALSE;
5060  WorkQueue->pRundownContext = NULL;
5061  WorkQueue->NumberOfWorkItemsDispatched = 0;
5062  WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
5063  WorkQueue->CumulativeQueueLength = 0;
5064  WorkQueue->NumberOfSpinUpRequests = 0;
5065  WorkQueue->NumberOfActiveWorkerThreads = 0;
5066  WorkQueue->NumberOfIdleWorkerThreads = 0;
5067  WorkQueue->NumberOfFailedSpinUpRequests = 0;
5068  WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
5069  WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
5070  WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
5071  WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
5072  WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
5073  WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
5074  WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
5075  WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
5076  WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
5077  WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
5078  WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
5079  WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
5080  WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
5081 
5082  KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
5083  KeInitializeSpinLock(&WorkQueue->SpinLock);
5084 }
5085 
5086 /*
5087  * @implemented
5088  */
5089 NTSTATUS
5091  PRX_WORK_QUEUE_DISPATCHER Dispatcher)
5092 {
5093  NTSTATUS Status;
5094  ULONG MaximumNumberOfWorkerThreads;
5095 
5096  PAGED_CODE();
5097 
5098  /* Number of threads will depend on system capacity */
5100  {
5101  MaximumNumberOfWorkerThreads = 5;
5102  }