ReactOS 0.4.15-dev-8222-g9164419
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
36VOID
39 PVOID File,
40 ULONG Line,
42
43VOID
47
51
52VOID
56
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60 WORK_QUEUE_TYPE WorkQueueType,
61 PRX_WORK_QUEUE_ITEM WorkQueueItem);
62
65 PRX_CONTEXT RxContext);
66
67VOID
71
72VOID
74 PSRV_CALL SrvCall,
75 PSRV_OPEN SrvOpen,
76 PLIST_ENTRY DiscardedRequests);
77
78VOID
82
83VOID
86 _In_ struct _KDPC *Dpc,
90
91VOID
95
101 _In_ ULONG Tag);
102
103VOID
104NTAPI
107
108VOID
109NTAPI
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 */
182NTAPI
185{
187}
188
189/*
190 * @implemented
191 */
193NTAPI
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 */
241NTAPI
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 {
268 }
269 }
270
271 return Ret;
272}
273
274VOID
275NTAPI
278{
280}
281
283NTAPI
287{
290}
291
292/*
293 * @implemented
294 */
295VOID
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 */
315PVOID
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 */
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 */
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 {
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
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 */
540PVOID
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 {
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
568 StructSize = sizeof(NET_ROOT);
570 {
571 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
572 }
573 break;
574
577 StructSize = sizeof(V_NET_ROOT);
579 {
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 {
603 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
604 Extension = &((PSRV_CALL)Object)->Context;
605 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
606 break;
607
609 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
610 Extension = &((PNET_ROOT)Object)->Context;
611 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
612 break;
613
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));
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 */
644VOID
647 PVOID File,
648 ULONG Line,
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);
698
699 /* Continue looping, so that after dump, execution can continue (with ignore) */
700 }
701}
702
703/*
704 * @implemented
705 */
706VOID
707NTAPI
710{
711 PRX_WORK_QUEUE RxWorkQueue;
712
713 PAGED_CODE();
714
715 RxWorkQueue = WorkQueue;
716 RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
717}
718
719/*
720 * @implemented
721 */
722VOID
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 */
782NTAPI
784 PSRV_OPEN SrvOpen,
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 */
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));
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 {
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) &&
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));
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
923 PRX_CONTEXT RxContext,
924 PV_NET_ROOT VNetRoot,
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 */
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! */
956}
957
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 */
995VOID
997 IN PRX_CONTEXT RxContext,
998 IN PIRP Irp,
1000{
1001 CCHAR Boost;
1002 KIRQL OldIrql;
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 */
1095VOID
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? */
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 */
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{
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 */
1263 IN PRX_CONTEXT RxContext,
1264 IN PSRV_CALL SrvCall,
1265 OUT PLOCK_HOLDING_STATE LockHoldingState)
1266{
1268 PRX_PREFIX_TABLE PrefixTable;
1269 PRDBSS_DEVICE_OBJECT RxDeviceObject;
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;
1326 Calldown->BestFinisher = NULL;
1329
1330 /* Call the mini-rdr */
1331 ASSERT(RxDeviceObject->Dispatch != NULL);
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 */
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 */
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{
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 {
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 */
1480PFCB
1482 IN PRX_CONTEXT RxContext,
1483 IN PV_NET_ROOT VNetRoot,
1485{
1486 PFCB Fcb;
1487 BOOLEAN FakeFcb;
1488 PNET_ROOT NetRoot;
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;
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
1584
1585 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1587
1588 return Fcb;
1589}
1590
1591/*
1592 * @implemented
1593 */
1595NTAPI
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));
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;
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 */
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;
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 */
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 */
1782VOID
1783NTAPI
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 */
1796NTAPI
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 */
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 */
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 */
1893VOID
1894NTAPI
1897{
1898 KIRQL OldIrql;
1899 PSRV_CALL SrvCall;
1900 PRX_CONTEXT RxContext;
1901 ULONG NumberRemaining;
1902 BOOLEAN StartDispatcher;
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 */
1937 {
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 {
1953
1956 if (!NT_SUCCESS(Status))
1957 {
1958 /* It failed - run it manually.... */
1960 }
1961 }
1962}
1963
1964/*
1965 * @implemented
1966 */
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,
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{
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;
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 */
2158VOID
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 */
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
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
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
2299 break;
2300 }
2301 }
2302}
2303
2304/*
2305 * @implemented
2306 */
2307VOID
2308NTAPI
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
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
2388VOID
2389NTAPI
2391 PVOID Context)
2392{
2394}
2395
2396/*
2397 * @implemented
2398 */
2400NTAPI
2402 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
2403 IN WORK_QUEUE_TYPE WorkQueueType,
2405 IN PVOID pContext)
2406{
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 */
2439VOID
2442{
2443 PAGED_CODE();
2444
2446}
2447
2448/*
2449 * @implemented
2450 */
2451VOID
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 */
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 */
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 */
2527PFCB
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 */
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 */
2635NTAPI
2637 IN OUT PNET_ROOT NetRoot,
2638 IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2639 IN LOGICAL ForceFilesClosed)
2640{
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 */
2810VOID
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 */
2831BOOLEAN
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 */
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 {
2899
2900 Entry = ThisFcb->BufferedLocks.List;
2901 ThisFcb->BufferedLocks.List = Entry->Next;
2902
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 */
2963BOOLEAN
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 {
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 {
3012
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 */
3061BOOLEAN
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 */
3080 {
3081 return FALSE;
3082 }
3083
3084 /* Mark we're finalizing */
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 {
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 */
3163BOOLEAN
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 {
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 */
3253BOOLEAN
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 {
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 */
3366BOOLEAN
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 {
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
3442 IN PRX_CONTEXT RxContext,
3443 IN PUNICODE_STRING CanonicalName,
3444 IN NET_ROOT_TYPE NetRootType,
3446{
3447 ULONG Flags;
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);
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;
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 {
3600 LockHoldingState = LHS_ExclusiveLockHeld;
3601 break;
3602 }
3603
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 {
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 */
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 {
3740RetryLookup:
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
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
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);
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
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 {
3890 }
3891
3892 /* Now, we want exclusive lock */
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 {
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);
3942 RxReleasePrefixTableLock(PrefixTable);
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 {
3962 }
3963 NetRoot->Type = NetRootType;
3964
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);
3974 }
3975 RxReferenceVNetRoot(VNetRoot);
3976
3977 /* We're get closer! */
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 {
3997
3999
4000 Stack = RxContext->CurrentIrpSp;
4001 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
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 */
4028VOID
4029NTAPI
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);
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
4060 {
4061 /* If our FCB newly points to a file, initiliaze everything related */
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 {
4081 }
4082 }
4083}
4084
4085/*
4086 * @implemented
4087 */
4091{
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
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 */
4190VOID
4191NTAPI
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;
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 */
4242 }
4243}
4244
4245/*
4246 * @implemented
4247 */
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 */
4273VOID
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 */
4318VOID
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 */
4326 {
4327 PSRV_CALL SrvCall;
4329
4330 SrvCall = (PSRV_CALL)pObject;
4331 DeviceObject = SrvCall->RxDeviceObject;
4332 if (DeviceObject != NULL)
4333 {
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 */
4355}
4356
4357/*
4358 * @implemented
4359 */
4360VOID
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 */
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;
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
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:
4472 break;
4473 }
4474
4475 /* Job done */
4476 return DeviceObject;
4477}
4478
4479/*
4480 * @implemented
4481 */
4482VOID
4484 IN PFCB Fcb,
4486{
4487 PAGED_CODE();
4488
4489 *FileSize = Fcb->Header.FileSize.QuadPart;
4490}
4491
4492/*
4493 * @implemented
4494 */
4496NTAPI
4498 VOID)
4499{
4500 return RxData.OurProcess;
4501}
4502
4503/*
4504 * @implemented
4505 */
4508 PSRV_CALL SrvCall)
4509{
4520
4521 return STATUS_SUCCESS;
4522}
4523
4524/*
4525 * @implemented
4526 */
4527VOID
4528NTAPI
4530 IN PIRP Irp,
4531 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4532 IN ULONG InitialContextFlags,
4533 IN OUT PRX_CONTEXT RxContext)
4534{
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;
4570 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
4571 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
4572 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
4573 {
4574 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4575 }
4576 }
4577
4578 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
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 */
4675VOID
4676NTAPI
4678 VOID)
4679{
4680 /* Nothing to do */
4681}
4682
4683/*
4684 * @implemented
4685 */
4687NTAPI
4689 VOID)
4690{
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;
4703 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
4704
4708
4709 /* Initialize our dispatchers */