[RXCE]
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <dfs.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 VOID
37 RxAssert(
38 PVOID Assert,
39 PVOID File,
40 ULONG Line,
41 PVOID Message);
42
43 VOID
44 NTAPI
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context);
47
48 NTSTATUS
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown);
51
52 VOID
53 NTAPI
54 RxFinishSrvCallConstructionDispatcher(
55 IN PVOID Context);
56
57 NTSTATUS
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60 WORK_QUEUE_TYPE WorkQueueType,
61 PRX_WORK_DISPATCH_ITEM DispatchItem);
62
63 PVOID
64 RxNewMapUserBuffer(
65 PRX_CONTEXT RxContext);
66
67 VOID
68 NTAPI
69 RxWorkItemDispatcher(
70 PVOID Context);
71
72 extern ULONG ReadAheadGranularity;
73
74 volatile LONG RxNumberOfActiveFcbs = 0;
75 ULONG SerialNumber = 1;
76 PVOID RxNull = NULL;
77 volatile ULONG RxContextSerialNumberCounter;
78 BOOLEAN RxStopOnLoudCompletion = TRUE;
79 BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
80 LIST_ENTRY RxSrvCalldownList;
81 RX_SPIN_LOCK RxStrucSupSpinLock;
82 ULONG RdbssReferenceTracingValue;
83 LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
84 LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
85 RX_DISPATCHER RxDispatcher;
86 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
87 FAST_MUTEX RxLowIoPagingIoSyncMutex;
88 BOOLEAN RxContinueFromAssert = TRUE;
89 #if DBG
90 BOOLEAN DumpDispatchRoutine = TRUE;
91 #else
92 BOOLEAN DumpDispatchRoutine = FALSE;
93 #endif
94
95 #ifdef ASSERT
96 #undef ASSERT
97 #endif
98
99 #define ASSERT(exp) \
100 if (!(exp)) \
101 { \
102 RxAssert(#exp, __FILE__, __LINE__, NULL); \
103 }
104
105 /* FUNCTIONS ****************************************************************/
106
107 /*
108 * @implemented
109 */
110 VOID
111 RxAddVirtualNetRootToNetRoot(
112 PNET_ROOT NetRoot,
113 PV_NET_ROOT VNetRoot)
114 {
115 PAGED_CODE();
116
117 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
118
119 /* Insert in the VNetRoot list - make sure lock is held */
120 ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
121
122 VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
123 ++NetRoot->NumberOfVirtualNetRoots;
124 InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
125 }
126
127 /*
128 * @implemented
129 */
130 PVOID
131 RxAllocateFcbObject(
132 PRDBSS_DEVICE_OBJECT RxDeviceObject,
133 NODE_TYPE_CODE NodeType,
134 POOL_TYPE PoolType,
135 ULONG NameSize,
136 PVOID AlreadyAllocatedObject)
137 {
138 PFCB Fcb;
139 PFOBX Fobx;
140 PSRV_OPEN SrvOpen;
141 PVOID Buffer, PAPNBuffer;
142 PNON_PAGED_FCB NonPagedFcb;
143 PMINIRDR_DISPATCH Dispatch;
144 ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
145
146 PAGED_CODE();
147
148 Dispatch = RxDeviceObject->Dispatch;
149
150 NonPagedSize = 0;
151 FobxSize = 0;
152 SrvOpenSize = 0;
153 FcbSize = 0;
154
155 Fcb = NULL;
156 Fobx = NULL;
157 SrvOpen = NULL;
158 NonPagedFcb = NULL;
159 PAPNBuffer = NULL;
160
161 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
162 if (NodeType == RDBSS_NTC_FOBX)
163 {
164 FobxSize = sizeof(FOBX);
165 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
166 {
167 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
168 }
169 }
170 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
171 else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
172 {
173 SrvOpenSize = sizeof(SRV_OPEN);
174 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
175 {
176 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
177 }
178
179 FobxSize = sizeof(FOBX);
180 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
181 {
182 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
183 }
184 }
185 /* Otherwise, we're asked to allocate a FCB */
186 else
187 {
188 /* So, allocate the FCB and its extension if asked */
189 FcbSize = sizeof(FCB);
190 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
191 {
192 FcbSize += QuadAlign(Dispatch->MRxFcbSize);
193 }
194
195 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
196 * Otherwise, it will be allocated later on, specifically
197 */
198 if (PoolType == NonPagedPool)
199 {
200 NonPagedSize = sizeof(NON_PAGED_FCB);
201 }
202
203 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
204 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
205 {
206 SrvOpenSize = sizeof(SRV_OPEN);
207 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
208 {
209 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
210 }
211
212 FobxSize = sizeof(FOBX);
213 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
214 {
215 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
216 }
217 }
218 }
219
220 /* If we already have a buffer, go ahead */
221 if (AlreadyAllocatedObject != NULL)
222 {
223 Buffer = AlreadyAllocatedObject;
224 }
225 /* Otherwise, allocate it */
226 else
227 {
228 Buffer = ExAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
229 if (Buffer == NULL)
230 {
231 return NULL;
232 }
233 }
234
235 /* Now, get the pointers - FOBX is easy */
236 if (NodeType == RDBSS_NTC_FOBX)
237 {
238 Fobx = Buffer;
239 }
240 /* SRV_OPEN first, FOBX next */
241 else if (NodeType == RDBSS_NTC_SRVOPEN)
242 {
243 SrvOpen = Buffer;
244 Fobx = Add2Ptr(Buffer, SrvOpenSize);
245 }
246 else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
247 {
248 SrvOpen = Buffer;
249 }
250 else
251 {
252 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
253 Fcb = Buffer;
254 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
255 {
256 SrvOpen = Add2Ptr(Buffer, FcbSize);
257 Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
258 }
259
260 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
261 if (PoolType != NonPagedPool)
262 {
263 NonPagedFcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
264 if (NonPagedFcb == NULL)
265 {
266 ExFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
267 return NULL;
268 }
269
270 PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
271 }
272 /* Otherwise, just point at the right place in what has been allocated previously */
273 else
274 {
275 NonPagedFcb = Add2Ptr(Fobx, FobxSize);
276 PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
277 }
278 }
279
280 /* If we have allocated a SRV_OPEN, initialize it */
281 if (SrvOpen != NULL)
282 {
283 ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
284
285 if (NodeType == RDBSS_NTC_SRVOPEN)
286 {
287 SrvOpen->InternalFobx = Fobx;
288 }
289 else
290 {
291 SrvOpen->InternalFobx = NULL;
292 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
293 }
294
295 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
296 {
297 SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
298 }
299
300 InitializeListHead(&SrvOpen->SrvOpenQLinks);
301 }
302
303 /* If we have allocated a FOBX, initialize it */
304 if (Fobx != NULL)
305 {
306 ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
307
308 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
309 {
310 Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
311 }
312 }
313
314 /* If we have allocated a FCB, initialize it */
315 if (Fcb != NULL)
316 {
317 ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
318
319 Fcb->NonPaged = NonPagedFcb;
320 ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
321 Fcb->CopyOfNonPaged = NonPagedFcb;
322 NonPagedFcb->FcbBackPointer = Fcb;
323
324 Fcb->InternalSrvOpen = SrvOpen;
325 Fcb->InternalFobx = Fobx;
326
327 Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
328 Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
329 Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
330
331 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
332 {
333 Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
334 }
335
336 ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
337
338 InterlockedIncrement(&RxNumberOfActiveFcbs);
339 InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
340
341 ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
342 FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
343 }
344
345 return Buffer;
346 }
347
348 /*
349 * @implemented
350 */
351 PVOID
352 RxAllocateObject(
353 NODE_TYPE_CODE NodeType,
354 PMINIRDR_DISPATCH MRxDispatch,
355 ULONG NameLength)
356 {
357 ULONG Tag, ObjectSize;
358 PVOID Object, *Extension;
359 PRX_PREFIX_ENTRY PrefixEntry;
360 USHORT StructSize, ExtensionSize;
361
362 PAGED_CODE();
363
364 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
365 ExtensionSize = 0;
366 switch (NodeType)
367 {
368 case RDBSS_NTC_SRVCALL:
369 Tag = RX_SRVCALL_POOLTAG;
370 StructSize = sizeof(SRV_CALL);
371 if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
372 {
373 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
374 }
375 break;
376
377 case RDBSS_NTC_NETROOT:
378 Tag = RX_NETROOT_POOLTAG;
379 StructSize = sizeof(NET_ROOT);
380 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
381 {
382 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
383 }
384 break;
385
386 case RDBSS_NTC_V_NETROOT:
387 Tag = RX_V_NETROOT_POOLTAG;
388 StructSize = sizeof(V_NET_ROOT);
389 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
390 {
391 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
392 }
393 break;
394
395 default:
396 ASSERT(FALSE);
397 break;
398 }
399
400 /* Now, allocate the object */
401 ObjectSize = ExtensionSize + StructSize + NameLength;
402 Object = ExAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
403 if (Object == NULL)
404 {
405 return NULL;
406 }
407 /* Initialize it */
408 ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
409
410 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
411 switch (NodeType)
412 {
413 case RDBSS_NTC_SRVCALL:
414 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
415 Extension = &((PSRV_CALL)Object)->Context;
416 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
417 break;
418
419 case RDBSS_NTC_NETROOT:
420 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
421 Extension = &((PNET_ROOT)Object)->Context;
422 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
423 break;
424
425 case RDBSS_NTC_V_NETROOT:
426 PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
427 Extension = &((PV_NET_ROOT)Object)->Context;
428 break;
429
430 default:
431 ASSERT(FALSE);
432 break;
433 }
434
435 /* Set the prefix table unicode string */
436 RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
437 PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
438 PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
439 PrefixEntry->Prefix.Length = NameLength;
440 PrefixEntry->Prefix.MaximumLength = NameLength;
441 PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
442
443 /* Return the extension if we are asked to manage it */
444 if (ExtensionSize != 0)
445 {
446 *Extension = Add2Ptr(Object, StructSize);
447 }
448
449 return Object;
450 }
451
452 /*
453 * @implemented
454 */
455 VOID
456 RxAssert(
457 PVOID Assert,
458 PVOID File,
459 ULONG Line,
460 PVOID Message)
461 {
462 CHAR Response[2];
463 CONTEXT Context;
464
465 /* If we're not asked to continue, just stop the system */
466 if (!RxContinueFromAssert)
467 {
468 KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
469 }
470
471 /* Otherwise, capture context to offer the user to dump it */
472 RtlCaptureContext(&Context);
473
474 /* Loop until the user hits 'i' */
475 while (TRUE)
476 {
477 /* If no file provided, use empty name */
478 if (File == NULL)
479 {
480 File = "";
481 }
482
483 /* If no message provided, use empty one */
484 if (Message == NULL)
485 {
486 Message = "";
487 }
488
489 /* Display the message */
490 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
491 /* And ask the user */
492 DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
493 /* If he asks for ignore, quit
494 * In case of invalid input, ask again
495 */
496 if (Response[0] != 'B' && Response[0] != 'b')
497 {
498 if (Response[0] == 'I' || Response[0] == 'i')
499 {
500 return;
501 }
502
503 continue;
504 }
505
506 /* Break: offer the user to dump the context and break */
507 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
508 DbgBreakPoint();
509
510 /* Continue looping, so that after dump, execution can continue (with ignore) */
511 }
512 }
513
514 /*
515 * @implemented
516 */
517 VOID
518 NTAPI
519 RxBootstrapWorkerThreadDispatcher(
520 IN PVOID WorkQueue)
521 {
522 PRX_WORK_QUEUE RxWorkQueue;
523
524 PAGED_CODE();
525
526 RxWorkQueue = WorkQueue;
527 RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
528 }
529
530 NTSTATUS
531 RxCheckVNetRootCredentials(
532 PRX_CONTEXT RxContext,
533 PV_NET_ROOT VNetRoot,
534 PLUID LogonId,
535 PUNICODE_STRING UserName,
536 PUNICODE_STRING UserDomain,
537 PUNICODE_STRING Password,
538 ULONG Flags)
539 {
540 PAGED_CODE();
541
542 /* If that's a UNC name, there's nothing to process */
543 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
544 (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
545 Flags != 0))
546 {
547 return STATUS_MORE_PROCESSING_REQUIRED;
548 }
549
550 /* Compare the logon ID in the VNetRoot with the one provided */
551 if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
552 {
553 return STATUS_MORE_PROCESSING_REQUIRED;
554 }
555
556 /* No credential provided? That's OK */
557 if (UserName == NULL && UserDomain == NULL && Password == NULL)
558 {
559 return STATUS_SUCCESS;
560 }
561
562 /* Left to do! */
563 UNIMPLEMENTED;
564 return STATUS_NOT_IMPLEMENTED;
565 }
566
567 NTSTATUS
568 RxCompleteRequest(
569 PRX_CONTEXT Context,
570 NTSTATUS Status)
571 {
572 PIRP Irp;
573
574 PAGED_CODE();
575
576 DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
577
578 ASSERT(Context != NULL);
579 ASSERT(Context->CurrentIrp != NULL);
580 Irp = Context->CurrentIrp;
581
582 /* Debug what the caller asks for */
583 if (Context->LoudCompletionString != NULL)
584 {
585 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
586 /* Does the user asks to stop on failed completion */
587 if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
588 {
589 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
590 }
591 }
592
593 /* Complete for real */
594 Context->CurrentIrp = NULL;
595 RxCompleteRequest_Real(Context, Irp, Status);
596
597 DPRINT("Status: %lx\n", Status);
598 return Status;
599 }
600
601 /*
602 * @implemented
603 */
604 VOID
605 RxCompleteRequest_Real(
606 IN PRX_CONTEXT RxContext,
607 IN PIRP Irp,
608 IN NTSTATUS Status)
609 {
610 CCHAR Boost;
611 KIRQL OldIrql;
612 PIO_STACK_LOCATION Stack;
613
614 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
615
616 /* Nothing to complete, just free context */
617 if (Irp == NULL)
618 {
619 DPRINT("NULL IRP for %p\n", RxContext);
620 if (RxContext != NULL)
621 {
622 RxDereferenceAndDeleteRxContext_Real(RxContext);
623 }
624
625 return;
626 }
627
628 /* Remove cancel routine */
629 IoAcquireCancelSpinLock(&OldIrql);
630 IoSetCancelRoutine(Irp, NULL);
631 IoReleaseCancelSpinLock(OldIrql);
632
633 /* Select the boost, given the success/paging operation */
634 if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
635 {
636 Boost = IO_DISK_INCREMENT;
637 }
638 else
639 {
640 Irp->IoStatus.Information = 0;
641 Boost = IO_NO_INCREMENT;
642 }
643 Irp->IoStatus.Status = Status;
644
645 if (RxContext != NULL)
646 {
647 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
648 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
649 {
650 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
651 RxContext->MinorFunction, RxContext, Irp,
652 Status, Irp->IoStatus.Information, RxContext->SerialNumber);
653 }
654 }
655
656 /* If that's an opening, there might be a canonical name allocated,
657 * if completion isn't pending, release it
658 */
659 Stack = IoGetCurrentIrpStackLocation(Irp);
660 if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
661 RxContext != NULL)
662 {
663 if (BooleanFlagOn(RxContext->Create.Flags, 2))
664 {
665 Stack->FileObject->FileName.Length += sizeof(WCHAR);
666 }
667
668 RxpPrepareCreateContextForReuse(RxContext);
669 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
670 }
671
672 /* If it's a write, validate the correct behavior of the operation */
673 if (Stack->MajorFunction == IRP_MJ_WRITE)
674 {
675 if (NT_SUCCESS(Irp->IoStatus.Status))
676 {
677 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
678 }
679 }
680
681 /* If it's pending, make sure IRP is marked as such */
682 if (RxContext != NULL)
683 {
684 if (RxContext->PendingReturned)
685 {
686 ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
687 }
688 }
689
690 /* Complete now */
691 DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
692 IoCompleteRequest(Irp, Boost);
693
694 /* If there's a context, dereference it */
695 if (RxContext != NULL)
696 {
697 RxDereferenceAndDeleteRxContext_Real(RxContext);
698 }
699 }
700
701 VOID
702 RxCompleteSrvOpenKeyAssociation(
703 IN OUT PSRV_OPEN SrvOpen)
704 {
705 UNIMPLEMENTED;
706 }
707
708 /*
709 * @implemented
710 */
711 NTSTATUS
712 RxConstructNetRoot(
713 IN PRX_CONTEXT RxContext,
714 IN PSRV_CALL SrvCall,
715 IN PNET_ROOT NetRoot,
716 IN PV_NET_ROOT VirtualNetRoot,
717 OUT PLOCK_HOLDING_STATE LockHoldingState)
718 {
719 NTSTATUS Status;
720 PRX_PREFIX_TABLE PrefixTable;
721 PMRX_CREATENETROOT_CONTEXT Context;
722 RX_BLOCK_CONDITION RootCondition, VRootCondition;
723
724 PAGED_CODE();
725
726 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
727 VirtualNetRoot, LockHoldingState);
728
729 /* Validate the lock is exclusively held */
730 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
731 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
732
733 /* Allocate the context */
734 Context = ExAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
735 if (Context == NULL)
736 {
737 return STATUS_INSUFFICIENT_RESOURCES;
738 }
739
740 /* We can release lock now */
741 RxReleasePrefixTableLock(PrefixTable);
742 *LockHoldingState = LHS_LockNotHeld;
743
744 RootCondition = Condition_Bad;
745 VRootCondition = Condition_Bad;
746
747 /* Initialize the context */
748 RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
749 KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
750 Context->RxContext = RxContext;
751 Context->pVNetRoot = VirtualNetRoot;
752 Context->Callback = RxCreateNetRootCallBack;
753
754 /* And call the mini-rdr */
755 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
756 if (Status == STATUS_PENDING)
757 {
758 /* Wait for the mini-rdr to be done */
759 KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
760 /* Update the structures condition according to mini-rdr return */
761 if (NT_SUCCESS(Context->NetRootStatus))
762 {
763 if (NT_SUCCESS(Context->VirtualNetRootStatus))
764 {
765 RootCondition = Condition_Good;
766 VRootCondition = Condition_Good;
767 Status = STATUS_SUCCESS;
768 }
769 else
770 {
771 RootCondition = Condition_Good;
772 Status = Context->VirtualNetRootStatus;
773 }
774 }
775 else
776 {
777 Status = Context->VirtualNetRootStatus;
778 if (NT_SUCCESS(Status))
779 {
780 Status = Context->NetRootStatus;
781 }
782 }
783 }
784 else
785 {
786 /* It has to return STATUS_PENDING! */
787 ASSERT(FALSE);
788 }
789
790 /* Acquire lock again - for caller lock status will remain unchanged */
791 ASSERT(*LockHoldingState == LHS_LockNotHeld);
792 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
793 *LockHoldingState = LHS_ExclusiveLockHeld;
794
795 /* Do the transition to the condition got from mini-rdr */
796 RxTransitionNetRoot(NetRoot, RootCondition);
797 RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
798
799 /* Context is not longer needed */
800 ExFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
801
802 DPRINT("Status: %x\n", Status);
803
804 return Status;
805 }
806
807 /*
808 * @implemented
809 */
810 NTSTATUS
811 RxConstructSrvCall(
812 IN PRX_CONTEXT RxContext,
813 IN PSRV_CALL SrvCall,
814 OUT PLOCK_HOLDING_STATE LockHoldingState)
815 {
816 NTSTATUS Status;
817 PRX_PREFIX_TABLE PrefixTable;
818 PRDBSS_DEVICE_OBJECT RxDeviceObject;
819 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
820 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
821
822 PAGED_CODE();
823
824 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
825
826 /* Validate the lock is exclusively held */
827 RxDeviceObject = RxContext->RxDeviceObject;
828 PrefixTable = RxDeviceObject->pRxNetNameTable;
829 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
830
831 /* Allocate the context for mini-rdr */
832 Calldown = ExAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
833 if (Calldown == NULL)
834 {
835 SrvCall->Context = NULL;
836 SrvCall->Condition = Condition_Bad;
837 RxReleasePrefixTableLock(PrefixTable);
838 *LockHoldingState = LHS_LockNotHeld;
839 return STATUS_INSUFFICIENT_RESOURCES;
840 }
841
842 /* Initialize it */
843 RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
844
845 SrvCall->Context = NULL;
846 SrvCall->Condition = Condition_InTransition;
847
848 RxReleasePrefixTableLock(PrefixTable);
849 *LockHoldingState = LHS_LockNotHeld;
850
851 CallbackContext = &Calldown->CallbackContexts[0];
852 DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
853 DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
854 CallbackContext->SrvCalldownStructure = Calldown;
855 CallbackContext->CallbackContextOrdinal = 0;
856 CallbackContext->RxDeviceObject = RxDeviceObject;
857
858 RxReferenceSrvCall(SrvCall);
859
860 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
861 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
862 {
863 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
864 }
865 else
866 {
867 KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
868 }
869
870 Calldown->NumberToWait = 1;
871 Calldown->NumberRemaining = 1;
872 Calldown->RxContext = RxContext;
873 Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
874 Calldown->CallBack = RxCreateSrvCallCallBack;
875 Calldown->BestFinisher = NULL;
876 CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
877 InitializeListHead(&Calldown->SrvCalldownList);
878
879 /* Call the mini-rdr */
880 ASSERT(RxDeviceObject->Dispatch != NULL);
881 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
882 ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
883 Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
884 /* It has to return STATUS_PENDING! */
885 ASSERT(Status == STATUS_PENDING);
886
887 /* No async, start completion */
888 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
889 {
890 KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
891
892 /* Finish construction - we'll notify mini-rdr it's the winner */
893 Status = RxFinishSrvCallConstruction(Calldown);
894 if (!NT_SUCCESS(Status))
895 {
896 RxReleasePrefixTableLock(PrefixTable);
897 *LockHoldingState = LHS_LockNotHeld;
898 }
899 else
900 {
901 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
902 *LockHoldingState = LHS_ExclusiveLockHeld;
903 }
904 }
905
906 DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
907 return Status;
908 }
909
910 /*
911 * @implemented
912 */
913 NTSTATUS
914 RxConstructVirtualNetRoot(
915 IN PRX_CONTEXT RxContext,
916 IN PUNICODE_STRING CanonicalName,
917 IN NET_ROOT_TYPE NetRootType,
918 OUT PV_NET_ROOT *VirtualNetRootPointer,
919 OUT PLOCK_HOLDING_STATE LockHoldingState,
920 OUT PRX_CONNECTION_ID RxConnectionId)
921 {
922 NTSTATUS Status;
923 PV_NET_ROOT VNetRoot;
924 RX_BLOCK_CONDITION Condition;
925 UNICODE_STRING LocalNetRootName, FilePathName;
926
927 PAGED_CODE();
928
929 ASSERT(*LockHoldingState != LHS_LockNotHeld);
930
931 VNetRoot = NULL;
932 Condition = Condition_Bad;
933 /* Before creating the VNetRoot, try to find the appropriate connection */
934 Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
935 &LocalNetRootName, &FilePathName,
936 LockHoldingState, RxConnectionId);
937 /* Found and active */
938 if (Status == STATUS_CONNECTION_ACTIVE)
939 {
940 /* We need a new VNetRoot */
941 VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
942 CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
943 if (VNetRoot != NULL)
944 {
945 RxReferenceVNetRoot(VNetRoot);
946 }
947
948 /* Dereference previous VNetRoot */
949 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
950 /* Reset and start construct (new structures will replace old ones) */
951 RxContext->Create.pSrvCall = NULL;
952 RxContext->Create.pNetRoot = NULL;
953 RxContext->Create.pVNetRoot = NULL;
954
955 /* Construct new NetRoot */
956 if (VNetRoot != NULL)
957 {
958 Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
959 (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
960 if (NT_SUCCESS(Status))
961 {
962 Condition = Condition_Good;
963 }
964 }
965 else
966 {
967 Status = STATUS_INSUFFICIENT_RESOURCES;
968 }
969 }
970 else
971 {
972 /* If it failed creating the connection, leave */
973 if (Status != STATUS_SUCCESS)
974 {
975 if (*LockHoldingState != LHS_LockNotHeld)
976 {
977 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
978 *LockHoldingState = LHS_LockNotHeld;
979 }
980
981 *VirtualNetRootPointer = VNetRoot;
982 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
983 return Status;
984 }
985
986 *LockHoldingState = LHS_ExclusiveLockHeld;
987
988 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
989 Condition = Condition_Good;
990 }
991
992 /* We have a non stable VNetRoot - transition it */
993 if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
994 {
995 RxTransitionVNetRoot(VNetRoot, Condition);
996 }
997
998 /* If recreation failed */
999 if (Status != STATUS_SUCCESS)
1000 {
1001 /* Dereference potential VNetRoot */
1002 if (VNetRoot != NULL)
1003 {
1004 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1005 RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1006 VNetRoot = NULL;
1007 }
1008
1009 /* Release lock */
1010 if (*LockHoldingState != LHS_LockNotHeld)
1011 {
1012 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1013 *LockHoldingState = LHS_LockNotHeld;
1014 }
1015
1016 /* Set NULL ptr */
1017 *VirtualNetRootPointer = VNetRoot;
1018 return Status;
1019 }
1020
1021 /* Return the allocated VNetRoot */
1022 *VirtualNetRootPointer = VNetRoot;
1023 return Status;
1024 }
1025
1026 /*
1027 * @implemented
1028 */
1029 PFCB
1030 RxCreateNetFcb(
1031 IN PRX_CONTEXT RxContext,
1032 IN PV_NET_ROOT VNetRoot,
1033 IN PUNICODE_STRING Name)
1034 {
1035 PFCB Fcb;
1036 BOOLEAN FakeFcb;
1037 PNET_ROOT NetRoot;
1038 POOL_TYPE PoolType;
1039 NODE_TYPE_CODE NodeType;
1040 PIO_STACK_LOCATION Stack;
1041 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1042
1043 PAGED_CODE();
1044
1045 /* We need a decent VNetRoot */
1046 ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1047
1048 NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1049 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1050 ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1051
1052 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1053 ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1054
1055 Stack = RxContext->CurrentIrpSp;
1056
1057 /* Do we need to create a fake FCB? Like for renaming */
1058 FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1059 !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
1060 ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1061
1062 PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
1063 NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
1064
1065 /* Allocate the FCB */
1066 Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1067 NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1068 if (Fcb == NULL)
1069 {
1070 return NULL;
1071 }
1072
1073 /* Initialize the FCB */
1074 Fcb->CachedNetRootType = NetRoot->Type;
1075 Fcb->RxDeviceObject = RxDeviceObject;
1076 Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1077 Fcb->VNetRoot = VNetRoot;
1078 Fcb->pNetRoot = VNetRoot->pNetRoot;
1079
1080 InitializeListHead(&Fcb->SrvOpenList);
1081 Fcb->SrvOpenListVersion = 0;
1082
1083 Fcb->FcbTableEntry.Path.Length = Name->Length;
1084 Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
1085 Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1086 RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1087 NetRoot->InnerNamePrefix.Length);
1088 RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1089
1090 /* Copy back parameters from RxContext */
1091 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1092 {
1093 Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
1094 }
1095
1096 InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
1097
1098 if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
1099 {
1100 Fcb->FcbState |= FCB_STATE_PAGING_FILE;
1101 }
1102
1103 if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1104 {
1105 Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
1106 }
1107
1108 Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1109 ExInitializeResourceLite(Fcb->Header.Resource);
1110
1111 Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1112 ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1113
1114 Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
1115 ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
1116
1117 /* Fake FCB doesn't go in prefix table */
1118 if (FakeFcb)
1119 {
1120 Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
1121 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
1122 DPRINT("Fake FCB: %p\n", Fcb);
1123 }
1124 else
1125 {
1126 RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1127 }
1128
1129 RxReferenceVNetRoot(VNetRoot);
1130 InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1131
1132 Fcb->ulFileSizeVersion = 0;
1133
1134 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1135 RxReferenceNetFcb(Fcb);
1136
1137 return Fcb;
1138 }
1139
1140 /*
1141 * @implemented
1142 */
1143 PMRX_FOBX
1144 NTAPI
1145 RxCreateNetFobx(
1146 OUT PRX_CONTEXT RxContext,
1147 IN PMRX_SRV_OPEN MrxSrvOpen)
1148 {
1149 PFCB Fcb;
1150 PFOBX Fobx;
1151 ULONG Flags;
1152 PNET_ROOT NetRoot;
1153 PSRV_OPEN SrvOpen;
1154 POOL_TYPE PoolType;
1155
1156 PAGED_CODE();
1157
1158 SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1159 ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1160 ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1161 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1162
1163 Fcb = SrvOpen->Fcb;
1164 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1165 /* Can we use pre-allocated FOBX? */
1166 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
1167 {
1168 Fobx = Fcb->InternalFobx;
1169 /* Call allocate to initialize the FOBX */
1170 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1171 /* Mark it used now */
1172 Fcb->FcbState |= FCB_STATE_FOBX_USED;
1173 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1174 }
1175 else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1176 {
1177 Fobx = SrvOpen->InternalFobx;
1178 /* Call allocate to initialize the FOBX */
1179 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1180 /* Mark it used now */
1181 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1182 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1183 }
1184 else
1185 {
1186 /* Last case, we cannot, allocate a FOBX */
1187 Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
1188 Flags = 0;
1189 }
1190
1191 /* Allocation failed! */
1192 if (Fobx == NULL)
1193 {
1194 return NULL;
1195 }
1196
1197 /* Set flags */
1198 Fobx->Flags = Flags;
1199
1200 /* Initialize throttling */
1201 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1202 if (NetRoot != NULL)
1203 {
1204 if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1205 {
1206 RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1207 NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1208 NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1209 }
1210 else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1211 {
1212 RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1213 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1214 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1215 }
1216 }
1217
1218 /* Propagate flags fron RxContext */
1219 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1220 {
1221 Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1222 }
1223
1224 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1225 {
1226 Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1227 }
1228
1229 /* Continue init */
1230 Fobx->FobxSerialNumber = 0;
1231 Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1232 Fobx->NodeReferenceCount = 1;
1233 Fobx->RxDeviceObject = Fcb->RxDeviceObject;
1234
1235 RxReferenceSrvOpen(SrvOpen);
1236 InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1237
1238 InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1239 InitializeListHead(&Fobx->ScavengerFinalizationList);
1240 InitializeListHead(&Fobx->ClosePendingList);
1241
1242 Fobx->CloseTime.QuadPart = 0;
1243 Fobx->fOpenCountDecremented = FALSE;
1244
1245 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1246
1247 return (PMRX_FOBX)Fobx;
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 PNET_ROOT
1254 RxCreateNetRoot(
1255 IN PSRV_CALL SrvCall,
1256 IN PUNICODE_STRING Name,
1257 IN ULONG NetRootFlags,
1258 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1259 {
1260 PNET_ROOT NetRoot;
1261 USHORT CaseInsensitiveLength;
1262 PRX_PREFIX_TABLE PrefixTable;
1263
1264 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1265
1266 PAGED_CODE();
1267
1268 /* We need a SRV_CALL */
1269 ASSERT(SrvCall != NULL);
1270
1271 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1272 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1273
1274 /* Get name length */
1275 CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1276 if (CaseInsensitiveLength > MAXUSHORT)
1277 {
1278 return NULL;
1279 }
1280
1281 /* Allocate the NetRoot */
1282 NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1283 CaseInsensitiveLength);
1284 if (NetRoot == NULL)
1285 {
1286 return NULL;
1287 }
1288
1289 /* Construct name */
1290 RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1291 Name->Buffer, Name->Length);
1292 if (SrvCall->PrefixEntry.Prefix.Length != 0)
1293 {
1294 RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1295 SrvCall->PrefixEntry.Prefix.Length);
1296 }
1297
1298 if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1299 {
1300 CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1301 }
1302 /* Inisert in prefix table */
1303 RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1304 (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1305 RxConnectionId);
1306
1307 /* Prepare the FCB table */
1308 RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1309
1310 InitializeListHead(&NetRoot->TransitionWaitList);
1311 InitializeListHead(&NetRoot->ScavengerFinalizationList);
1312 InitializeListHead(&NetRoot->VirtualNetRoots);
1313
1314 RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
1315
1316 NetRoot->SerialNumberForEnum = SerialNumber++;
1317 NetRoot->Flags |= NetRootFlags;
1318 NetRoot->DiskParameters.ClusterSize = 1;
1319 NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1320 NetRoot->SrvCall = SrvCall;
1321
1322 RxReferenceSrvCall(SrvCall);
1323
1324 DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1325 return NetRoot;
1326 }
1327
1328 /*
1329 * @implemented
1330 */
1331 VOID
1332 NTAPI
1333 RxCreateNetRootCallBack(
1334 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1335 {
1336 PAGED_CODE();
1337
1338 KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1339 }
1340
1341 /*
1342 * @implemented
1343 */
1344 PRX_CONTEXT
1345 NTAPI
1346 RxCreateRxContext(
1347 IN PIRP Irp,
1348 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1349 IN ULONG InitialContextFlags)
1350 {
1351 KIRQL OldIrql;
1352 PRX_CONTEXT Context;
1353
1354 ASSERT(RxDeviceObject != NULL);
1355
1356 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1357
1358 InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
1359 InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1360
1361 /* Allocate the context from our lookaside list */
1362 Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1363 if (Context == NULL)
1364 {
1365 return NULL;
1366 }
1367
1368 /* And initialize it */
1369 RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1370 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1371 ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
1372
1373 /* Add it to our global list */
1374 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1375 InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1376 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1377
1378 DPRINT("Context: %p\n", Context);
1379 return Context;
1380 }
1381
1382 /*
1383 * @implemented
1384 */
1385 PSRV_CALL
1386 RxCreateSrvCall(
1387 IN PRX_CONTEXT RxContext,
1388 IN PUNICODE_STRING Name,
1389 IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1390 IN PRX_CONNECTION_ID RxConnectionId)
1391 {
1392 ULONG NameLength;
1393 PSRV_CALL SrvCall;
1394
1395 PAGED_CODE();
1396
1397 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1398
1399 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1400
1401 /* Get the name length */
1402 NameLength = Name->Length + 2 * sizeof(WCHAR);
1403 if (InnerNamePrefix != NULL)
1404 {
1405 NameLength += InnerNamePrefix->Length;
1406 }
1407
1408 /* Allocate the object */
1409 SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1410 if (SrvCall == NULL)
1411 {
1412 return NULL;
1413 }
1414
1415 /* Initialize it */
1416 SrvCall->SerialNumberForEnum = SerialNumber++;
1417 SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1418 RxInitializeBufferingManager(SrvCall);
1419 InitializeListHead(&SrvCall->TransitionWaitList);
1420 InitializeListHead(&SrvCall->ScavengerFinalizationList);
1421 RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
1422 RxInitializeSrvCallParameters(RxContext, SrvCall);
1423 RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1424 SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1425 SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1426 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1427 SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1428
1429 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1430 return SrvCall;
1431 }
1432
1433 /*
1434 * @implemented
1435 */
1436 VOID
1437 NTAPI
1438 RxCreateSrvCallCallBack(
1439 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
1440 {
1441 KIRQL OldIrql;
1442 PSRV_CALL SrvCall;
1443 PRX_CONTEXT RxContext;
1444 ULONG NumberRemaining;
1445 BOOLEAN StartDispatcher;
1446 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1447
1448 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1449
1450 /* Get our context structures */
1451 Calldown = Context->SrvCalldownStructure;
1452 SrvCall = (PSRV_CALL)Calldown->SrvCall;
1453
1454 /* If it is a success, that's the winner */
1455 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1456 if (Context->Status == STATUS_SUCCESS)
1457 {
1458 Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1459 Calldown->BestFinisher = Context->RxDeviceObject;
1460 }
1461 NumberRemaining = --Calldown->NumberRemaining;
1462 SrvCall->Status = Context->Status;
1463 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1464
1465 /* Still some to ask, keep going */
1466 if (NumberRemaining != 0)
1467 {
1468 return;
1469 }
1470
1471 /* If that's not async, signal we're done */
1472 RxContext = Calldown->RxContext;
1473 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1474 {
1475 KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1476 return;
1477 }
1478 /* If that's a mailslot, finish construction, no more to do */
1479 else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1480 {
1481 RxFinishSrvCallConstruction(Calldown);
1482 return;
1483 }
1484
1485 /* Queue our finish call for delayed completion */
1486 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1487 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1488 InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
1489 StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1490 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1491
1492 /* If we have to start dispatcher, go ahead */
1493 if (StartDispatcher)
1494 {
1495 NTSTATUS Status;
1496
1497 Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
1498 RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
1499 if (!NT_SUCCESS(Status))
1500 {
1501 /* It failed - run it manually.... */
1502 RxFinishSrvCallConstructionDispatcher(NULL);
1503 }
1504 }
1505 }
1506
1507 /*
1508 * @implemented
1509 */
1510 PSRV_OPEN
1511 RxCreateSrvOpen(
1512 IN PV_NET_ROOT VNetRoot,
1513 IN OUT PFCB Fcb)
1514 {
1515 ULONG Flags;
1516 PSRV_OPEN SrvOpen;
1517 POOL_TYPE PoolType;
1518
1519 PAGED_CODE();
1520
1521 ASSERT(NodeTypeIsFcb(Fcb));
1522 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1523
1524 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1525
1526 _SEH2_TRY
1527 {
1528 SrvOpen = Fcb->InternalSrvOpen;
1529 /* Check whethet we have to allocate a new SRV_OPEN */
1530 if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
1531 BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
1532 !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1533 {
1534 /* Proceed */
1535 SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1536 RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
1537 Flags = 0;
1538 }
1539 else
1540 {
1541 /* Otherwise, just use internal one and initialize it */
1542 RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1543 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
1544 Fcb->InternalSrvOpen);
1545 Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
1546 Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
1547 }
1548
1549 /* If SrvOpen was properly allocated, initialize it */
1550 if (SrvOpen != NULL)
1551 {
1552 SrvOpen->Flags = Flags;
1553 SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
1554 SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
1555 SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
1556 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
1557 SrvOpen->NodeReferenceCount = 1;
1558
1559 RxReferenceVNetRoot(VNetRoot);
1560 RxReferenceNetFcb(Fcb);
1561
1562 InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
1563 ++Fcb->SrvOpenListVersion;
1564
1565 InitializeListHead(&SrvOpen->ScavengerFinalizationList);
1566 InitializeListHead(&SrvOpen->TransitionWaitList);
1567 InitializeListHead(&SrvOpen->FobxList);
1568 InitializeListHead(&SrvOpen->SrvOpenKeyList);
1569 }
1570 }
1571 _SEH2_FINALLY
1572 {
1573 if (_SEH2_AbnormalTermination())
1574 {
1575 if (SrvOpen != NULL)
1576 {
1577 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
1578 SrvOpen = NULL;
1579 }
1580 }
1581 else
1582 {
1583 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
1584 }
1585 }
1586 _SEH2_END;
1587
1588 return SrvOpen;
1589 }
1590
1591 /*
1592 * @implemented
1593 */
1594 PV_NET_ROOT
1595 RxCreateVNetRoot(
1596 IN PRX_CONTEXT RxContext,
1597 IN PNET_ROOT NetRoot,
1598 IN PUNICODE_STRING CanonicalName,
1599 IN PUNICODE_STRING LocalNetRootName,
1600 IN PUNICODE_STRING FilePath,
1601 IN PRX_CONNECTION_ID RxConnectionId)
1602 {
1603 NTSTATUS Status;
1604 PV_NET_ROOT VNetRoot;
1605 USHORT CaseInsensitiveLength;
1606
1607 PAGED_CODE();
1608
1609 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
1610 LocalNetRootName, FilePath, RxConnectionId);
1611
1612 /* Lock must be held exclusively */
1613 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1614
1615 /* Check for overflow */
1616 if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
1617 {
1618 return NULL;
1619 }
1620
1621 /* Get name length and allocate VNetRoot */
1622 CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
1623 VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
1624 CaseInsensitiveLength);
1625 if (VNetRoot == NULL)
1626 {
1627 return NULL;
1628 }
1629
1630 /* Initialize its connection parameters */
1631 Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
1632 &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
1633 &VNetRoot->pPassword, &VNetRoot->Flags);
1634 if (!NT_SUCCESS(Status))
1635 {
1636 RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
1637 VNetRoot->pPassword, &VNetRoot->Flags);
1638 RxFreeObject(VNetRoot);
1639
1640 return NULL;
1641 }
1642
1643 /* Set name */
1644 RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
1645
1646 VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
1647 VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
1648 VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
1649 VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
1650
1651 InitializeListHead(&VNetRoot->TransitionWaitList);
1652 InitializeListHead(&VNetRoot->ScavengerFinalizationList);
1653
1654 if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
1655 {
1656 USHORT i;
1657
1658 if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1659 {
1660 CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
1661 }
1662 else
1663 {
1664 CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
1665 }
1666
1667 for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
1668 {
1669 if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
1670 {
1671 break;
1672 }
1673 }
1674
1675 CaseInsensitiveLength += (i * sizeof(WCHAR));
1676 }
1677
1678 /* Insert in prefix table */
1679 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
1680 VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
1681 RxConnectionId);
1682
1683 RxReferenceNetRoot(NetRoot);
1684 RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
1685
1686 /* Finish init */
1687 VNetRoot->SerialNumberForEnum = SerialNumber++;
1688 VNetRoot->UpperFinalizationDone = FALSE;
1689 VNetRoot->ConnectionFinalizationDone = FALSE;
1690 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
1691
1692 DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
1693 DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
1694
1695 return VNetRoot;
1696 }
1697
1698 VOID
1699 RxDereference(
1700 IN OUT PVOID Instance,
1701 IN LOCK_HOLDING_STATE LockHoldingState)
1702 {
1703 LONG RefCount;
1704 NODE_TYPE_CODE NodeType;
1705 PNODE_TYPE_AND_SIZE Node;
1706
1707 PAGED_CODE();
1708
1709 RxAcquireScavengerMutex();
1710
1711 /* Check we have a node we can handle */
1712 NodeType = NodeType(Instance);
1713 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
1714 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
1715 (NodeType == RDBSS_NTC_FOBX));
1716
1717 Node = (PNODE_TYPE_AND_SIZE)Instance;
1718 RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
1719 ASSERT(RefCount >= 0);
1720
1721 /* Trace refcount */
1722 switch (NodeType)
1723 {
1724 case RDBSS_NTC_SRVCALL:
1725 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
1726 break;
1727
1728 case RDBSS_NTC_NETROOT:
1729 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
1730 break;
1731
1732 case RDBSS_NTC_V_NETROOT:
1733 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
1734 break;
1735
1736 case RDBSS_NTC_SRVOPEN:
1737 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
1738 break;
1739
1740 case RDBSS_NTC_FOBX:
1741 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
1742 break;
1743
1744 default:
1745 ASSERT(FALSE);
1746 break;
1747 }
1748
1749 /* No need to free - still in use */
1750 if (RefCount > 1)
1751 {
1752 RxReleaseScavengerMutex();
1753 return;
1754 }
1755
1756 /* We have to be locked exclusively */
1757 if (LockHoldingState != LHS_ExclusiveLockHeld)
1758 {
1759 UNIMPLEMENTED;
1760 RxReleaseScavengerMutex();
1761 return;
1762 }
1763
1764 RxReleaseScavengerMutex();
1765
1766 /* TODO: Really deallocate stuff - we're leaking as hell! */
1767 switch (NodeType)
1768 {
1769 case RDBSS_NTC_SRVCALL:
1770 {
1771 PSRV_CALL SrvCall;
1772
1773 SrvCall = (PSRV_CALL)Instance;
1774
1775 ASSERT(SrvCall->RxDeviceObject != NULL);
1776 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
1777 RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
1778 break;
1779 }
1780
1781 case RDBSS_NTC_NETROOT:
1782 UNIMPLEMENTED;
1783 break;
1784
1785 case RDBSS_NTC_V_NETROOT:
1786 UNIMPLEMENTED;
1787 break;
1788
1789 case RDBSS_NTC_SRVOPEN:
1790 UNIMPLEMENTED;
1791 break;
1792
1793 case RDBSS_NTC_FOBX:
1794 UNIMPLEMENTED;
1795 break;
1796 }
1797 }
1798
1799 /*
1800 * @implemented
1801 */
1802 VOID
1803 NTAPI
1804 RxDereferenceAndDeleteRxContext_Real(
1805 IN PRX_CONTEXT RxContext)
1806 {
1807 KIRQL OldIrql;
1808 ULONG RefCount;
1809 BOOLEAN Allocated;
1810 PRX_CONTEXT StopContext = NULL;
1811
1812 /* Make sure we really have a context */
1813 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1814 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
1815 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
1816 /* If refcount is 0, start releasing stuff that needs spinlock held */
1817 if (RefCount == 0)
1818 {
1819 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1820
1821 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1822
1823 /* If that's stop context from DO, remove it */
1824 RxDeviceObject = RxContext->RxDeviceObject;
1825 if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
1826 {
1827 RxDeviceObject->StartStopContext.pStopContext = NULL;
1828 }
1829 else
1830 {
1831 /* Remove it from the list */
1832 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
1833 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
1834 RemoveEntryList(&RxContext->ContextListEntry);
1835
1836 /* If that was the last active context, save the stop context */
1837 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
1838 {
1839 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
1840 {
1841 StopContext = RxDeviceObject->StartStopContext.pStopContext;
1842 }
1843 }
1844 }
1845 }
1846 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1847
1848 /* Now, deal with what can be done without spinlock held */
1849 if (RefCount == 0)
1850 {
1851 /* Refcount shouldn't have changed */
1852 ASSERT(RxContext->ReferenceCount == 0);
1853 /* Reset everything that can be */
1854 RxPrepareContextForReuse(RxContext);
1855
1856 #ifdef RDBSS_TRACKER
1857 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
1858 #endif
1859 /* If that was the last active, set the event */
1860 if (StopContext != NULL)
1861 {
1862 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
1863 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
1864 }
1865
1866 /* Is ShadowCrit still owned? Shouldn't happen! */
1867 if (RxContext->ShadowCritOwner != 0)
1868 {
1869 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
1870 ASSERT(FALSE);
1871 }
1872
1873 /* If it was allocated, free it */
1874 if (Allocated)
1875 {
1876 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
1877 }
1878 }
1879 }
1880
1881 /*
1882 * @implemented
1883 */
1884 NTSTATUS
1885 NTAPI
1886 RxDispatchToWorkerThread(
1887 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
1888 IN WORK_QUEUE_TYPE WorkQueueType,
1889 IN PRX_WORKERTHREAD_ROUTINE Routine,
1890 IN PVOID pContext)
1891 {
1892 NTSTATUS Status;
1893 PRX_WORK_DISPATCH_ITEM DispatchItem;
1894
1895 /* Allocate a bit of context */
1896 DispatchItem = ExAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
1897 if (DispatchItem == NULL)
1898 {
1899 return STATUS_INSUFFICIENT_RESOURCES;
1900 }
1901
1902 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1903 DispatchItem->DispatchRoutine = Routine;
1904 DispatchItem->DispatchRoutineParameter = pContext;
1905 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
1906 DispatchItem->WorkQueueItem.Parameter = DispatchItem;
1907
1908 /* Insert item */
1909 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, DispatchItem);
1910 if (!NT_SUCCESS(Status))
1911 {
1912 ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
1913 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
1914 }
1915
1916 DPRINT("Dispatching: %p, %p\n", Routine, pContext);
1917
1918 return Status;
1919 }
1920
1921 /*
1922 * @implemented
1923 */
1924 VOID
1925 RxExclusivePrefixTableLockToShared(
1926 PRX_PREFIX_TABLE Table)
1927 {
1928 PAGED_CODE();
1929
1930 ExConvertExclusiveToSharedLite(&Table->TableLock);
1931 }
1932
1933 /*
1934 * @implemented
1935 */
1936 VOID
1937 RxExtractServerName(
1938 IN PUNICODE_STRING FilePathName,
1939 OUT PUNICODE_STRING SrvCallName,
1940 OUT PUNICODE_STRING RestOfName)
1941 {
1942 USHORT i, Length;
1943
1944 PAGED_CODE();
1945
1946 ASSERT(SrvCallName != NULL);
1947
1948 /* SrvCall name will start from the begin up to the first separator */
1949 SrvCallName->Buffer = FilePathName->Buffer;
1950 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
1951 {
1952 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
1953 {
1954 break;
1955 }
1956 }
1957
1958 /* Compute length */
1959 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
1960 SrvCallName->MaximumLength = Length;
1961 SrvCallName->Length = Length;
1962
1963 /* Return the rest if asked */
1964 if (RestOfName != NULL)
1965 {
1966 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
1967 RestOfName->Buffer = &FilePathName->Buffer[i];
1968 RestOfName->MaximumLength = Length;
1969 RestOfName->Length = Length;
1970 }
1971 }
1972
1973 /*
1974 * @implemented
1975 */
1976 NTSTATUS
1977 RxFcbTableInsertFcb(
1978 IN OUT PRX_FCB_TABLE FcbTable,
1979 IN OUT PFCB Fcb)
1980 {
1981 PAGED_CODE();
1982
1983 /* We deal with the table, make sure it's locked */
1984 ASSERT(RxIsFcbTableLockExclusive(FcbTable));
1985
1986 /* Compute the hash */
1987 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
1988
1989 RxReferenceNetFcb(Fcb);
1990
1991 /* If no length, it will be our null entry */
1992 if (Fcb->FcbTableEntry.Path.Length == 0)
1993 {
1994 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
1995 }
1996 /* Otherwise, insert in the appropriate bucket */
1997 else
1998 {
1999 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2000 &Fcb->FcbTableEntry.HashLinks);
2001 }
2002
2003 /* Propagate the change by incrementing the version number */
2004 InterlockedIncrement((volatile long *)&FcbTable->Version);
2005
2006 return STATUS_SUCCESS;
2007 }
2008
2009 /*
2010 * @implemented
2011 */
2012 PFCB
2013 RxFcbTableLookupFcb(
2014 IN PRX_FCB_TABLE FcbTable,
2015 IN PUNICODE_STRING Path)
2016 {
2017 PFCB Fcb;
2018 PRX_FCB_TABLE_ENTRY TableEntry;
2019
2020 PAGED_CODE();
2021
2022 /* No path - easy, that's null entry */
2023 if (Path == NULL)
2024 {
2025 TableEntry = FcbTable->TableEntryForNull;
2026 }
2027 else
2028 {
2029 ULONG Hash;
2030 PLIST_ENTRY HashBucket, ListEntry;
2031
2032 /* Otherwise, compute the hash value and find the associated bucket */
2033 Hash = RxTableComputePathHashValue(Path);
2034 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2035 /* If the bucket is empty, it means there's no entry yet */
2036 if (IsListEmpty(HashBucket))
2037 {
2038 TableEntry = NULL;
2039 }
2040 else
2041 {
2042 /* Otherwise, browse all the entry */
2043 for (ListEntry = HashBucket->Flink;
2044 ListEntry != HashBucket;
2045 ListEntry = ListEntry->Flink)
2046 {
2047 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2048 InterlockedIncrement(&FcbTable->Compares);
2049
2050 /* If entry hash and string are equal, thatt's the one! */
2051 if (TableEntry->HashValue == Hash &&
2052 TableEntry->Path.Length == Path->Length &&
2053 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2054 {
2055 break;
2056 }
2057 }
2058
2059 /* We reached the end? Not found */
2060 if (ListEntry == HashBucket)
2061 {
2062 TableEntry = NULL;
2063 }
2064 }
2065 }
2066
2067 InterlockedIncrement(&FcbTable->Lookups);
2068
2069 /* If table entry isn't null, return the FCB */
2070 if (TableEntry != NULL)
2071 {
2072 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2073 RxReferenceNetFcb(Fcb);
2074 }
2075 else
2076 {
2077 Fcb = NULL;
2078 InterlockedIncrement(&FcbTable->FailedLookups);
2079 }
2080
2081 return Fcb;
2082 }
2083
2084 /*
2085 * @implemented
2086 */
2087 NTSTATUS
2088 RxFcbTableRemoveFcb(
2089 IN OUT PRX_FCB_TABLE FcbTable,
2090 IN OUT PFCB Fcb)
2091 {
2092 PAGED_CODE();
2093
2094 ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2095
2096 /* If no path, then remove entry for null */
2097 if (Fcb->FcbTableEntry.Path.Length == 0)
2098 {
2099 FcbTable->TableEntryForNull = NULL;
2100 }
2101 /* Otherwise, remove from the bucket */
2102 else
2103 {
2104 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2105 }
2106
2107 /* Reset its list entry */
2108 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2109
2110 /* Propagate the change by incrementing the version number */
2111 InterlockedIncrement((volatile long *)&FcbTable->Version);
2112
2113 return STATUS_SUCCESS;
2114 }
2115
2116 /*
2117 * @implemented
2118 */
2119 BOOLEAN
2120 RxFinalizeNetFcb(
2121 OUT PFCB ThisFcb,
2122 IN BOOLEAN RecursiveFinalize,
2123 IN BOOLEAN ForceFinalize,
2124 IN LONG ReferenceCount)
2125 {
2126 PAGED_CODE();
2127
2128 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2129 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2130
2131 /* Make sure we have an exclusively acquired FCB */
2132 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2133 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2134
2135 /* We shouldn't force finalization... */
2136 ASSERT(!ForceFinalize);
2137
2138 /* If recurisve, finalize all the associated SRV_OPEN */
2139 if (RecursiveFinalize)
2140 {
2141 PLIST_ENTRY ListEntry;
2142
2143 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2144 ListEntry != &ThisFcb->SrvOpenList;
2145 ListEntry = ListEntry->Flink)
2146 {
2147 PSRV_OPEN SrvOpen;
2148
2149 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2150 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2151 }
2152 }
2153 /* If FCB is still in use, that's over */
2154 else
2155 {
2156 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2157 {
2158 ASSERT(ReferenceCount > 0);
2159
2160 return FALSE;
2161 }
2162 }
2163
2164 ASSERT(ReferenceCount >= 1);
2165
2166 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2167 if (ReferenceCount != 1 && !ForceFinalize)
2168 {
2169 return FALSE;
2170 }
2171
2172 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2173
2174 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
2175
2176 /* If finalization was not already initiated, go ahead */
2177 if (!ThisFcb->UpperFinalizationDone)
2178 {
2179 /* Free any FCB_LOCK */
2180 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2181 {
2182 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2183
2184 while (ThisFcb->BufferedLocks.List != NULL)
2185 {
2186 PFCB_LOCK Entry;
2187
2188 Entry = ThisFcb->BufferedLocks.List;
2189 ThisFcb->BufferedLocks.List = Entry->Next;
2190
2191 ExFreePool(Entry);
2192 }
2193 }
2194
2195 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2196 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2197 {
2198 PNET_ROOT NetRoot;
2199
2200 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2201
2202 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2203 /* So, remove it */
2204 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2205 {
2206 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2207 }
2208 }
2209
2210 ThisFcb->UpperFinalizationDone = TRUE;
2211 }
2212
2213 ASSERT(ReferenceCount >= 1);
2214
2215 /* Even if forced, don't allow broken free */
2216 if (ReferenceCount != 1)
2217 {
2218 return FALSE;
2219 }
2220
2221 /* Now, release everything */
2222 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2223 {
2224 ExFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2225 }
2226
2227 if (ThisFcb->MRxDispatch != NULL)
2228 {
2229 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2230 }
2231
2232 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2233 ExDeleteResourceLite(ThisFcb->Header.Resource);
2234 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2235
2236 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2237 RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
2238
2239 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2240 ASSERT(!ThisFcb->fMiniInited);
2241
2242 /* And free the object */
2243 RxFreeFcbObject(ThisFcb);
2244
2245 return TRUE;
2246 }
2247
2248 BOOLEAN
2249 RxFinalizeNetRoot(
2250 OUT PNET_ROOT ThisNetRoot,
2251 IN BOOLEAN RecursiveFinalize,
2252 IN BOOLEAN ForceFinalize
2253 )
2254 {
2255 UNIMPLEMENTED;
2256 return FALSE;
2257 }
2258
2259 BOOLEAN
2260 RxFinalizeSrvCall(
2261 OUT PSRV_CALL ThisSrvCall,
2262 IN BOOLEAN RecursiveFinalize,
2263 IN BOOLEAN ForceFinalize)
2264 {
2265 UNIMPLEMENTED;
2266 return FALSE;
2267 }
2268
2269 BOOLEAN
2270 RxFinalizeSrvOpen(
2271 OUT PSRV_OPEN ThisSrvOpen,
2272 IN BOOLEAN RecursiveFinalize,
2273 IN BOOLEAN ForceFinalize)
2274 {
2275 UNIMPLEMENTED;
2276 return FALSE;
2277 }
2278
2279 NTSTATUS
2280 RxFindOrConstructVirtualNetRoot(
2281 IN PRX_CONTEXT RxContext,
2282 IN PUNICODE_STRING CanonicalName,
2283 IN NET_ROOT_TYPE NetRootType,
2284 IN PUNICODE_STRING RemainingName)
2285 {
2286 ULONG Flags;
2287 NTSTATUS Status;
2288 PVOID Container;
2289 BOOLEAN Construct;
2290 PV_NET_ROOT VNetRoot;
2291 RX_CONNECTION_ID ConnectionID;
2292 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2293 LOCK_HOLDING_STATE LockHoldingState;
2294
2295 PAGED_CODE();
2296
2297 RxDeviceObject = RxContext->RxDeviceObject;
2298 ASSERT(RxDeviceObject->Dispatch != NULL);
2299 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
2300
2301 /* Ask the mini-rdr for connection ID */
2302 ConnectionID.SessionID = 0;
2303 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
2304 {
2305 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
2306 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
2307 {
2308 /* mini-rdr is expected not to fail - unless it's not implemented */
2309 DPRINT1("Failed to initialize connection ID\n");
2310 ASSERT(FALSE);
2311 }
2312 }
2313
2314 RxContext->Create.NetNamePrefixEntry = NULL;
2315
2316 Status = STATUS_MORE_PROCESSING_REQUIRED;
2317 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
2318 LockHoldingState = LHS_SharedLockHeld;
2319 Construct = TRUE;
2320 Flags = 0;
2321
2322 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2323 while (TRUE)
2324 {
2325 PNET_ROOT NetRoot;
2326 PV_NET_ROOT SavedVNetRoot;
2327
2328 /* Look in prefix table */
2329 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
2330 if (Container != NULL)
2331 {
2332 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2333 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
2334 {
2335 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2336 RxDereferenceSrvCall(Container, LockHoldingState);
2337 }
2338 else
2339 {
2340 VNetRoot = Container;
2341 NetRoot = VNetRoot->NetRoot;
2342
2343 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2344 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
2345 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2346 {
2347 Status = STATUS_BAD_NETWORK_PATH;
2348 SavedVNetRoot = NULL;
2349 }
2350 else
2351 {
2352 LUID LogonId;
2353 ULONG SessionId;
2354 PUNICODE_STRING UserName, UserDomain, Password;
2355
2356 /* We can reuse if we use same credentials */
2357 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
2358 &SessionId, &UserName,
2359 &UserDomain, &Password,
2360 &Flags);
2361 if (NT_SUCCESS(Status))
2362 {
2363 SavedVNetRoot = VNetRoot;
2364 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
2365 &LogonId, UserName,
2366 UserDomain, Password,
2367 Flags);
2368 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
2369 {
2370 PLIST_ENTRY ListEntry;
2371
2372 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
2373 ListEntry != &NetRoot->VirtualNetRoots;
2374 ListEntry = ListEntry->Flink)
2375 {
2376 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
2377 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
2378 &LogonId, UserName,
2379 UserDomain, Password,
2380 Flags);
2381 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2382 {
2383 break;
2384 }
2385 }
2386
2387 if (ListEntry == &NetRoot->VirtualNetRoots)
2388 {
2389 SavedVNetRoot = NULL;
2390 }
2391 }
2392
2393 if (!NT_SUCCESS(Status))
2394 {
2395 SavedVNetRoot = NULL;
2396 }
2397
2398 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
2399 }
2400 }
2401
2402 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2403 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
2404 {
2405 if (SavedVNetRoot == NULL)
2406 {
2407 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2408 }
2409 }
2410 /* Reference VNetRoot we'll keep, and dereference current */
2411 else if (SavedVNetRoot != VNetRoot)
2412 {
2413 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2414 if (SavedVNetRoot != NULL)
2415 {
2416 RxReferenceVNetRoot(SavedVNetRoot);
2417 }
2418 }
2419 }
2420
2421 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2422 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2423 {
2424 Construct = FALSE;
2425 break;
2426 }
2427 }
2428
2429 /* If we're locked exclusive, we won't loop again, it was the second pass */
2430 if (LockHoldingState != LHS_SharedLockHeld)
2431 {
2432 break;
2433 }
2434
2435 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2436 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
2437 {
2438 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2439 LockHoldingState = LHS_ExclusiveLockHeld;
2440 break;
2441 }
2442
2443 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2444 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
2445 LockHoldingState = LHS_ExclusiveLockHeld;
2446 }
2447
2448 /* We didn't fail, and didn't find any VNetRoot, construct one */
2449 if (Construct)
2450 {
2451 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
2452
2453 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
2454 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
2455
2456 if (Status == STATUS_SUCCESS)
2457 {
2458 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
2459 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
2460 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
2461
2462 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2463 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
2464 RemainingName->MaximumLength = RemainingName->Length;
2465
2466 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
2467 {
2468 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
2469 }
2470 VNetRoot->Flags |= Flags;
2471 }
2472 }
2473
2474 /* Release the prefix table - caller expects it to be released */
2475 if (LockHoldingState != LHS_LockNotHeld)
2476 {
2477 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2478 }
2479
2480 /* If we failed creating, quit */
2481 if (Status != STATUS_SUCCESS)
2482 {
2483 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
2484 return Status;
2485 }
2486
2487 /* Otherwise, wait until the VNetRoot is stable */
2488 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
2489 RxWaitForStableVNetRoot(VNetRoot, RxContext);
2490 /* It's all good, update the RX_CONTEXT with all our structs */
2491 if (VNetRoot->Condition == Condition_Good)
2492 {
2493 PNET_ROOT NetRoot;
2494
2495 NetRoot = VNetRoot->NetRoot;
2496 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2497 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2498 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
2499 }
2500 else
2501 {
2502 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2503 RxContext->Create.pVNetRoot = NULL;
2504 Status = STATUS_BAD_NETWORK_PATH;
2505 }
2506
2507 return Status;
2508 }
2509
2510 /*
2511 * @implemented
2512 */
2513 NTSTATUS
2514 RxFindOrCreateConnections(
2515 _In_ PRX_CONTEXT RxContext,
2516 _In_ PUNICODE_STRING CanonicalName,
2517 _In_ NET_ROOT_TYPE NetRootType,
2518 _Out_ PUNICODE_STRING LocalNetRootName,
2519 _Out_ PUNICODE_STRING FilePathName,
2520 _Inout_ PLOCK_HOLDING_STATE LockState,
2521 _In_ PRX_CONNECTION_ID RxConnectionId)
2522 {
2523 PVOID Container;
2524 PSRV_CALL SrvCall;
2525 PNET_ROOT NetRoot;
2526 PV_NET_ROOT VNetRoot;
2527 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2528 PRX_PREFIX_TABLE PrefixTable;
2529 UNICODE_STRING RemainingName, NetRootName;
2530
2531 PAGED_CODE();
2532
2533 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2534 RxContext, CanonicalName, NetRootType, LocalNetRootName,
2535 FilePathName, LockState, RxConnectionId);
2536
2537 *FilePathName = *CanonicalName;
2538 LocalNetRootName->Length = 0;
2539 LocalNetRootName->MaximumLength = 0;
2540 LocalNetRootName->Buffer = CanonicalName->Buffer;
2541
2542 /* UNC path, split it */
2543 if (FilePathName->Buffer[1] == ';')
2544 {
2545 BOOLEAN Slash;
2546 USHORT i, Length;
2547
2548 Slash = FALSE;
2549 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
2550 {
2551 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2552 {
2553 Slash = TRUE;
2554 break;
2555 }
2556 }
2557
2558 if (!Slash)
2559 {
2560 return STATUS_OBJECT_NAME_INVALID;
2561 }
2562
2563 FilePathName->Buffer = &FilePathName->Buffer[i];
2564 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
2565 LocalNetRootName->Length = Length;
2566 LocalNetRootName->MaximumLength = Length;
2567 FilePathName->Length -= Length;
2568
2569 DPRINT("CanonicalName: %wZ\n", CanonicalName);
2570 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
2571 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
2572 }
2573
2574 Container = NULL;
2575 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
2576
2577 _SEH2_TRY
2578 {
2579 RetryLookup:
2580 ASSERT(*LockState != LHS_LockNotHeld);
2581
2582 /* If previous lookup left something, dereference it */
2583 if (Container != NULL)
2584 {
2585 switch (NodeType(Container))
2586 {
2587 case RDBSS_NTC_SRVCALL:
2588 RxDereferenceSrvCall(Container, *LockState);
2589 break;
2590
2591 case RDBSS_NTC_NETROOT:
2592 RxDereferenceNetRoot(Container, *LockState);
2593 break;
2594
2595 case RDBSS_NTC_V_NETROOT:
2596 RxDereferenceVNetRoot(Container, *LockState);
2597 break;
2598
2599 default:
2600 /* Should never happen */
2601 ASSERT(FALSE);
2602 break;
2603 }
2604 }
2605
2606 /* Look for our NetRoot in prefix table */
2607 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
2608 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
2609
2610 while (TRUE)
2611 {
2612 UNICODE_STRING SrvCallName;
2613
2614 SrvCall = NULL;
2615 NetRoot = NULL;
2616 VNetRoot = NULL;
2617
2618 /* Assume we didn't succeed */
2619 RxContext->Create.pVNetRoot = NULL;
2620 RxContext->Create.pNetRoot = NULL;
2621 RxContext->Create.pSrvCall = NULL;
2622 RxContext->Create.Type = NetRootType;
2623
2624 /* If we found something */
2625 if (Container != NULL)
2626 {
2627 /* A VNetRoot */
2628 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
2629 {
2630 VNetRoot = Container;
2631 /* Use its NetRoot */
2632 NetRoot = VNetRoot->NetRoot;
2633
2634 /* If it's not stable, wait for it to be stable */
2635 if (NetRoot->Condition == Condition_InTransition)
2636 {
2637 RxReleasePrefixTableLock(PrefixTable);
2638 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
2639 RxWaitForStableNetRoot(NetRoot, RxContext);
2640 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2641 *LockState = LHS_ExclusiveLockHeld;
2642
2643 /* Now that's it's ok, retry lookup to find what we want */
2644 if (NetRoot->Condition == Condition_Good)
2645 {
2646 goto RetryLookup;
2647 }
2648 }
2649
2650 /* Is the associated netroot good? */
2651 if (NetRoot->Condition == Condition_Good)
2652 {
2653 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
2654
2655 /* If it is, and SrvCall as well, then, we have our active connection */
2656 if (SrvCall->Condition == Condition_Good &&
2657 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
2658 {
2659 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2660 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2661 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2662
2663 Status = STATUS_CONNECTION_ACTIVE;
2664 _SEH2_LEAVE;
2665 }
2666 }
2667
2668 /* If VNetRoot was well constructed, it means the connection is active */
2669 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
2670 {
2671 Status = STATUS_CONNECTION_ACTIVE;
2672 }
2673 else
2674 {
2675 Status = VNetRoot->ConstructionStatus;
2676 }
2677
2678 RxDereferenceVNetRoot(VNetRoot, *LockState);
2679 _SEH2_LEAVE;
2680 }
2681 /* Can only be a SrvCall */
2682 else
2683 {
2684 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2685 SrvCall = Container;
2686
2687 /* Wait for the SRV_CALL to be stable */
2688 if (SrvCall->Condition == Condition_InTransition)
2689 {
2690 RxReleasePrefixTableLock(PrefixTable);
2691 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
2692 RxWaitForStableSrvCall(SrvCall, RxContext);
2693 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2694 *LockState = LHS_ExclusiveLockHeld;
2695
2696 /* It went good, loop again to find what we look for */
2697 if (SrvCall->Condition == Condition_Good)
2698 {
2699 goto RetryLookup;
2700 }
2701 }
2702
2703 /* If it's not good... */
2704 if (SrvCall->Condition != Condition_Good)
2705 {
2706 /* But SRV_CALL was well constructed, assume a connection was active */
2707 if (SrvCall->Status == STATUS_SUCCESS)
2708 {
2709 Status = STATUS_CONNECTION_ACTIVE;
2710 }
2711 else
2712 {
2713 Status = SrvCall->Status;
2714 }
2715
2716 RxDereferenceSrvCall(SrvCall, *LockState);
2717 _SEH2_LEAVE;
2718 }
2719 }
2720 }
2721
2722 /* If we found a SRV_CALL not matching our DO, quit */
2723 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
2724 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2725 {
2726 RxDereferenceSrvCall(SrvCall, *LockState);
2727 Status = STATUS_BAD_NETWORK_NAME;
2728 _SEH2_LEAVE;
2729 }
2730
2731 /* Now, we want exclusive lock */
2732 if (*LockState == LHS_SharedLockHeld)
2733 {
2734 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
2735 {
2736 RxReleasePrefixTableLock(PrefixTable);
2737 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2738 *LockState = LHS_ExclusiveLockHeld;
2739 goto RetryLookup;
2740 }
2741
2742 RxReleasePrefixTableLock(PrefixTable);
2743 *LockState = LHS_ExclusiveLockHeld;
2744 }
2745
2746 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2747
2748 /* If we reach that point, we found something, no need to create something */
2749 if (Container != NULL)
2750 {
2751 break;
2752 }
2753
2754 /* Get the name for the SRV_CALL */
2755 RxExtractServerName(FilePathName, &SrvCallName, NULL);
2756 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
2757 /* And create the SRV_CALL */
2758 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
2759 if (SrvCall == NULL)
2760 {
2761 Status = STATUS_INSUFFICIENT_RESOURCES;
2762 _SEH2_LEAVE;
2763 }
2764
2765 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2766 RxReferenceSrvCall(SrvCall);
2767 RxContext->Create.pVNetRoot = NULL;
2768 RxContext->Create.pNetRoot = NULL;
2769 RxContext->Create.pSrvCall = NULL;
2770 RxContext->Create.Type = NetRootType;
2771 Container = SrvCall;
2772
2773 /* Construct SRV_CALL, ie, use mini-rdr */
2774 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
2775 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
2776 if (Status != STATUS_SUCCESS)
2777 {
2778 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
2779 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2780 RxDereferenceSrvCall(SrvCall, *LockState);
2781 RxReleasePrefixTableLock(PrefixTable);
2782 _SEH2_LEAVE;
2783 }
2784
2785 /* Loop again to make use of SRV_CALL stable condition wait */
2786 }
2787
2788 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2789 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
2790 ASSERT(NetRoot == NULL && VNetRoot == NULL);
2791 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
2792
2793 /* Call mini-rdr to get NetRoot name */
2794 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
2795 /* And create the NetRoot with that name */
2796 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
2797 if (NetRoot == NULL)
2798 {
2799 Status = STATUS_INSUFFICIENT_RESOURCES;
2800 _SEH2_LEAVE;
2801 }
2802 NetRoot->Type = NetRootType;
2803
2804 RxDereferenceSrvCall(SrvCall, *LockState);
2805
2806 /* Finally, create the associated VNetRoot */
2807 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
2808 if (VNetRoot == NULL)
2809 {
2810 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2811 Status = STATUS_INSUFFICIENT_RESOURCES;
2812 _SEH2_LEAVE;
2813 }
2814 RxReferenceVNetRoot(VNetRoot);
2815
2816 /* We're get closer! */
2817 NetRoot->Condition = Condition_InTransition;
2818 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2819 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2820 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2821
2822 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2823 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
2824 if (!NT_SUCCESS(Status))
2825 {
2826 RxTransitionVNetRoot(VNetRoot, Condition_Bad);
2827 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
2828 RxDereferenceVNetRoot(VNetRoot, *LockState);
2829
2830 RxContext->Create.pNetRoot = NULL;
2831 RxContext->Create.pVNetRoot = NULL;
2832 }
2833 else
2834 {
2835 PIO_STACK_LOCATION Stack;
2836
2837 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2838
2839 Stack = RxContext->CurrentIrpSp;
2840 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2841 {
2842 RxExclusivePrefixTableLockToShared(PrefixTable);
2843 *LockState = LHS_SharedLockHeld;
2844 }
2845 }
2846 }
2847 _SEH2_FINALLY
2848 {
2849 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
2850 {
2851 if (*LockState != LHS_LockNotHeld)
2852 {
2853 RxReleasePrefixTableLock(PrefixTable);
2854 *LockState = LHS_LockNotHeld;
2855 }
2856 }
2857 }
2858 _SEH2_END;
2859
2860 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
2861 return Status;
2862 }
2863
2864 /*
2865 * @implemented
2866 */
2867 VOID
2868 NTAPI
2869 RxFinishFcbInitialization(
2870 IN OUT PMRX_FCB Fcb,
2871 IN RX_FILE_TYPE FileType,
2872 IN PFCB_INIT_PACKET InitPacket OPTIONAL)
2873 {
2874 NODE_TYPE_CODE OldType;
2875
2876 PAGED_CODE();
2877
2878 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
2879
2880 OldType = Fcb->Header.NodeTypeCode;
2881 Fcb->Header.NodeTypeCode = FileType;
2882 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2883 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
2884 {
2885 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2886 }
2887 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2888 else if (InitPacket != NULL)
2889 {
2890 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
2891 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
2892 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
2893 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
2894 InitPacket->pValidDataLength->QuadPart);
2895 }
2896
2897 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2898 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2899 {
2900 /* If our FCB newly points to a file, initiliaz everything related */
2901 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
2902 !OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
2903 {
2904 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
2905 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
2906 &RxUnlockOperation);
2907
2908 ((PFCB)Fcb)->BufferedLocks.List = NULL;
2909 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
2910
2911 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
2912 }
2913 else
2914 {
2915 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
2916 }
2917 }
2918 }
2919
2920 /*
2921 * @implemented
2922 */
2923 NTSTATUS
2924 RxFinishSrvCallConstruction(
2925 PMRX_SRVCALLDOWN_STRUCTURE Calldown)
2926 {
2927 NTSTATUS Status;
2928 PSRV_CALL SrvCall;
2929 PRX_CONTEXT Context;
2930 RX_BLOCK_CONDITION Condition;
2931 PRX_PREFIX_TABLE PrefixTable;
2932
2933 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
2934
2935 SrvCall = (PSRV_CALL)Calldown->SrvCall;
2936 Context = Calldown->RxContext;
2937 PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
2938
2939 /* We have a winner, notify him */
2940 if (Calldown->BestFinisher != NULL)
2941 {
2942 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
2943
2944 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
2945
2946 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
2947 MRxSrvCallWinnerNotify,
2948 ((PMRX_SRV_CALL)SrvCall, TRUE,
2949 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
2950 if (Status != STATUS_SUCCESS)
2951 {
2952 Condition = Condition_Bad;
2953 }
2954 else
2955 {
2956 Condition = Condition_Good;
2957 }
2958 }
2959 /* Otherwise, just fail our SRV_CALL */
2960 else
2961 {
2962 Status = Calldown->CallbackContexts[0].Status;
2963 Condition = Condition_Bad;
2964 }
2965
2966 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2967 RxTransitionSrvCall(SrvCall, Condition);
2968 ExFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
2969
2970 /* If async, finish it here, otherwise, caller has already finished the stuff */
2971 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
2972 {
2973 DPRINT("Finishing async call\n");
2974
2975 RxReleasePrefixTableLock(PrefixTable);
2976
2977 /* Make sure we weren't cancelled in-between */
2978 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
2979 {
2980 Status = STATUS_CANCELLED;
2981 }
2982
2983 /* In case that was a create, context can be reused */
2984 if (Context->MajorFunction == IRP_MJ_CREATE)
2985 {
2986 RxpPrepareCreateContextForReuse(Context);
2987 }
2988
2989 /* If that's a failure, reset everything and return failure */
2990 if (Status != STATUS_SUCCESS)
2991 {
2992 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
2993 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
2994 {
2995 if (Context->Info.Buffer != NULL)
2996 {
2997 ExFreePool(Context->Info.Buffer);
2998 Context->Info.Buffer = NULL;
2999 }
3000 }
3001 Context->CurrentIrp->IoStatus.Information = 0;
3002 Context->CurrentIrp->IoStatus.Status = Status;
3003 RxCompleteRequest(Context, Status);
3004 }
3005 /* Otherwise, call resume routine and done! */
3006 else
3007 {
3008 Status = Context->ResumeRoutine(Context);
3009 if (Status != STATUS_PENDING)
3010 {
3011 RxCompleteRequest(Context, Status);
3012 }
3013
3014 DPRINT("Not completing, pending\n");
3015 }
3016 }
3017
3018 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
3019 return Status;
3020 }
3021
3022 /*
3023 * @implemented
3024 */
3025 VOID
3026 NTAPI
3027 RxFinishSrvCallConstructionDispatcher(
3028 IN PVOID Context)
3029 {
3030 KIRQL OldIrql;
3031 BOOLEAN Direct, KeepLoop;
3032
3033 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
3034
3035 /* In case of failure of starting dispatcher, context is not set
3036 * We keep track of it to fail associated SRV_CALL
3037 */
3038 Direct = (Context == NULL);
3039
3040 /* Separated thread, loop forever */
3041 while (TRUE)
3042 {
3043 PLIST_ENTRY ListEntry;
3044 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
3045
3046 /* If there are no SRV_CALL to finalize left, just finish thread */
3047 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
3048 if (IsListEmpty(&RxSrvCalldownList))
3049 {
3050 KeepLoop = FALSE;
3051 RxSrvCallConstructionDispatcherActive = FALSE;
3052 }
3053 /* Otherwise, get the SRV_CALL to finish construction */
3054 else
3055 {
3056 ListEntry = RemoveHeadList(&RxSrvCalldownList);
3057 KeepLoop = TRUE;
3058 }
3059 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
3060
3061 /* Nothing to do */
3062 if (!KeepLoop)
3063 {
3064 break;
3065 }
3066
3067 /* If direct is set, reset the finisher to avoid electing a winner
3068 * and fail SRV_CALL (see upper comment)
3069 */
3070 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
3071 if (Direct)
3072 {
3073 Calldown->BestFinisher = NULL;
3074 }
3075 /* Finish SRV_CALL construction */
3076 RxFinishSrvCallConstruction(Calldown);
3077 }
3078 }
3079
3080 VOID
3081 RxFreeFcbObject(
3082 PVOID Object)
3083 {
3084 UNIMPLEMENTED;
3085 }
3086
3087 VOID
3088 RxFreeObject(
3089 PVOID pObject)
3090 {
3091 UNIMPLEMENTED;
3092 }
3093
3094 /*
3095 * @implemented
3096 */
3097 VOID
3098 RxGetFileSizeWithLock(
3099 IN PFCB Fcb,
3100 OUT PLONGLONG FileSize)
3101 {
3102 PAGED_CODE();
3103
3104 *FileSize = Fcb->Header.FileSize.QuadPart;
3105 }
3106
3107 /*
3108 * @implemented
3109 */
3110 PEPROCESS
3111 NTAPI
3112 RxGetRDBSSProcess(
3113 VOID)
3114 {
3115 return RxData.OurProcess;
3116 }
3117
3118 /*
3119 * @implemented
3120 */
3121 NTSTATUS
3122 RxInitializeBufferingManager(
3123 PSRV_CALL SrvCall)
3124 {
3125 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
3126 InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
3127 InitializeListHead(&SrvCall->BufferingManager.HandlerList);
3128 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
3129 SrvCall->BufferingManager.DispatcherActive = FALSE;
3130 SrvCall->BufferingManager.HandlerInactive = FALSE;
3131 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
3132 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
3133 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
3134 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
3135
3136 return STATUS_SUCCESS;
3137 }
3138
3139 /*
3140 * @implemented
3141 */
3142 VOID
3143 NTAPI
3144 RxInitializeContext(
3145 IN PIRP Irp,
3146 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
3147 IN ULONG InitialContextFlags,
3148 IN OUT PRX_CONTEXT RxContext)
3149 {
3150 PIO_STACK_LOCATION Stack;
3151
3152 /* Initialize our various fields */
3153 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
3154 RxContext->NodeByteSize = sizeof(RX_CONTEXT);
3155 RxContext->ReferenceCount = 1;
3156 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
3157 RxContext->RxDeviceObject = RxDeviceObject;
3158 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
3159 RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
3160 InitializeListHead(&RxContext->BlockedOperations);
3161 RxContext->MRxCancelRoutine = NULL;
3162 RxContext->ResumeRoutine = NULL;
3163 RxContext->Flags |= InitialContextFlags;
3164 RxContext->CurrentIrp = Irp;
3165 RxContext->LastExecutionThread = PsGetCurrentThread();
3166 RxContext->OriginalThread = RxContext->LastExecutionThread;
3167
3168 /* If've got no IRP, mark RX_CONTEXT */
3169 if (Irp == NULL)
3170 {
3171 RxContext->CurrentIrpSp = NULL;
3172 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
3173 RxContext->MinorFunction = 0;
3174 }
3175 else
3176 {
3177 /* Otherwise, first determine whether we are performing async operation */
3178 Stack = IoGetCurrentIrpStackLocation(Irp);
3179 if (Stack->FileObject != NULL)
3180 {
3181 PFCB Fcb;
3182
3183 Fcb = Stack->FileObject->FsContext;
3184 if (!IoIsOperationSynchronous(Irp) ||
3185 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
3186 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
3187 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
3188 {
3189 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3190 }
3191 }
3192
3193 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
3194 {
3195 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3196 }
3197 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
3198 {
3199 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3200 }
3201
3202 /* Set proper flags if TopLevl IRP/Device */
3203 if (!RxIsThisTheTopLevelIrp(Irp))
3204 {
3205 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
3206 }
3207 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
3208 {
3209 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
3210 }
3211
3212 /* Copy stack information */
3213 RxContext->MajorFunction = Stack->MajorFunction;
3214 RxContext->MinorFunction = Stack->MinorFunction;
3215 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
3216 RxContext->CurrentIrpSp = Stack;
3217
3218 /* If we have a FO associated, learn for more */
3219 if (Stack->FileObject != NULL)
3220 {
3221 PFCB Fcb;
3222 PFOBX Fobx;
3223
3224 /* Get the FCB and CCB (FOBX) */
3225 Fcb = Stack->FileObject->FsContext;
3226 Fobx = Stack->FileObject->FsContext2;
3227 RxContext->pFcb = (PMRX_FCB)Fcb;
3228 if (Fcb != NULL && NodeTypeIsFcb(Fcb))
3229 {
3230 RxContext->NonPagedFcb = Fcb->NonPaged;
3231 }
3232
3233 /* We have a FOBX, this not a DFS opening, keep track of it */
3234 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
3235 {
3236 RxContext->pFobx = (PMRX_FOBX)Fobx;
3237 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
3238 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3239 {
3240 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
3241 }
3242 }
3243 else
3244 {
3245 RxContext->pFobx = NULL;
3246 }
3247
3248 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3249 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
3250 Fobx != NULL)
3251 {
3252 PV_NET_ROOT VNetRoot = NULL;
3253
3254 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3255 {
3256 VNetRoot = Fcb->VNetRoot;
3257 }
3258 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
3259 {
3260 VNetRoot = (PV_NET_ROOT)Fobx;
3261 }
3262
3263 if (VNetRoot != NULL)
3264 {
3265 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3266 }
3267 }
3268
3269 /* Remember if that's a write through file */
3270 RxContext->RealDevice = Stack->FileObject->DeviceObject;
3271 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
3272 {
3273 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
3274 }
3275 }
3276 }
3277
3278 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
3279 {
3280 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3281 RxContext, RxContext->MinorFunction, Irp,
3282 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
3283 RxContext->SerialNumber);
3284 }
3285 }
3286
3287 /*
3288 * @implemented
3289 */
3290 NTSTATUS
3291 NTAPI
3292 RxInitializeDispatcher(
3293 VOID)
3294 {
3295 NTSTATUS Status;
3296 HANDLE ThreadHandle;
3297
3298 PAGED_CODE();