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