13f206ceafe03cd4abee813cc7185b2051dcad4d
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <dfs.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 VOID
37 RxAssert(
38 PVOID Assert,
39 PVOID File,
40 ULONG Line,
41 PVOID Message);
42
43 VOID
44 NTAPI
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context);
47
48 NTSTATUS
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown);
51
52 VOID
53 NTAPI
54 RxFinishSrvCallConstructionDispatcher(
55 IN PVOID Context);
56
57 NTSTATUS
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60 WORK_QUEUE_TYPE WorkQueueType,
61 PRX_WORK_DISPATCH_ITEM DispatchItem);
62
63 PVOID
64 RxNewMapUserBuffer(
65 PRX_CONTEXT RxContext);
66
67 VOID
68 NTAPI
69 RxWorkItemDispatcher(
70 PVOID Context);
71
72 extern ULONG ReadAheadGranularity;
73
74 volatile LONG RxNumberOfActiveFcbs = 0;
75 ULONG SerialNumber = 1;
76 PVOID RxNull = NULL;
77 volatile ULONG RxContextSerialNumberCounter;
78 BOOLEAN RxStopOnLoudCompletion = TRUE;
79 BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
80 LIST_ENTRY RxSrvCalldownList;
81 RX_SPIN_LOCK RxStrucSupSpinLock;
82 ULONG RdbssReferenceTracingValue;
83 LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
84 LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
85 RX_DISPATCHER RxDispatcher;
86 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
87 FAST_MUTEX RxLowIoPagingIoSyncMutex;
88 BOOLEAN RxContinueFromAssert = TRUE;
89 #if DBG
90 BOOLEAN DumpDispatchRoutine = TRUE;
91 #else
92 BOOLEAN DumpDispatchRoutine = FALSE;
93 #endif
94
95 #ifdef ASSERT
96 #undef ASSERT
97 #endif
98
99 #define ASSERT(exp) \
100 if (!(exp)) \
101 { \
102 RxAssert(#exp, __FILE__, __LINE__, NULL); \
103 }
104
105 /* FUNCTIONS ****************************************************************/
106
107 /*
108 * @implemented
109 */
110 VOID
111 RxAddVirtualNetRootToNetRoot(
112 PNET_ROOT NetRoot,
113 PV_NET_ROOT VNetRoot)
114 {
115 PAGED_CODE();
116
117 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
118
119 /* Insert in the VNetRoot list - make sure lock is held */
120 ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
121
122 VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
123 ++NetRoot->NumberOfVirtualNetRoots;
124 InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
125 }
126
127 /*
128 * @implemented
129 */
130 PVOID
131 RxAllocateFcbObject(
132 PRDBSS_DEVICE_OBJECT RxDeviceObject,
133 NODE_TYPE_CODE NodeType,
134 POOL_TYPE PoolType,
135 ULONG NameSize,
136 PVOID AlreadyAllocatedObject)
137 {
138 PFCB Fcb;
139 PFOBX Fobx;
140 PSRV_OPEN SrvOpen;
141 PVOID Buffer, PAPNBuffer;
142 PNON_PAGED_FCB NonPagedFcb;
143 PMINIRDR_DISPATCH Dispatch;
144 ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
145
146 PAGED_CODE();
147
148 Dispatch = RxDeviceObject->Dispatch;
149
150 NonPagedSize = 0;
151 FobxSize = 0;
152 SrvOpenSize = 0;
153 FcbSize = 0;
154
155 Fcb = NULL;
156 Fobx = NULL;
157 SrvOpen = NULL;
158 NonPagedFcb = NULL;
159 PAPNBuffer = NULL;
160
161 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
162 if (NodeType == RDBSS_NTC_FOBX)
163 {
164 FobxSize = sizeof(FOBX);
165 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
166 {
167 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
168 }
169 }
170 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
171 else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
172 {
173 SrvOpenSize = sizeof(SRV_OPEN);
174 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
175 {
176 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
177 }
178
179 FobxSize = sizeof(FOBX);
180 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
181 {
182 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
183 }
184 }
185 /* Otherwise, we're asked to allocate a FCB */
186 else
187 {
188 /* So, allocate the FCB and its extension if asked */
189 FcbSize = sizeof(FCB);
190 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
191 {
192 FcbSize += QuadAlign(Dispatch->MRxFcbSize);
193 }
194
195 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
196 * Otherwise, it will be allocated later on, specifically
197 */
198 if (PoolType == NonPagedPool)
199 {
200 NonPagedSize = sizeof(NON_PAGED_FCB);
201 }
202
203 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
204 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
205 {
206 SrvOpenSize = sizeof(SRV_OPEN);
207 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
208 {
209 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
210 }
211
212 FobxSize = sizeof(FOBX);
213 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
214 {
215 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
216 }
217 }
218 }
219
220 /* If we already have a buffer, go ahead */
221 if (AlreadyAllocatedObject != NULL)
222 {
223 Buffer = AlreadyAllocatedObject;
224 }
225 /* Otherwise, allocate it */
226 else
227 {
228 Buffer = ExAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
229 if (Buffer == NULL)
230 {
231 return NULL;
232 }
233 }
234
235 /* Now, get the pointers - FOBX is easy */
236 if (NodeType == RDBSS_NTC_FOBX)
237 {
238 Fobx = Buffer;
239 }
240 /* SRV_OPEN first, FOBX next */
241 else if (NodeType == RDBSS_NTC_SRVOPEN)
242 {
243 SrvOpen = Buffer;
244 Fobx = Add2Ptr(Buffer, SrvOpenSize);
245 }
246 else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
247 {
248 SrvOpen = Buffer;
249 }
250 else
251 {
252 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
253 Fcb = Buffer;
254 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
255 {
256 SrvOpen = Add2Ptr(Buffer, FcbSize);
257 Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
258 }
259
260 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
261 if (PoolType != NonPagedPool)
262 {
263 NonPagedFcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
264 if (NonPagedFcb == NULL)
265 {
266 ExFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
267 return NULL;
268 }
269
270 PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
271 }
272 /* Otherwise, just point at the right place in what has been allocated previously */
273 else
274 {
275 NonPagedFcb = Add2Ptr(Fobx, FobxSize);
276 PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
277 }
278 }
279
280 /* If we have allocated a SRV_OPEN, initialize it */
281 if (SrvOpen != NULL)
282 {
283 ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
284
285 if (NodeType == RDBSS_NTC_SRVOPEN)
286 {
287 SrvOpen->InternalFobx = Fobx;
288 }
289 else
290 {
291 SrvOpen->InternalFobx = NULL;
292 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
293 }
294
295 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
296 {
297 SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
298 }
299
300 InitializeListHead(&SrvOpen->SrvOpenQLinks);
301 }
302
303 /* If we have allocated a FOBX, initialize it */
304 if (Fobx != NULL)
305 {
306 ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
307
308 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
309 {
310 Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
311 }
312 }
313
314 /* If we have allocated a FCB, initialize it */
315 if (Fcb != NULL)
316 {
317 ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
318
319 Fcb->NonPaged = NonPagedFcb;
320 ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
321 Fcb->CopyOfNonPaged = NonPagedFcb;
322 NonPagedFcb->FcbBackPointer = Fcb;
323
324 Fcb->InternalSrvOpen = SrvOpen;
325 Fcb->InternalFobx = Fobx;
326
327 Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
328 Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
329 Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
330
331 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
332 {
333 Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
334 }
335
336 ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
337
338 InterlockedIncrement(&RxNumberOfActiveFcbs);
339 InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
340
341 ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
342 FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
343 }
344
345 return Buffer;
346 }
347
348 /*
349 * @implemented
350 */
351 PVOID
352 RxAllocateObject(
353 NODE_TYPE_CODE NodeType,
354 PMINIRDR_DISPATCH MRxDispatch,
355 ULONG NameLength)
356 {
357 ULONG Tag, ObjectSize;
358 PVOID Object, *Extension;
359 PRX_PREFIX_ENTRY PrefixEntry;
360 USHORT StructSize, ExtensionSize;
361
362 PAGED_CODE();
363
364 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
365 ExtensionSize = 0;
366 switch (NodeType)
367 {
368 case RDBSS_NTC_SRVCALL:
369 Tag = RX_SRVCALL_POOLTAG;
370 StructSize = sizeof(SRV_CALL);
371 if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
372 {
373 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
374 }
375 break;
376
377 case RDBSS_NTC_NETROOT:
378 Tag = RX_NETROOT_POOLTAG;
379 StructSize = sizeof(NET_ROOT);
380 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
381 {
382 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
383 }
384 break;
385
386 case RDBSS_NTC_V_NETROOT:
387 Tag = RX_V_NETROOT_POOLTAG;
388 StructSize = sizeof(V_NET_ROOT);
389 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
390 {
391 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
392 }
393 break;
394
395 default:
396 ASSERT(FALSE);
397 break;
398 }
399
400 /* Now, allocate the object */
401 ObjectSize = ExtensionSize + StructSize + NameLength;
402 Object = ExAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
403 if (Object == NULL)
404 {
405 return NULL;
406 }
407 /* Initialize it */
408 ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
409
410 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
411 switch (NodeType)
412 {
413 case RDBSS_NTC_SRVCALL:
414 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
415 Extension = &((PSRV_CALL)Object)->Context;
416 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
417 break;
418
419 case RDBSS_NTC_NETROOT:
420 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
421 Extension = &((PNET_ROOT)Object)->Context;
422 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
423 break;
424
425 case RDBSS_NTC_V_NETROOT:
426 PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
427 Extension = &((PV_NET_ROOT)Object)->Context;
428 break;
429
430 default:
431 ASSERT(FALSE);
432 break;
433 }
434
435 /* Set the prefix table unicode string */
436 RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
437 PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
438 PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
439 PrefixEntry->Prefix.Length = NameLength;
440 PrefixEntry->Prefix.MaximumLength = NameLength;
441 PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
442
443 /* Return the extension if we are asked to manage it */
444 if (ExtensionSize != 0)
445 {
446 *Extension = Add2Ptr(Object, StructSize);
447 }
448
449 return Object;
450 }
451
452 /*
453 * @implemented
454 */
455 VOID
456 RxAssert(
457 PVOID Assert,
458 PVOID File,
459 ULONG Line,
460 PVOID Message)
461 {
462 CHAR Response[2];
463 CONTEXT Context;
464
465 /* If we're not asked to continue, just stop the system */
466 if (!RxContinueFromAssert)
467 {
468 KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
469 }
470
471 /* Otherwise, capture context to offer the user to dump it */
472 RtlCaptureContext(&Context);
473
474 /* Loop until the user hits 'i' */
475 while (TRUE)
476 {
477 /* If no file provided, use empty name */
478 if (File == NULL)
479 {
480 File = "";
481 }
482
483 /* If no message provided, use empty one */
484 if (Message == NULL)
485 {
486 Message = "";
487 }
488
489 /* Display the message */
490 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
491 /* And ask the user */
492 DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
493 /* If he asks for ignore, quit
494 * In case of invalid input, ask again
495 */
496 if (Response[0] != 'B' && Response[0] != 'b')
497 {
498 if (Response[0] == 'I' || Response[0] == 'i')
499 {
500 return;
501 }
502
503 continue;
504 }
505
506 /* Break: offer the user to dump the context and break */
507 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
508 DbgBreakPoint();
509
510 /* Continue looping, so that after dump, execution can continue (with ignore) */
511 }
512 }
513
514 /*
515 * @implemented
516 */
517 VOID
518 NTAPI
519 RxBootstrapWorkerThreadDispatcher(
520 IN PVOID WorkQueue)
521 {
522 PRX_WORK_QUEUE RxWorkQueue;
523
524 PAGED_CODE();
525
526 RxWorkQueue = WorkQueue;
527 RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
528 }
529
530 NTSTATUS
531 RxCheckVNetRootCredentials(
532 PRX_CONTEXT RxContext,
533 PV_NET_ROOT VNetRoot,
534 PLUID LogonId,
535 PUNICODE_STRING UserName,
536 PUNICODE_STRING UserDomain,
537 PUNICODE_STRING Password,
538 ULONG Flags)
539 {
540 PAGED_CODE();
541
542 /* If that's a UNC name, there's nothing to process */
543 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
544 (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
545 Flags != 0))
546 {
547 return STATUS_MORE_PROCESSING_REQUIRED;
548 }
549
550 /* Compare the logon ID in the VNetRoot with the one provided */
551 if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
552 {
553 return STATUS_MORE_PROCESSING_REQUIRED;
554 }
555
556 /* No credential provided? That's OK */
557 if (UserName == NULL && UserDomain == NULL && Password == NULL)
558 {
559 return STATUS_SUCCESS;
560 }
561
562 /* Left to do! */
563 UNIMPLEMENTED;
564 return STATUS_NOT_IMPLEMENTED;
565 }
566
567 NTSTATUS
568 RxCompleteRequest(
569 PRX_CONTEXT Context,
570 NTSTATUS Status)
571 {
572 PIRP Irp;
573
574 PAGED_CODE();
575
576 DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
577
578 ASSERT(Context != NULL);
579 ASSERT(Context->CurrentIrp != NULL);
580 Irp = Context->CurrentIrp;
581
582 /* Debug what the caller asks for */
583 if (Context->LoudCompletionString != NULL)
584 {
585 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
586 /* Does the user asks to stop on failed completion */
587 if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
588 {
589 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
590 }
591 }
592
593 /* Complete for real */
594 Context->CurrentIrp = NULL;
595 RxCompleteRequest_Real(Context, Irp, Status);
596
597 DPRINT("Status: %lx\n", Status);
598 return Status;
599 }
600
601 /*
602 * @implemented
603 */
604 VOID
605 RxCompleteRequest_Real(
606 IN PRX_CONTEXT RxContext,
607 IN PIRP Irp,
608 IN NTSTATUS Status)
609 {
610 CCHAR Boost;
611 KIRQL OldIrql;
612 PIO_STACK_LOCATION Stack;
613
614 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
615
616 /* Nothing to complete, just free context */
617 if (Irp == NULL)
618 {
619 DPRINT("NULL IRP for %p\n", RxContext);
620 if (RxContext != NULL)
621 {
622 RxDereferenceAndDeleteRxContext_Real(RxContext);
623 }
624
625 return;
626 }
627
628 /* Remove cancel routine */
629 IoAcquireCancelSpinLock(&OldIrql);
630 IoSetCancelRoutine(Irp, NULL);
631 IoReleaseCancelSpinLock(OldIrql);
632
633 /* Select the boost, given the success/paging operation */
634 if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
635 {
636 Boost = IO_DISK_INCREMENT;
637 }
638 else
639 {
640 Irp->IoStatus.Information = 0;
641 Boost = IO_NO_INCREMENT;
642 }
643 Irp->IoStatus.Status = Status;
644
645 if (RxContext != NULL)
646 {
647 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
648 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
649 {
650 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
651 RxContext->MinorFunction, RxContext, Irp,
652 Status, Irp->IoStatus.Information, RxContext->SerialNumber);
653 }
654 }
655
656 /* If that's an opening, there might be a canonical name allocated,
657 * if completion isn't pending, release it
658 */
659 Stack = IoGetCurrentIrpStackLocation(Irp);
660 if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
661 RxContext != NULL)
662 {
663 if (BooleanFlagOn(RxContext->Create.Flags, 2))
664 {
665 Stack->FileObject->FileName.Length += sizeof(WCHAR);
666 }
667
668 RxpPrepareCreateContextForReuse(RxContext);
669 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
670 }
671
672 /* If it's a write, validate the correct behavior of the operation */
673 if (Stack->MajorFunction == IRP_MJ_WRITE)
674 {
675 if (NT_SUCCESS(Irp->IoStatus.Status))
676 {
677 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
678 }
679 }
680
681 /* If it's pending, make sure IRP is marked as such */
682 if (RxContext != NULL)
683 {
684 if (RxContext->PendingReturned)
685 {
686 ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
687 }
688 }
689
690 /* Complete now */
691 DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
692 IoCompleteRequest(Irp, Boost);
693
694 /* If there's a context, dereference it */
695 if (RxContext != NULL)
696 {
697 RxDereferenceAndDeleteRxContext_Real(RxContext);
698 }
699 }
700
701 VOID
702 RxCompleteSrvOpenKeyAssociation(
703 IN OUT PSRV_OPEN SrvOpen)
704 {
705 UNIMPLEMENTED;
706 }
707
708 /*
709 * @implemented
710 */
711 NTSTATUS
712 RxConstructNetRoot(
713 IN PRX_CONTEXT RxContext,
714 IN PSRV_CALL SrvCall,
715 IN PNET_ROOT NetRoot,
716 IN PV_NET_ROOT VirtualNetRoot,
717 OUT PLOCK_HOLDING_STATE LockHoldingState)
718 {
719 NTSTATUS Status;
720 PRX_PREFIX_TABLE PrefixTable;
721 PMRX_CREATENETROOT_CONTEXT Context;
722 RX_BLOCK_CONDITION RootCondition, VRootCondition;
723
724 PAGED_CODE();
725
726 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
727 VirtualNetRoot, LockHoldingState);
728
729 /* Validate the lock is exclusively held */
730 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
731 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
732
733 /* Allocate the context */
734 Context = ExAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
735 if (Context == NULL)
736 {
737 return STATUS_INSUFFICIENT_RESOURCES;
738 }
739
740 /* We can release lock now */
741 RxReleasePrefixTableLock(PrefixTable);
742 *LockHoldingState = LHS_LockNotHeld;
743
744 RootCondition = Condition_Bad;
745 VRootCondition = Condition_Bad;
746
747 /* Initialize the context */
748 RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
749 KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
750 Context->RxContext = RxContext;
751 Context->pVNetRoot = VirtualNetRoot;
752 Context->Callback = RxCreateNetRootCallBack;
753
754 /* And call the mini-rdr */
755 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
756 if (Status == STATUS_PENDING)
757 {
758 /* Wait for the mini-rdr to be done */
759 KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
760 /* Update the structures condition according to mini-rdr return */
761 if (NT_SUCCESS(Context->NetRootStatus))
762 {
763 if (NT_SUCCESS(Context->VirtualNetRootStatus))
764 {
765 RootCondition = Condition_Good;
766 VRootCondition = Condition_Good;
767 Status = STATUS_SUCCESS;
768 }
769 else
770 {
771 RootCondition = Condition_Good;
772 Status = Context->VirtualNetRootStatus;
773 }
774 }
775 else
776 {
777 Status = Context->VirtualNetRootStatus;
778 if (NT_SUCCESS(Status))
779 {
780 Status = Context->NetRootStatus;
781 }
782 }
783 }
784 else
785 {
786 /* It has to return STATUS_PENDING! */
787 ASSERT(FALSE);
788 }
789
790 /* Acquire lock again - for caller lock status will remain unchanged */
791 ASSERT(*LockHoldingState == LHS_LockNotHeld);
792 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
793 *LockHoldingState = LHS_ExclusiveLockHeld;
794
795 /* Do the transition to the condition got from mini-rdr */
796 RxTransitionNetRoot(NetRoot, RootCondition);
797 RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
798
799 /* Context is not longer needed */
800 ExFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
801
802 DPRINT("Status: %x\n", Status);
803
804 return Status;
805 }
806
807 /*
808 * @implemented
809 */
810 NTSTATUS
811 RxConstructSrvCall(
812 IN PRX_CONTEXT RxContext,
813 IN PSRV_CALL SrvCall,
814 OUT PLOCK_HOLDING_STATE LockHoldingState)
815 {
816 NTSTATUS Status;
817 PRX_PREFIX_TABLE PrefixTable;
818 PRDBSS_DEVICE_OBJECT RxDeviceObject;
819 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
820 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
821
822 PAGED_CODE();
823
824 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
825
826 /* Validate the lock is exclusively held */
827 RxDeviceObject = RxContext->RxDeviceObject;
828 PrefixTable = RxDeviceObject->pRxNetNameTable;
829 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
830
831 /* Allocate the context for mini-rdr */
832 Calldown = ExAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
833 if (Calldown == NULL)
834 {
835 SrvCall->Context = NULL;
836 SrvCall->Condition = Condition_Bad;
837 RxReleasePrefixTableLock(PrefixTable);
838 *LockHoldingState = LHS_LockNotHeld;
839 return STATUS_INSUFFICIENT_RESOURCES;
840 }
841
842 /* Initialize it */
843 RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
844
845 SrvCall->Context = NULL;
846 SrvCall->Condition = Condition_InTransition;
847
848 RxReleasePrefixTableLock(PrefixTable);
849 *LockHoldingState = LHS_LockNotHeld;
850
851 CallbackContext = &Calldown->CallbackContexts[0];
852 DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
853 DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
854 CallbackContext->SrvCalldownStructure = Calldown;
855 CallbackContext->CallbackContextOrdinal = 0;
856 CallbackContext->RxDeviceObject = RxDeviceObject;
857
858 RxReferenceSrvCall(SrvCall);
859
860 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
861 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
862 {
863 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
864 }
865 else
866 {
867 KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
868 }
869
870 Calldown->NumberToWait = 1;
871 Calldown->NumberRemaining = 1;
872 Calldown->RxContext = RxContext;
873 Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
874 Calldown->CallBack = RxCreateSrvCallCallBack;
875 Calldown->BestFinisher = NULL;
876 CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
877 InitializeListHead(&Calldown->SrvCalldownList);
878
879 /* Call the mini-rdr */
880 ASSERT(RxDeviceObject->Dispatch != NULL);
881 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
882 ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
883 Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
884 /* It has to return STATUS_PENDING! */
885 ASSERT(Status == STATUS_PENDING);
886
887 /* No async, start completion */
888 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
889 {
890 KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
891
892 /* Finish construction - we'll notify mini-rdr it's the winner */
893 Status = RxFinishSrvCallConstruction(Calldown);
894 if (!NT_SUCCESS(Status))
895 {
896 RxReleasePrefixTableLock(PrefixTable);
897 *LockHoldingState = LHS_LockNotHeld;
898 }
899 else
900 {
901 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
902 *LockHoldingState = LHS_ExclusiveLockHeld;
903 }
904 }
905
906 DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
907 return Status;
908 }
909
910 /*
911 * @implemented
912 */
913 NTSTATUS
914 RxConstructVirtualNetRoot(
915 IN PRX_CONTEXT RxContext,
916 IN PUNICODE_STRING CanonicalName,
917 IN NET_ROOT_TYPE NetRootType,
918 OUT PV_NET_ROOT *VirtualNetRootPointer,
919 OUT PLOCK_HOLDING_STATE LockHoldingState,
920 OUT PRX_CONNECTION_ID RxConnectionId)
921 {
922 NTSTATUS Status;
923 PV_NET_ROOT VNetRoot;
924 RX_BLOCK_CONDITION Condition;
925 UNICODE_STRING LocalNetRootName, FilePathName;
926
927 PAGED_CODE();
928
929 ASSERT(*LockHoldingState != LHS_LockNotHeld);
930
931 VNetRoot = NULL;
932 Condition = Condition_Bad;
933 /* Before creating the VNetRoot, try to find the appropriate connection */
934 Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
935 &LocalNetRootName, &FilePathName,
936 LockHoldingState, RxConnectionId);
937 /* Found and active */
938 if (Status == STATUS_CONNECTION_ACTIVE)
939 {
940 /* We need a new VNetRoot */
941 VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
942 CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
943 if (VNetRoot != NULL)
944 {
945 RxReferenceVNetRoot(VNetRoot);
946 }
947
948 /* Dereference previous VNetRoot */
949 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
950 /* Reset and start construct (new structures will replace old ones) */
951 RxContext->Create.pSrvCall = NULL;
952 RxContext->Create.pNetRoot = NULL;
953 RxContext->Create.pVNetRoot = NULL;
954
955 /* Construct new NetRoot */
956 if (VNetRoot != NULL)
957 {
958 Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
959 (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
960 if (NT_SUCCESS(Status))
961 {
962 Condition = Condition_Good;
963 }
964 }
965 else
966 {
967 Status = STATUS_INSUFFICIENT_RESOURCES;
968 }
969 }
970 else
971 {
972 /* If it failed creating the connection, leave */
973 if (Status != STATUS_SUCCESS)
974 {
975 if (*LockHoldingState != LHS_LockNotHeld)
976 {
977 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
978 *LockHoldingState = LHS_LockNotHeld;
979 }
980
981 *VirtualNetRootPointer = VNetRoot;
982 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
983 return Status;
984 }
985
986 *LockHoldingState = LHS_ExclusiveLockHeld;
987
988 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
989 Condition = Condition_Good;
990 }
991
992 /* We have a non stable VNetRoot - transition it */
993 if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
994 {
995 RxTransitionVNetRoot(VNetRoot, Condition);
996 }
997
998 /* If recreation failed */
999 if (Status != STATUS_SUCCESS)
1000 {
1001 /* Dereference potential VNetRoot */
1002 if (VNetRoot != NULL)
1003 {
1004 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1005 RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1006 VNetRoot = NULL;
1007 }
1008
1009 /* Release lock */
1010 if (*LockHoldingState != LHS_LockNotHeld)
1011 {
1012 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1013 *LockHoldingState = LHS_LockNotHeld;
1014 }
1015
1016 /* Set NULL ptr */
1017 *VirtualNetRootPointer = VNetRoot;
1018 return Status;
1019 }
1020
1021 /* Return the allocated VNetRoot */
1022 *VirtualNetRootPointer = VNetRoot;
1023 return Status;
1024 }
1025
1026 /*
1027 * @implemented
1028 */
1029 PFCB
1030 RxCreateNetFcb(
1031 IN PRX_CONTEXT RxContext,
1032 IN PV_NET_ROOT VNetRoot,
1033 IN PUNICODE_STRING Name)
1034 {
1035 PFCB Fcb;
1036 BOOLEAN FakeFcb;
1037 PNET_ROOT NetRoot;
1038 POOL_TYPE PoolType;
1039 NODE_TYPE_CODE NodeType;
1040 PIO_STACK_LOCATION Stack;
1041 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1042
1043 PAGED_CODE();
1044
1045 /* We need a decent VNetRoot */
1046 ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1047
1048 NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1049 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1050 ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1051
1052 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1053 ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1054
1055 Stack = RxContext->CurrentIrpSp;
1056
1057 /* Do we need to create a fake FCB? Like for renaming */
1058 FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1059 !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
1060 ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1061
1062 PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
1063 NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
1064
1065 /* Allocate the FCB */
1066 Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1067 NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1068 if (Fcb == NULL)
1069 {
1070 return NULL;
1071 }
1072
1073 /* Initialize the FCB */
1074 Fcb->CachedNetRootType = NetRoot->Type;
1075 Fcb->RxDeviceObject = RxDeviceObject;
1076 Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1077 Fcb->VNetRoot = VNetRoot;
1078 Fcb->pNetRoot = VNetRoot->pNetRoot;
1079
1080 InitializeListHead(&Fcb->SrvOpenList);
1081 Fcb->SrvOpenListVersion = 0;
1082
1083 Fcb->FcbTableEntry.Path.Length = Name->Length;
1084 Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
1085 Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1086 RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1087 NetRoot->InnerNamePrefix.Length);
1088 RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1089
1090 /* Copy back parameters from RxContext */
1091 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1092 {
1093 Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
1094 }
1095
1096 InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
1097
1098 if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
1099 {
1100 Fcb->FcbState |= FCB_STATE_PAGING_FILE;
1101 }
1102
1103 if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1104 {
1105 Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
1106 }
1107
1108 Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1109 ExInitializeResourceLite(Fcb->Header.Resource);
1110
1111 Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1112 ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1113
1114 Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
1115 ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
1116
1117 /* Fake FCB doesn't go in prefix table */
1118 if (FakeFcb)
1119 {
1120 Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
1121 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
1122 DPRINT("Fake FCB: %p\n", Fcb);
1123 }
1124 else
1125 {
1126 RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1127 }
1128
1129 RxReferenceVNetRoot(VNetRoot);
1130 InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1131
1132 Fcb->ulFileSizeVersion = 0;
1133
1134 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1135 RxReferenceNetFcb(Fcb);
1136
1137 return Fcb;
1138 }
1139
1140 /*
1141 * @implemented
1142 */
1143 PMRX_FOBX
1144 NTAPI
1145 RxCreateNetFobx(
1146 OUT PRX_CONTEXT RxContext,
1147 IN PMRX_SRV_OPEN MrxSrvOpen)
1148 {
1149 PFCB Fcb;
1150 PFOBX Fobx;
1151 ULONG Flags;
1152 PNET_ROOT NetRoot;
1153 PSRV_OPEN SrvOpen;
1154 POOL_TYPE PoolType;
1155
1156 PAGED_CODE();
1157
1158 SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1159 ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1160 ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1161 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1162
1163 Fcb = SrvOpen->Fcb;
1164 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1165 /* Can we use pre-allocated FOBX? */
1166 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
1167 {
1168 Fobx = Fcb->InternalFobx;
1169 /* Call allocate to initialize the FOBX */
1170 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1171 /* Mark it used now */
1172 Fcb->FcbState |= FCB_STATE_FOBX_USED;
1173 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1174 }
1175 else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1176 {
1177 Fobx = SrvOpen->InternalFobx;
1178 /* Call allocate to initialize the FOBX */
1179 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1180 /* Mark it used now */
1181 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1182 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1183 }
1184 else
1185 {
1186 /* Last case, we cannot, allocate a FOBX */
1187 Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
1188 Flags = 0;
1189 }
1190
1191 /* Allocation failed! */
1192 if (Fobx == NULL)
1193 {
1194 return NULL;
1195 }
1196
1197 /* Set flags */
1198 Fobx->Flags = Flags;
1199
1200 /* Initialize throttling */
1201 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1202 if (NetRoot != NULL)
1203 {
1204 if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1205 {
1206 RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1207 NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1208 NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1209 }
1210 else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1211 {
1212 RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1213 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1214 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1215 }
1216 }
1217
1218 /* Propagate flags fron RxContext */
1219 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1220 {
1221 Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1222 }
1223
1224 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1225 {
1226 Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1227 }
1228
1229 /* Continue init */
1230 Fobx->FobxSerialNumber = 0;
1231 Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1232 Fobx->NodeReferenceCount = 1;
1233 Fobx->RxDeviceObject = Fcb->RxDeviceObject;
1234
1235 RxReferenceSrvOpen(SrvOpen);
1236 InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1237
1238 InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1239 InitializeListHead(&Fobx->ScavengerFinalizationList);
1240 InitializeListHead(&Fobx->ClosePendingList);
1241
1242 Fobx->CloseTime.QuadPart = 0;
1243 Fobx->fOpenCountDecremented = FALSE;
1244
1245 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1246
1247 return (PMRX_FOBX)Fobx;
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 PNET_ROOT
1254 RxCreateNetRoot(
1255 IN PSRV_CALL SrvCall,
1256 IN PUNICODE_STRING Name,
1257 IN ULONG NetRootFlags,
1258 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1259 {
1260 PNET_ROOT NetRoot;
1261 USHORT CaseInsensitiveLength;
1262 PRX_PREFIX_TABLE PrefixTable;
1263
1264 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1265
1266 PAGED_CODE();
1267
1268 /* We need a SRV_CALL */
1269 ASSERT(SrvCall != NULL);
1270
1271 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1272 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1273
1274 /* Get name length */
1275 CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1276 if (CaseInsensitiveLength > MAXUSHORT)
1277 {
1278 return NULL;
1279 }
1280
1281 /* Allocate the NetRoot */
1282 NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1283 CaseInsensitiveLength);
1284 if (NetRoot == NULL)
1285 {
1286 return NULL;
1287 }
1288
1289 /* Construct name */
1290 RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1291 Name->Buffer, Name->Length);
1292 if (SrvCall->PrefixEntry.Prefix.Length != 0)
1293 {
1294 RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1295 SrvCall->PrefixEntry.Prefix.Length);
1296 }
1297
1298 if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1299 {
1300 CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1301 }
1302 /* Inisert in prefix table */
1303 RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1304 (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1305 RxConnectionId);
1306
1307 /* Prepare the FCB table */
1308 RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1309
1310 InitializeListHead(&NetRoot->TransitionWaitList);
1311 InitializeListHead(&NetRoot->ScavengerFinalizationList);
1312 InitializeListHead(&NetRoot->VirtualNetRoots);
1313
1314 RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
1315
1316 NetRoot->SerialNumberForEnum = SerialNumber++;
1317 NetRoot->Flags |= NetRootFlags;
1318 NetRoot->DiskParameters.ClusterSize = 1;
1319 NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1320 NetRoot->SrvCall = SrvCall;
1321
1322 RxReferenceSrvCall(SrvCall);
1323
1324 DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1325 return NetRoot;
1326 }
1327
1328 /*
1329 * @implemented
1330 */
1331 VOID
1332 NTAPI
1333 RxCreateNetRootCallBack(
1334 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1335 {
1336 PAGED_CODE();
1337
1338 KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1339 }
1340
1341 /*
1342 * @implemented
1343 */
1344 PRX_CONTEXT
1345 NTAPI
1346 RxCreateRxContext(
1347 IN PIRP Irp,
1348 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1349 IN ULONG InitialContextFlags)
1350 {
1351 KIRQL OldIrql;
1352 PRX_CONTEXT Context;
1353
1354 ASSERT(RxDeviceObject != NULL);
1355
1356 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1357
1358 InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
1359 InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1360
1361 /* Allocate the context from our lookaside list */
1362 Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1363 if (Context == NULL)
1364 {
1365 return NULL;
1366 }
1367
1368 /* And initialize it */
1369 RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1370 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1371 ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
1372
1373 /* Add it to our global list */
1374 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1375 InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1376 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1377
1378 DPRINT("Context: %p\n", Context);
1379 return Context;
1380 }
1381
1382 /*
1383 * @implemented
1384 */
1385 PSRV_CALL
1386 RxCreateSrvCall(
1387 IN PRX_CONTEXT RxContext,
1388 IN PUNICODE_STRING Name,
1389 IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1390 IN PRX_CONNECTION_ID RxConnectionId)
1391 {
1392 ULONG NameLength;
1393 PSRV_CALL SrvCall;
1394
1395 PAGED_CODE();
1396
1397 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1398
1399 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1400
1401 /* Get the name length */
1402 NameLength = Name->Length + 2 * sizeof(WCHAR);
1403 if (InnerNamePrefix != NULL)
1404 {
1405 NameLength += InnerNamePrefix->Length;
1406 }
1407
1408 /* Allocate the object */
1409 SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1410 if (SrvCall == NULL)
1411 {
1412 return NULL;
1413 }
1414
1415 /* Initialize it */
1416 SrvCall->SerialNumberForEnum = SerialNumber++;
1417 SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1418 RxInitializeBufferingManager(SrvCall);
1419 InitializeListHead(&SrvCall->TransitionWaitList);
1420 InitializeListHead(&SrvCall->ScavengerFinalizationList);
1421 RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
1422 RxInitializeSrvCallParameters(RxContext, SrvCall);
1423 RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1424 SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1425 SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1426 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1427 SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1428
1429 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1430 return SrvCall;
1431 }
1432
1433 /*
1434 * @implemented
1435 */
1436 VOID
1437 NTAPI
1438 RxCreateSrvCallCallBack(
1439 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
1440 {
1441 KIRQL OldIrql;
1442 PSRV_CALL SrvCall;
1443 PRX_CONTEXT RxContext;
1444 ULONG NumberRemaining;
1445 BOOLEAN StartDispatcher;
1446 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1447
1448 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1449
1450 /* Get our context structures */
1451 Calldown = Context->SrvCalldownStructure;
1452 SrvCall = (PSRV_CALL)Calldown->SrvCall;
1453
1454 /* If it is a success, that's the winner */
1455 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1456 if (Context->Status == STATUS_SUCCESS)
1457 {
1458 Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1459 Calldown->BestFinisher = Context->RxDeviceObject;
1460 }
1461 NumberRemaining = --Calldown->NumberRemaining;
1462 SrvCall->Status = Context->Status;
1463 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1464
1465 /* Still some to ask, keep going */
1466 if (NumberRemaining != 0)
1467 {
1468 return;
1469 }
1470
1471 /* If that's not async, signal we're done */
1472 RxContext = Calldown->RxContext;
1473 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1474 {
1475 KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1476 return;
1477 }
1478 /* If that's a mailslot, finish construction, no more to do */
1479 else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1480 {
1481 RxFinishSrvCallConstruction(Calldown);
1482 return;
1483 }
1484
1485 /* Queue our finish call for delayed completion */
1486 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1487 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1488 InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
1489 StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1490 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1491
1492 /* If we have to start dispatcher, go ahead */
1493 if (StartDispatcher)
1494 {
1495 NTSTATUS Status;
1496
1497 Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
1498 RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
1499 if (!NT_SUCCESS(Status))
1500 {
1501 /* It failed - run it manually.... */
1502 RxFinishSrvCallConstructionDispatcher(NULL);
1503 }
1504 }
1505 }
1506
1507 /*
1508 * @implemented
1509 */
1510 PSRV_OPEN
1511 RxCreateSrvOpen(
1512 IN PV_NET_ROOT VNetRoot,
1513 IN OUT PFCB Fcb)
1514 {
1515 ULONG Flags;
1516 PSRV_OPEN SrvOpen;
1517 POOL_TYPE PoolType;
1518
1519 PAGED_CODE();
1520
1521 ASSERT(NodeTypeIsFcb(Fcb));
1522 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1523
1524 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1525
1526 _SEH2_TRY
1527 {
1528 SrvOpen = Fcb->InternalSrvOpen;
1529 /* Check whethet we have to allocate a new SRV_OPEN */
1530 if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
1531 BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
1532 !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1533 {
1534 /* Proceed */
1535 SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1536 RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
1537 Flags = 0;
1538 }
1539 else
1540 {
1541 /* Otherwise, just use internal one and initialize it */
1542 RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1543 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
1544 Fcb->InternalSrvOpen);
1545 Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
1546 Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
1547 }
1548
1549 /* If SrvOpen was properly allocated, initialize it */
1550 if (SrvOpen != NULL)
1551 {
1552 SrvOpen->Flags = Flags;
1553 SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
1554 SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
1555 SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
1556 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
1557 SrvOpen->NodeReferenceCount = 1;
1558
1559 RxReferenceVNetRoot(VNetRoot);
1560 RxReferenceNetFcb(Fcb);
1561
1562 InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
1563 ++Fcb->SrvOpenListVersion;
1564
1565 InitializeListHead(&SrvOpen->ScavengerFinalizationList);
1566 InitializeListHead(&SrvOpen->TransitionWaitList);
1567 InitializeListHead(&SrvOpen->FobxList);
1568 InitializeListHead(&SrvOpen->SrvOpenKeyList);
1569 }
1570 }
1571 _SEH2_FINALLY
1572 {
1573 if (_SEH2_AbnormalTermination())
1574 {
1575 if (SrvOpen != NULL)
1576 {
1577 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
1578 SrvOpen = NULL;
1579 }
1580 }
1581 else
1582 {
1583 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
1584 }
1585 }
1586 _SEH2_END;
1587
1588 return SrvOpen;
1589 }
1590
1591 /*
1592 * @implemented
1593 */
1594 PV_NET_ROOT
1595 RxCreateVNetRoot(
1596 IN PRX_CONTEXT RxContext,
1597 IN PNET_ROOT NetRoot,
1598 IN PUNICODE_STRING CanonicalName,
1599 IN PUNICODE_STRING LocalNetRootName,
1600 IN PUNICODE_STRING FilePath,
1601 IN PRX_CONNECTION_ID RxConnectionId)
1602 {
1603 NTSTATUS Status;
1604 PV_NET_ROOT VNetRoot;
1605 USHORT CaseInsensitiveLength;
1606
1607 PAGED_CODE();
1608
1609 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
1610 LocalNetRootName, FilePath, RxConnectionId);
1611
1612 /* Lock must be held exclusively */
1613 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1614
1615 /* Check for overflow */
1616 if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
1617 {
1618 return NULL;
1619 }
1620
1621 /* Get name length and allocate VNetRoot */
1622 CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
1623 VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
1624 CaseInsensitiveLength);
1625 if (VNetRoot == NULL)
1626 {
1627 return NULL;
1628 }
1629
1630 /* Initialize its connection parameters */
1631 Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
1632 &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
1633 &VNetRoot->pPassword, &VNetRoot->Flags);
1634 if (!NT_SUCCESS(Status))
1635 {
1636 RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
1637 VNetRoot->pPassword, &VNetRoot->Flags);
1638 RxFreeObject(VNetRoot);
1639
1640 return NULL;
1641 }
1642
1643 /* Set name */
1644 RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
1645
1646 VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
1647 VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
1648 VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
1649 VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
1650
1651 InitializeListHead(&VNetRoot->TransitionWaitList);
1652 InitializeListHead(&VNetRoot->ScavengerFinalizationList);
1653
1654 if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
1655 {
1656 USHORT i;
1657
1658 if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1659 {
1660 CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
1661 }
1662 else
1663 {
1664 CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
1665 }
1666
1667 for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
1668 {
1669 if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
1670 {
1671 break;
1672 }
1673 }
1674
1675 CaseInsensitiveLength += (i * sizeof(WCHAR));
1676 }
1677
1678 /* Insert in prefix table */
1679 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
1680 VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
1681 RxConnectionId);
1682
1683 RxReferenceNetRoot(NetRoot);
1684 RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
1685
1686 /* Finish init */
1687 VNetRoot->SerialNumberForEnum = SerialNumber++;
1688 VNetRoot->UpperFinalizationDone = FALSE;
1689 VNetRoot->ConnectionFinalizationDone = FALSE;
1690 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
1691
1692 DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
1693 DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
1694
1695 return VNetRoot;
1696 }
1697
1698 VOID
1699 RxDereference(
1700 IN OUT PVOID Instance,
1701 IN LOCK_HOLDING_STATE LockHoldingState)
1702 {
1703 LONG RefCount;
1704 NODE_TYPE_CODE NodeType;
1705 PNODE_TYPE_AND_SIZE Node;
1706
1707 PAGED_CODE();
1708
1709 RxAcquireScavengerMutex();
1710
1711 /* Check we have a node we can handle */
1712 NodeType = NodeType(Instance);
1713 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
1714 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
1715 (NodeType == RDBSS_NTC_FOBX));
1716
1717 Node = (PNODE_TYPE_AND_SIZE)Instance;
1718 RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
1719 ASSERT(RefCount >= 0);
1720
1721 /* Trace refcount */
1722 switch (NodeType)
1723 {
1724 case RDBSS_NTC_SRVCALL:
1725 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
1726 break;
1727
1728 case RDBSS_NTC_NETROOT:
1729 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
1730 break;
1731
1732 case RDBSS_NTC_V_NETROOT:
1733 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
1734 break;
1735
1736 case RDBSS_NTC_SRVOPEN:
1737 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
1738 break;
1739
1740 case RDBSS_NTC_FOBX:
1741 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
1742 break;
1743
1744 default:
1745 ASSERT(FALSE);
1746 break;
1747 }
1748
1749 /* No need to free - still in use */
1750 if (RefCount > 1)
1751 {
1752 RxReleaseScavengerMutex();
1753 return;
1754 }
1755
1756 /* We have to be locked exclusively */
1757 if (LockHoldingState != LHS_ExclusiveLockHeld)
1758 {
1759 UNIMPLEMENTED;
1760 RxReleaseScavengerMutex();
1761 return;
1762 }
1763
1764 RxReleaseScavengerMutex();
1765
1766 /* TODO: Really deallocate stuff - we're leaking as hell! */
1767 switch (NodeType)
1768 {
1769 case RDBSS_NTC_SRVCALL:
1770 {
1771 PSRV_CALL SrvCall;
1772
1773 SrvCall = (PSRV_CALL)Instance;
1774
1775 ASSERT(SrvCall->RxDeviceObject != NULL);
1776 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
1777 RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
1778 break;
1779 }
1780
1781 case RDBSS_NTC_NETROOT:
1782 UNIMPLEMENTED;
1783 break;
1784
1785 case RDBSS_NTC_V_NETROOT:
1786 UNIMPLEMENTED;
1787 break;
1788
1789 case RDBSS_NTC_SRVOPEN:
1790 UNIMPLEMENTED;
1791 break;
1792
1793 case RDBSS_NTC_FOBX:
1794 UNIMPLEMENTED;
1795 break;
1796 }
1797 }
1798
1799 /*
1800 * @implemented
1801 */
1802 VOID
1803 NTAPI
1804 RxDereferenceAndDeleteRxContext_Real(
1805 IN PRX_CONTEXT RxContext)
1806 {
1807 KIRQL OldIrql;
1808 ULONG RefCount;
1809 BOOLEAN Allocated;
1810 PRX_CONTEXT StopContext = NULL;
1811
1812 /* Make sure we really have a context */
1813 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1814 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
1815 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
1816 /* If refcount is 0, start releasing stuff that needs spinlock held */
1817 if (RefCount == 0)
1818 {
1819 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1820
1821 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1822
1823 /* If that's stop context from DO, remove it */
1824 RxDeviceObject = RxContext->RxDeviceObject;
1825 if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
1826 {
1827 RxDeviceObject->StartStopContext.pStopContext = NULL;
1828 }
1829 else
1830 {
1831 /* Remove it from the list */
1832 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
1833 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
1834 RemoveEntryList(&RxContext->ContextListEntry);
1835
1836 /* If that was the last active context, save the stop context */
1837 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
1838 {
1839 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
1840 {
1841 StopContext = RxDeviceObject->StartStopContext.pStopContext;
1842 }
1843 }
1844 }
1845 }
1846 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1847
1848 /* Now, deal with what can be done without spinlock held */
1849 if (RefCount == 0)
1850 {
1851 /* Refcount shouldn't have changed */
1852 ASSERT(RxContext->ReferenceCount == 0);
1853 /* Reset everything that can be */
1854 RxPrepareContextForReuse(RxContext);
1855
1856 #ifdef RDBSS_TRACKER
1857 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
1858 #endif
1859 /* If that was the last active, set the event */
1860 if (StopContext != NULL)
1861 {
1862 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
1863 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
1864 }
1865
1866 /* Is ShadowCrit still owned? Shouldn't happen! */
1867 if (RxContext->ShadowCritOwner != 0)
1868 {
1869 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
1870 ASSERT(FALSE);
1871 }
1872
1873 /* If it was allocated, free it */
1874 if (Allocated)
1875 {
1876 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
1877 }
1878 }
1879 }
1880
1881 /*
1882 * @implemented
1883 */
1884 NTSTATUS
1885 NTAPI
1886 RxDispatchToWorkerThread(
1887 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
1888 IN WORK_QUEUE_TYPE WorkQueueType,
1889 IN PRX_WORKERTHREAD_ROUTINE Routine,
1890 IN PVOID pContext)
1891 {
1892 NTSTATUS Status;
1893 PRX_WORK_DISPATCH_ITEM DispatchItem;
1894
1895 /* Allocate a bit of context */
1896 DispatchItem = ExAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
1897 if (DispatchItem == NULL)
1898 {
1899 return STATUS_INSUFFICIENT_RESOURCES;
1900 }
1901
1902 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1903 DispatchItem->DispatchRoutine = Routine;
1904 DispatchItem->DispatchRoutineParameter = pContext;
1905 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
1906 DispatchItem->WorkQueueItem.Parameter = DispatchItem;
1907
1908 /* Insert item */
1909 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, DispatchItem);
1910 if (!NT_SUCCESS(Status))
1911 {
1912 ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
1913 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
1914 }
1915
1916 DPRINT("Dispatching: %p, %p\n", Routine, pContext);
1917
1918 return Status;
1919 }
1920
1921 /*
1922 * @implemented
1923 */
1924 VOID
1925 RxExclusivePrefixTableLockToShared(
1926 PRX_PREFIX_TABLE Table)
1927 {
1928 PAGED_CODE();
1929
1930 ExConvertExclusiveToSharedLite(&Table->TableLock);
1931 }
1932
1933 /*
1934 * @implemented
1935 */
1936 VOID
1937 RxExtractServerName(
1938 IN PUNICODE_STRING FilePathName,
1939 OUT PUNICODE_STRING SrvCallName,
1940 OUT PUNICODE_STRING RestOfName)
1941 {
1942 USHORT i, Length;
1943
1944 PAGED_CODE();
1945
1946 ASSERT(SrvCallName != NULL);
1947
1948 /* SrvCall name will start from the begin up to the first separator */
1949 SrvCallName->Buffer = FilePathName->Buffer;
1950 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
1951 {
1952 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
1953 {
1954 break;
1955 }
1956 }
1957
1958 /* Compute length */
1959 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
1960 SrvCallName->MaximumLength = Length;
1961 SrvCallName->Length = Length;
1962
1963 /* Return the rest if asked */
1964 if (RestOfName != NULL)
1965 {
1966 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
1967 RestOfName->Buffer = &FilePathName->Buffer[i];
1968 RestOfName->MaximumLength = Length;
1969 RestOfName->Length = Length;
1970 }
1971 }
1972
1973 /*
1974 * @implemented
1975 */
1976 NTSTATUS
1977 RxFcbTableInsertFcb(
1978 IN OUT PRX_FCB_TABLE FcbTable,
1979 IN OUT PFCB Fcb)
1980 {
1981 PAGED_CODE();
1982
1983 /* We deal with the table, make sure it's locked */
1984 ASSERT(RxIsFcbTableLockExclusive(FcbTable));
1985
1986 /* Compute the hash */
1987 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
1988
1989 RxReferenceNetFcb(Fcb);
1990
1991 /* If no length, it will be our null entry */
1992 if (Fcb->FcbTableEntry.Path.Length == 0)
1993 {
1994 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
1995 }
1996 /* Otherwise, insert in the appropriate bucket */
1997 else
1998 {
1999 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2000 &Fcb->FcbTableEntry.HashLinks);
2001 }
2002
2003 /* Propagate the change by incrementing the version number */
2004 InterlockedIncrement((volatile long *)&FcbTable->Version);
2005
2006 return STATUS_SUCCESS;
2007 }
2008
2009 /*
2010 * @implemented
2011 */
2012 PFCB
2013 RxFcbTableLookupFcb(
2014 IN PRX_FCB_TABLE FcbTable,
2015 IN PUNICODE_STRING Path)
2016 {
2017 PFCB Fcb;
2018 PRX_FCB_TABLE_ENTRY TableEntry;
2019
2020 PAGED_CODE();
2021
2022 /* No path - easy, that's null entry */
2023 if (Path == NULL)
2024 {
2025 TableEntry = FcbTable->TableEntryForNull;
2026 }
2027 else
2028 {
2029 ULONG Hash;
2030 PLIST_ENTRY HashBucket, ListEntry;
2031
2032 /* Otherwise, compute the hash value and find the associated bucket */
2033 Hash = RxTableComputePathHashValue(Path);
2034 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2035 /* If the bucket is empty, it means there's no entry yet */
2036 if (IsListEmpty(HashBucket))
2037 {
2038 TableEntry = NULL;
2039 }
2040 else
2041 {
2042 /* Otherwise, browse all the entry */
2043 for (ListEntry = HashBucket->Flink;
2044 ListEntry != HashBucket;
2045 ListEntry = ListEntry->Flink)
2046 {
2047 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2048 InterlockedIncrement(&FcbTable->Compares);
2049
2050 /* If entry hash and string are equal, thatt's the one! */
2051 if (TableEntry->HashValue == Hash &&
2052 TableEntry->Path.Length == Path->Length &&
2053 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2054 {
2055 break;
2056 }
2057 }
2058
2059 /* We reached the end? Not found */
2060 if (ListEntry == HashBucket)
2061 {
2062 TableEntry = NULL;
2063 }
2064 }
2065 }
2066
2067 InterlockedIncrement(&FcbTable->Lookups);
2068
2069 /* If table entry isn't null, return the FCB */
2070 if (TableEntry != NULL)
2071 {
2072 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2073 RxReferenceNetFcb(Fcb);
2074 }
2075 else
2076 {
2077 Fcb = NULL;
2078 InterlockedIncrement(&FcbTable->FailedLookups);
2079 }
2080
2081 return Fcb;
2082 }
2083
2084 /*
2085 * @implemented
2086 */
2087 NTSTATUS
2088 RxFcbTableRemoveFcb(
2089 IN OUT PRX_FCB_TABLE FcbTable,
2090 IN OUT PFCB Fcb)
2091 {
2092 PAGED_CODE();
2093
2094 ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2095
2096 /* If no path, then remove entry for null */
2097 if (Fcb->FcbTableEntry.Path.Length == 0)
2098 {
2099 FcbTable->TableEntryForNull = NULL;
2100 }
2101 /* Otherwise, remove from the bucket */
2102 else
2103 {
2104 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2105 }
2106
2107 /* Reset its list entry */
2108 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2109
2110 /* Propagate the change by incrementing the version number */
2111 InterlockedIncrement((volatile long *)&FcbTable->Version);
2112
2113 return STATUS_SUCCESS;
2114 }
2115
2116 /*
2117 * @implemented
2118 */
2119 BOOLEAN
2120 RxFinalizeNetFcb(
2121 OUT PFCB ThisFcb,
2122 IN BOOLEAN RecursiveFinalize,
2123 IN BOOLEAN ForceFinalize,
2124 IN LONG ReferenceCount)
2125 {
2126 PAGED_CODE();
2127
2128 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2129 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2130
2131 /* Make sure we have an exclusively acquired FCB */
2132 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2133 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2134
2135 /* We shouldn't force finalization... */
2136 ASSERT(!ForceFinalize);
2137
2138 /* If recurisve, finalize all the associated SRV_OPEN */
2139 if (RecursiveFinalize)
2140 {
2141 PLIST_ENTRY ListEntry;
2142
2143 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2144 ListEntry != &ThisFcb->SrvOpenList;
2145 ListEntry = ListEntry->Flink)
2146 {
2147 PSRV_OPEN SrvOpen;
2148
2149 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2150 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2151 }
2152 }
2153 /* If FCB is still in use, that's over */
2154 else
2155 {
2156 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2157 {
2158 ASSERT(ReferenceCount > 0);
2159
2160 return FALSE;
2161 }
2162 }
2163
2164 ASSERT(ReferenceCount >= 1);
2165
2166 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2167 if (ReferenceCount != 1 && !ForceFinalize)
2168 {
2169 return FALSE;
2170 }
2171
2172 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2173
2174 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
2175
2176 /* If finalization was not already initiated, go ahead */
2177 if (!ThisFcb->UpperFinalizationDone)
2178 {
2179 /* Free any FCB_LOCK */
2180 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2181 {
2182 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2183
2184 while (ThisFcb->BufferedLocks.List != NULL)
2185 {
2186 PFCB_LOCK Entry;
2187
2188 Entry = ThisFcb->BufferedLocks.List;
2189 ThisFcb->BufferedLocks.List = Entry->Next;
2190
2191 ExFreePool(Entry);
2192 }
2193 }
2194
2195 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2196 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2197 {
2198 PNET_ROOT NetRoot;
2199
2200 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2201
2202 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2203 /* So, remove it */
2204 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2205 {
2206 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2207 }
2208 }
2209
2210 ThisFcb->UpperFinalizationDone = TRUE;
2211 }
2212
2213 ASSERT(ReferenceCount >= 1);
2214
2215 /* Even if forced, don't allow broken free */
2216 if (ReferenceCount != 1)
2217 {
2218 return FALSE;
2219 }
2220
2221 /* Now, release everything */
2222 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2223 {
2224 ExFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2225 }
2226
2227 if (ThisFcb->MRxDispatch != NULL)
2228 {
2229 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2230 }
2231
2232 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2233 ExDeleteResourceLite(ThisFcb->Header.Resource);
2234 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2235
2236 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2237 RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
2238
2239 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2240 ASSERT(!ThisFcb->fMiniInited);
2241
2242 /* And free the object */
2243 RxFreeFcbObject(ThisFcb);
2244
2245 return TRUE;
2246 }
2247
2248 BOOLEAN
2249 RxFinalizeNetRoot(
2250 OUT PNET_ROOT ThisNetRoot,
2251 IN BOOLEAN RecursiveFinalize,
2252 IN BOOLEAN ForceFinalize
2253 )
2254 {
2255 UNIMPLEMENTED;
2256 return FALSE;
2257 }
2258
2259 BOOLEAN
2260 RxFinalizeSrvCall(
2261 OUT PSRV_CALL ThisSrvCall,
2262 IN BOOLEAN RecursiveFinalize,
2263 IN BOOLEAN ForceFinalize)
2264 {
2265 UNIMPLEMENTED;
2266 return FALSE;
2267 }
2268
2269 BOOLEAN
2270 RxFinalizeSrvOpen(
2271 OUT PSRV_OPEN ThisSrvOpen,
2272 IN BOOLEAN RecursiveFinalize,
2273 IN BOOLEAN ForceFinalize)
2274 {
2275 UNIMPLEMENTED;
2276 return FALSE;
2277 }
2278
2279 NTSTATUS
2280 RxFindOrConstructVirtualNetRoot(
2281 IN PRX_CONTEXT RxContext,
2282 IN PUNICODE_STRING CanonicalName,
2283 IN NET_ROOT_TYPE NetRootType,
2284 IN PUNICODE_STRING RemainingName)
2285 {
2286 ULONG Flags;
2287 NTSTATUS Status;
2288 PVOID Container;
2289 BOOLEAN Construct;
2290 PV_NET_ROOT VNetRoot;
2291 RX_CONNECTION_ID ConnectionID;
2292 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2293 LOCK_HOLDING_STATE LockHoldingState;
2294
2295 PAGED_CODE();
2296
2297 RxDeviceObject = RxContext->RxDeviceObject;
2298 ASSERT(RxDeviceObject->Dispatch != NULL);
2299 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
2300
2301 /* Ask the mini-rdr for connection ID */
2302 ConnectionID.SessionID = 0;
2303 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
2304 {
2305 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
2306 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
2307 {
2308 /* mini-rdr is expected not to fail - unless it's not implemented */
2309 DPRINT1("Failed to initialize connection ID\n");
2310 ASSERT(FALSE);
2311 }
2312 }
2313
2314 RxContext->Create.NetNamePrefixEntry = NULL;
2315
2316 Status = STATUS_MORE_PROCESSING_REQUIRED;
2317 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
2318 LockHoldingState = LHS_SharedLockHeld;
2319 Construct = TRUE;
2320 Flags = 0;
2321
2322 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2323 while (TRUE)
2324 {
2325 PNET_ROOT NetRoot;
2326 PV_NET_ROOT SavedVNetRoot;
2327
2328 /* Look in prefix table */
2329 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
2330 if (Container != NULL)
2331 {
2332 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2333 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
2334 {
2335 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2336 RxDereferenceSrvCall(Container, LockHoldingState);
2337 }
2338 else
2339 {
2340 VNetRoot = Container;
2341 NetRoot = VNetRoot->NetRoot;
2342
2343 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2344 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
2345 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2346 {
2347 Status = STATUS_BAD_NETWORK_PATH;
2348 SavedVNetRoot = NULL;
2349 }
2350 else
2351 {
2352 LUID LogonId;
2353 ULONG SessionId;
2354 PUNICODE_STRING UserName, UserDomain, Password;
2355
2356 /* We can reuse if we use same credentials */
2357 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
2358 &SessionId, &UserName,
2359 &UserDomain, &Password,
2360 &Flags);
2361 if (NT_SUCCESS(Status))
2362 {
2363 SavedVNetRoot = VNetRoot;
2364 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
2365 &LogonId, UserName,
2366 UserDomain, Password,
2367 Flags);
2368 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
2369 {
2370 PLIST_ENTRY ListEntry;
2371
2372 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
2373 ListEntry != &NetRoot->VirtualNetRoots;
2374 ListEntry = ListEntry->Flink)
2375 {
2376 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
2377 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
2378 &LogonId, UserName,
2379 UserDomain, Password,
2380 Flags);
2381 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2382 {
2383 break;
2384 }
2385 }
2386
2387 if (ListEntry == &NetRoot->VirtualNetRoots)
2388 {
2389 SavedVNetRoot = NULL;
2390 }
2391 }
2392
2393 if (!NT_SUCCESS(Status))
2394 {
2395 SavedVNetRoot = NULL;
2396 }
2397
2398 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
2399 }
2400 }
2401
2402 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2403 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
2404 {
2405 if (SavedVNetRoot == NULL)
2406 {
2407 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2408 }
2409 }
2410 /* Reference VNetRoot we'll keep, and dereference current */
2411 else if (SavedVNetRoot != VNetRoot)
2412 {
2413 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2414 if (SavedVNetRoot != NULL)
2415 {
2416 RxReferenceVNetRoot(SavedVNetRoot);
2417 }
2418 }
2419 }
2420
2421 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2422 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2423 {
2424 Construct = FALSE;
2425 break;
2426 }
2427 }
2428
2429 /* If we're locked exclusive, we won't loop again, it was the second pass */
2430 if (LockHoldingState != LHS_SharedLockHeld)
2431 {
2432 break;
2433 }
2434
2435 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2436 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
2437 {
2438 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2439 LockHoldingState = LHS_ExclusiveLockHeld;
2440 break;
2441 }
2442
2443 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2444 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
2445 LockHoldingState = LHS_ExclusiveLockHeld;
2446 }
2447
2448 /* We didn't fail, and didn't find any VNetRoot, construct one */
2449 if (Construct)
2450 {
2451 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
2452
2453 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
2454 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
2455
2456 if (Status == STATUS_SUCCESS)
2457 {
2458 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
2459 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
2460 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
2461
2462 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2463 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
2464 RemainingName->MaximumLength = RemainingName->Length;
2465
2466 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
2467 {
2468 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
2469 }
2470 VNetRoot->Flags |= Flags;
2471 }
2472 }
2473
2474 /* Release the prefix table - caller expects it to be released */
2475 if (LockHoldingState != LHS_LockNotHeld)
2476 {
2477 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2478 }
2479
2480 /* If we failed creating, quit */
2481 if (Status != STATUS_SUCCESS)
2482 {
2483 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
2484 return Status;
2485 }
2486
2487 /* Otherwise, wait until the VNetRoot is stable */
2488 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
2489 RxWaitForStableVNetRoot(VNetRoot, RxContext);
2490 /* It's all good, update the RX_CONTEXT with all our structs */
2491 if (VNetRoot->Condition == Condition_Good)
2492 {
2493 PNET_ROOT NetRoot;
2494
2495 NetRoot = VNetRoot->NetRoot;
2496 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2497 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2498 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
2499 }
2500 else
2501 {
2502 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2503 RxContext->Create.pVNetRoot = NULL;
2504 Status = STATUS_BAD_NETWORK_PATH;
2505 }
2506
2507 return Status;
2508 }
2509
2510 /*
2511 * @implemented
2512 */
2513 NTSTATUS
2514 RxFindOrCreateConnections(
2515 _In_ PRX_CONTEXT RxContext,
2516 _In_ PUNICODE_STRING CanonicalName,
2517 _In_ NET_ROOT_TYPE NetRootType,
2518 _Out_ PUNICODE_STRING LocalNetRootName,
2519 _Out_ PUNICODE_STRING FilePathName,
2520 _Inout_ PLOCK_HOLDING_STATE LockState,
2521 _In_ PRX_CONNECTION_ID RxConnectionId)
2522 {
2523 PVOID Container;
2524 PSRV_CALL SrvCall;
2525 PNET_ROOT NetRoot;
2526 PV_NET_ROOT VNetRoot;
2527 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2528 PRX_PREFIX_TABLE PrefixTable;
2529 UNICODE_STRING RemainingName, NetRootName;
2530
2531 PAGED_CODE();
2532
2533 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2534 RxContext, CanonicalName, NetRootType, LocalNetRootName,
2535 FilePathName, LockState, RxConnectionId);
2536
2537 *FilePathName = *CanonicalName;
2538 LocalNetRootName->Length = 0;
2539 LocalNetRootName->MaximumLength = 0;
2540 LocalNetRootName->Buffer = CanonicalName->Buffer;
2541
2542 /* UNC path, split it */
2543 if (FilePathName->Buffer[1] == ';')
2544 {
2545 BOOLEAN Slash;
2546 USHORT i, Length;
2547
2548 Slash = FALSE;
2549 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
2550 {
2551 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2552 {
2553 Slash = TRUE;
2554 break;
2555 }
2556 }
2557
2558 if (!Slash)
2559 {
2560 return STATUS_OBJECT_NAME_INVALID;
2561 }
2562
2563 FilePathName->Buffer = &FilePathName->Buffer[i];
2564 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
2565 LocalNetRootName->Length = Length;
2566 LocalNetRootName->MaximumLength = Length;
2567 FilePathName->Length -= Length;
2568
2569 DPRINT("CanonicalName: %wZ\n", CanonicalName);
2570 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
2571 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
2572 }
2573
2574 Container = NULL;
2575 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
2576
2577 _SEH2_TRY
2578 {
2579 RetryLookup:
2580 ASSERT(*LockState != LHS_LockNotHeld);
2581
2582 /* If previous lookup left something, dereference it */
2583 if (Container != NULL)
2584 {
2585 switch (NodeType(Container))
2586 {
2587 case RDBSS_NTC_SRVCALL:
2588 RxDereferenceSrvCall(Container, *LockState);
2589 break;
2590
2591 case RDBSS_NTC_NETROOT:
2592 RxDereferenceNetRoot(Container, *LockState);
2593 break;
2594
2595 case RDBSS_NTC_V_NETROOT:
2596 RxDereferenceVNetRoot(Container, *LockState);
2597 break;
2598
2599 default:
2600 /* Should never happen */
2601 ASSERT(FALSE);
2602 break;
2603 }
2604 }
2605
2606 /* Look for our NetRoot in prefix table */
2607 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
2608 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
2609
2610 while (TRUE)
2611 {
2612 UNICODE_STRING SrvCallName;
2613
2614 SrvCall = NULL;
2615 NetRoot = NULL;
2616 VNetRoot = NULL;
2617
2618 /* Assume we didn't succeed */
2619 RxContext->Create.pVNetRoot = NULL;
2620 RxContext->Create.pNetRoot = NULL;
2621 RxContext->Create.pSrvCall = NULL;
2622 RxContext->Create.Type = NetRootType;
2623
2624 /* If we found something */
2625 if (Container != NULL)
2626 {
2627 /* A VNetRoot */
2628 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
2629 {
2630 VNetRoot = Container;
2631 /* Use its NetRoot */
2632 NetRoot = VNetRoot->NetRoot;
2633
2634 /* If it's not stable, wait for it to be stable */
2635 if (NetRoot->Condition == Condition_InTransition)
2636 {
2637 RxReleasePrefixTableLock(PrefixTable);
2638 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
2639 RxWaitForStableNetRoot(NetRoot, RxContext);
2640 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2641 *LockState = LHS_ExclusiveLockHeld;
2642
2643 /* Now that's it's ok, retry lookup to find what we want */
2644 if (NetRoot->Condition == Condition_Good)
2645 {
2646 goto RetryLookup;
2647 }
2648 }
2649
2650 /* Is the associated netroot good? */
2651 if (NetRoot->Condition == Condition_Good)
2652 {
2653 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
2654
2655 /* If it is, and SrvCall as well, then, we have our active connection */
2656 if (SrvCall->Condition == Condition_Good &&
2657 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
2658 {
2659 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2660 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2661 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2662
2663 Status = STATUS_CONNECTION_ACTIVE;
2664 _SEH2_LEAVE;
2665 }
2666 }
2667
2668 /* If VNetRoot was well constructed, it means the connection is active */
2669 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
2670 {
2671 Status = STATUS_CONNECTION_ACTIVE;
2672 }
2673 else
2674 {
2675 Status = VNetRoot->ConstructionStatus;
2676 }
2677
2678 RxDereferenceVNetRoot(VNetRoot, *LockState);
2679 _SEH2_LEAVE;
2680 }
2681 /* Can only be a SrvCall */
2682 else
2683 {
2684 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2685 SrvCall = Container;
2686
2687 /* Wait for the SRV_CALL to be stable */
2688 if (SrvCall->Condition == Condition_InTransition)
2689 {
2690 RxReleasePrefixTableLock(PrefixTable);
2691 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
2692 RxWaitForStableSrvCall(SrvCall, RxContext);
2693 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2694 *LockState = LHS_ExclusiveLockHeld;
2695
2696 /* It went good, loop again to find what we look for */
2697 if (SrvCall->Condition == Condition_Good)
2698 {
2699 goto RetryLookup;
2700 }
2701 }
2702
2703 /* If it's not good... */
2704 if (SrvCall->Condition != Condition_Good)
2705 {
2706 /* But SRV_CALL was well constructed, assume a connection was active */
2707 if (SrvCall->Status == STATUS_SUCCESS)
2708 {
2709 Status = STATUS_CONNECTION_ACTIVE;
2710 }
2711 else
2712 {
2713 Status = SrvCall->Status;
2714 }
2715
2716 RxDereferenceSrvCall(SrvCall, *LockState);
2717 _SEH2_LEAVE;
2718 }
2719 }
2720 }
2721
2722 /* If we found a SRV_CALL not matching our DO, quit */
2723 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
2724 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2725 {
2726 RxDereferenceSrvCall(SrvCall, *LockState);
2727 Status = STATUS_BAD_NETWORK_NAME;
2728 _SEH2_LEAVE;
2729 }
2730
2731 /* Now, we want exclusive lock */
2732 if (*LockState == LHS_SharedLockHeld)
2733 {
2734 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
2735 {
2736 RxReleasePrefixTableLock(PrefixTable);
2737 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2738 *LockState = LHS_ExclusiveLockHeld;
2739 goto RetryLookup;
2740 }
2741
2742 RxReleasePrefixTableLock(PrefixTable);
2743 *LockState = LHS_ExclusiveLockHeld;
2744 }
2745
2746 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2747
2748 /* If we reach that point, we found something, no need to create something */
2749 if (Container != NULL)
2750 {
2751 break;
2752 }
2753
2754 /* Get the name for the SRV_CALL */
2755 RxExtractServerName(FilePathName, &SrvCallName, NULL);
2756 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
2757 /* And create the SRV_CALL */
2758 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
2759 if (SrvCall == NULL)
2760 {
2761 Status = STATUS_INSUFFICIENT_RESOURCES;
2762 _SEH2_LEAVE;
2763 }
2764
2765 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2766 RxReferenceSrvCall(SrvCall);
2767 RxContext->Create.pVNetRoot = NULL;
2768 RxContext->Create.pNetRoot = NULL;
2769 RxContext->Create.pSrvCall = NULL;
2770 RxContext->Create.Type = NetRootType;
2771 Container = SrvCall;
2772
2773 /* Construct SRV_CALL, ie, use mini-rdr */
2774 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
2775 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
2776 if (Status != STATUS_SUCCESS)
2777 {
2778 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
2779 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2780 RxDereferenceSrvCall(SrvCall, *LockState);
2781 RxReleasePrefixTableLock(PrefixTable);
2782 _SEH2_LEAVE;
2783 }
2784
2785 /* Loop again to make use of SRV_CALL stable condition wait */
2786 }
2787
2788 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2789 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
2790 ASSERT(NetRoot == NULL && VNetRoot == NULL);
2791 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
2792
2793 /* Call mini-rdr to get NetRoot name */
2794 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
2795 /* And create the NetRoot with that name */
2796 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
2797 if (NetRoot == NULL)
2798 {
2799 Status = STATUS_INSUFFICIENT_RESOURCES;
2800 _SEH2_LEAVE;
2801 }
2802 NetRoot->Type = NetRootType;
2803
2804 RxDereferenceSrvCall(SrvCall, *LockState);
2805
2806 /* Finally, create the associated VNetRoot */
2807 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
2808 if (VNetRoot == NULL)
2809 {
2810 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2811 Status = STATUS_INSUFFICIENT_RESOURCES;
2812 _SEH2_LEAVE;
2813 }
2814 RxReferenceVNetRoot(VNetRoot);
2815
2816 /* We're get closer! */
2817 NetRoot->Condition = Condition_InTransition;
2818 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2819 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2820 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2821
2822 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2823 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
2824 if (!NT_SUCCESS(Status))
2825 {
2826 RxTransitionVNetRoot(VNetRoot, Condition_Bad);
2827 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
2828 RxDereferenceVNetRoot(VNetRoot, *LockState);
2829
2830 RxContext->Create.pNetRoot = NULL;
2831 RxContext->Create.pVNetRoot = NULL;
2832 }
2833 else
2834 {
2835 PIO_STACK_LOCATION Stack;
2836
2837 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2838
2839 Stack = RxContext->CurrentIrpSp;
2840 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2841 {
2842 RxExclusivePrefixTableLockToShared(PrefixTable);
2843 *LockState = LHS_SharedLockHeld;
2844 }
2845 }
2846 }
2847 _SEH2_FINALLY
2848 {
2849 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
2850 {
2851 if (*LockState != LHS_LockNotHeld)
2852 {
2853 RxReleasePrefixTableLock(PrefixTable);
2854 *LockState = LHS_LockNotHeld;
2855 }
2856 }
2857 }
2858 _SEH2_END;
2859
2860 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
2861 return Status;
2862 }
2863
2864 /*
2865 * @implemented
2866 */
2867 VOID
2868 NTAPI
2869 RxFinishFcbInitialization(
2870 IN OUT PMRX_FCB Fcb,
2871 IN RX_FILE_TYPE FileType,
2872 IN PFCB_INIT_PACKET InitPacket OPTIONAL)
2873 {
2874 NODE_TYPE_CODE OldType;
2875
2876 PAGED_CODE();
2877
2878 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
2879
2880 OldType = Fcb->Header.NodeTypeCode;
2881 Fcb->Header.NodeTypeCode = FileType;
2882 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2883 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
2884 {
2885 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2886 }
2887 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2888 else if (InitPacket != NULL)
2889 {
2890 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
2891 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
2892 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
2893 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
2894 InitPacket->pValidDataLength->QuadPart);
2895 }
2896
2897 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2898 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2899 {
2900 /* If our FCB newly points to a file, initiliaz everything related */
2901 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
2902 !OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
2903 {
2904 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
2905 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
2906 &RxUnlockOperation);
2907
2908 ((PFCB)Fcb)->BufferedLocks.List = NULL;
2909 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
2910
2911 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
2912 }
2913 else
2914 {
2915 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
2916 }
2917 }
2918 }
2919
2920 /*
2921 * @implemented
2922 */
2923 NTSTATUS
2924 RxFinishSrvCallConstruction(
2925 PMRX_SRVCALLDOWN_STRUCTURE Calldown)
2926 {
2927 NTSTATUS Status;
2928 PSRV_CALL SrvCall;
2929 PRX_CONTEXT Context;
2930 RX_BLOCK_CONDITION Condition;
2931 PRX_PREFIX_TABLE PrefixTable;
2932
2933 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
2934
2935 SrvCall = (PSRV_CALL)Calldown->SrvCall;
2936 Context = Calldown->RxContext;
2937 PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
2938
2939 /* We have a winner, notify him */
2940 if (Calldown->BestFinisher != NULL)
2941 {
2942 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
2943
2944 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
2945
2946 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
2947 MRxSrvCallWinnerNotify,
2948 ((PMRX_SRV_CALL)SrvCall, TRUE,
2949 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
2950 if (Status != STATUS_SUCCESS)
2951 {
2952 Condition = Condition_Bad;
2953 }
2954 else
2955 {
2956 Condition = Condition_Good;
2957 }
2958 }
2959 /* Otherwise, just fail our SRV_CALL */
2960 else
2961 {
2962 Status = Calldown->CallbackContexts[0].Status;
2963 Condition = Condition_Bad;
2964 }
2965
2966 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2967 RxTransitionSrvCall(SrvCall, Condition);
2968 ExFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
2969
2970 /* If async, finish it here, otherwise, caller has already finished the stuff */
2971 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
2972 {
2973 DPRINT("Finishing async call\n");
2974
2975 RxReleasePrefixTableLock(PrefixTable);
2976
2977 /* Make sure we weren't cancelled in-between */
2978 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
2979 {
2980 Status = STATUS_CANCELLED;
2981 }
2982
2983 /* In case that was a create, context can be reused */
2984 if (Context->MajorFunction == IRP_MJ_CREATE)
2985 {
2986 RxpPrepareCreateContextForReuse(Context);
2987 }
2988
2989 /* If that's a failure, reset everything and return failure */
2990 if (Status != STATUS_SUCCESS)
2991 {
2992 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
2993 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
2994 {
2995 if (Context->Info.Buffer != NULL)
2996 {
2997 ExFreePool(Context->Info.Buffer);
2998 Context->Info.Buffer = NULL;
2999 }
3000 }
3001 Context->CurrentIrp->IoStatus.Information = 0;
3002 Context->CurrentIrp->IoStatus.Status = Status;
3003 RxCompleteRequest(Context, Status);
3004 }
3005 /* Otherwise, call resume routine and done! */
3006 else
3007 {
3008 Status = Context->ResumeRoutine(Context);
3009 if (Status != STATUS_PENDING)
3010 {
3011 RxCompleteRequest(Context, Status);
3012 }
3013
3014 DPRINT("Not completing, pending\n");
3015 }
3016 }
3017
3018 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
3019 return Status;
3020 }
3021
3022 /*
3023 * @implemented
3024 */
3025 VOID
3026 NTAPI
3027 RxFinishSrvCallConstructionDispatcher(
3028 IN PVOID Context)
3029 {
3030 KIRQL OldIrql;
3031 BOOLEAN Direct, KeepLoop;
3032
3033 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
3034
3035 /* In case of failure of starting dispatcher, context is not set
3036 * We keep track of it to fail associated SRV_CALL
3037 */
3038 Direct = (Context == NULL);
3039
3040 /* Separated thread, loop forever */
3041 while (TRUE)
3042 {
3043 PLIST_ENTRY ListEntry;
3044 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
3045
3046 /* If there are no SRV_CALL to finalize left, just finish thread */
3047 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
3048 if (IsListEmpty(&RxSrvCalldownList))
3049 {
3050 KeepLoop = FALSE;
3051 RxSrvCallConstructionDispatcherActive = FALSE;
3052 }
3053 /* Otherwise, get the SRV_CALL to finish construction */
3054 else
3055 {
3056 ListEntry = RemoveHeadList(&RxSrvCalldownList);
3057 KeepLoop = TRUE;
3058 }
3059 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
3060
3061 /* Nothing to do */
3062 if (!KeepLoop)
3063 {
3064 break;
3065 }
3066
3067 /* If direct is set, reset the finisher to avoid electing a winner
3068 * and fail SRV_CALL (see upper comment)
3069 */
3070 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
3071 if (Direct)
3072 {
3073 Calldown->BestFinisher = NULL;
3074 }
3075 /* Finish SRV_CALL construction */
3076 RxFinishSrvCallConstruction(Calldown);
3077 }
3078 }
3079
3080 VOID
3081 RxFreeFcbObject(
3082 PVOID Object)
3083 {
3084 UNIMPLEMENTED;
3085 }
3086
3087 VOID
3088 RxFreeObject(
3089 PVOID pObject)
3090 {
3091 UNIMPLEMENTED;
3092 }
3093
3094 /*
3095 * @implemented
3096 */
3097 VOID
3098 RxGetFileSizeWithLock(
3099 IN PFCB Fcb,
3100 OUT PLONGLONG FileSize)
3101 {
3102 PAGED_CODE();
3103
3104 *FileSize = Fcb->Header.FileSize.QuadPart;
3105 }
3106
3107 /*
3108 * @implemented
3109 */
3110 PEPROCESS
3111 NTAPI
3112 RxGetRDBSSProcess(
3113 VOID)
3114 {
3115 return RxData.OurProcess;
3116 }
3117
3118 /*
3119 * @implemented
3120 */
3121 NTSTATUS
3122 RxInitializeBufferingManager(
3123 PSRV_CALL SrvCall)
3124 {
3125 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
3126 InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
3127 InitializeListHead(&SrvCall->BufferingManager.HandlerList);
3128 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
3129 SrvCall->BufferingManager.DispatcherActive = FALSE;
3130 SrvCall->BufferingManager.HandlerInactive = FALSE;
3131 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
3132 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
3133 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
3134 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
3135
3136 return STATUS_SUCCESS;
3137 }
3138
3139 /*
3140 * @implemented
3141 */
3142 VOID
3143 NTAPI
3144 RxInitializeContext(
3145 IN PIRP Irp,
3146 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
3147 IN ULONG InitialContextFlags,
3148 IN OUT PRX_CONTEXT RxContext)
3149 {
3150 PIO_STACK_LOCATION Stack;
3151
3152 /* Initialize our various fields */
3153 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
3154 RxContext->NodeByteSize = sizeof(RX_CONTEXT);
3155 RxContext->ReferenceCount = 1;
3156 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
3157 RxContext->RxDeviceObject = RxDeviceObject;
3158 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
3159 RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
3160 InitializeListHead(&RxContext->BlockedOperations);
3161 RxContext->MRxCancelRoutine = NULL;
3162 RxContext->ResumeRoutine = NULL;
3163 RxContext->Flags |= InitialContextFlags;
3164 RxContext->CurrentIrp = Irp;
3165 RxContext->LastExecutionThread = PsGetCurrentThread();
3166 RxContext->OriginalThread = RxContext->LastExecutionThread;
3167
3168 /* If've got no IRP, mark RX_CONTEXT */
3169 if (Irp == NULL)
3170 {
3171 RxContext->CurrentIrpSp = NULL;
3172 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
3173 RxContext->MinorFunction = 0;
3174 }
3175 else
3176 {
3177 /* Otherwise, first determine whether we are performing async operation */
3178 Stack = IoGetCurrentIrpStackLocation(Irp);
3179 if (Stack->FileObject != NULL)
3180 {
3181 PFCB Fcb;
3182
3183 Fcb = Stack->FileObject->FsContext;
3184 if (!IoIsOperationSynchronous(Irp) ||
3185 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
3186 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
3187 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
3188 {
3189 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3190 }
3191 }
3192
3193 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
3194 {
3195 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3196 }
3197 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
3198 {
3199 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3200 }
3201
3202 /* Set proper flags if TopLevl IRP/Device */
3203 if (!RxIsThisTheTopLevelIrp(Irp))
3204 {
3205 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
3206 }
3207 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
3208 {
3209 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
3210 }
3211
3212 /* Copy stack information */
3213 RxContext->MajorFunction = Stack->MajorFunction;
3214 RxContext->MinorFunction = Stack->MinorFunction;
3215 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
3216 RxContext->CurrentIrpSp = Stack;
3217
3218 /* If we have a FO associated, learn for more */
3219 if (Stack->FileObject != NULL)
3220 {
3221 PFCB Fcb;
3222 PFOBX Fobx;
3223
3224 /* Get the FCB and CCB (FOBX) */
3225 Fcb = Stack->FileObject->FsContext;
3226 Fobx = Stack->FileObject->FsContext2;
3227 RxContext->pFcb = (PMRX_FCB)Fcb;
3228 if (Fcb != NULL && NodeTypeIsFcb(Fcb))
3229 {
3230 RxContext->NonPagedFcb = Fcb->NonPaged;
3231 }
3232
3233 /* We have a FOBX, this not a DFS opening, keep track of it */
3234 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
3235 {
3236 RxContext->pFobx = (PMRX_FOBX)Fobx;
3237 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
3238 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3239 {
3240 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
3241 }
3242 }
3243 else
3244 {
3245 RxContext->pFobx = NULL;
3246 }
3247
3248 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3249 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
3250 Fobx != NULL)
3251 {
3252 PV_NET_ROOT VNetRoot = NULL;
3253
3254 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3255 {
3256 VNetRoot = Fcb->VNetRoot;
3257 }
3258 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
3259 {
3260 VNetRoot = (PV_NET_ROOT)Fobx;
3261 }
3262
3263 if (VNetRoot != NULL)
3264 {
3265 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3266 }
3267 }
3268
3269 /* Remember if that's a write through file */
3270 RxContext->RealDevice = Stack->FileObject->DeviceObject;
3271 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
3272 {
3273 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
3274 }
3275 }
3276 }
3277
3278 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
3279 {
3280 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3281 RxContext, RxContext->MinorFunction, Irp,
3282 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
3283 RxContext->SerialNumber);
3284 }
3285 }
3286
3287 /*
3288 * @implemented
3289 */
3290 NTSTATUS
3291 NTAPI
3292 RxInitializeDispatcher(
3293 VOID)
3294 {
3295 NTSTATUS Status;
3296 HANDLE ThreadHandle;
3297
3298 PAGED_CODE();
3299
3300 RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
3301 RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
3302
3303 /* Set appropriate timeouts: 10s & 60s */
3304 RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3305 RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3306 RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3307 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
3308
3309 RxDispatcher.NumberOfProcessors = 1;
3310 RxDispatcher.OwnerProcess = IoGetCurrentProcess();
3311 RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
3312
3313 /* Initialize our dispatchers */
3314 Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
3315 if (!NT_SUCCESS(Status))
3316 {
3317 return Status;
3318 }
3319
3320 Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
3321 if (!NT_SUCCESS(Status))
3322 {
3323 return Status;
3324 }
3325
3326 /* And start them */
3327 RxDispatcher.State = RxDispatcherActive;
3328 InitializeListHead(&RxDispatcher.SpinUpRequests);
3329 KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
3330 KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
3331 KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
3332 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
3333 NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
3334 if (NT_SUCCESS(Status))
3335 {
3336 ZwClose(ThreadHandle);
3337 }
3338
3339 return Status;
3340 }
3341
3342 /*
3343 * @implemented
3344 */
3345 VOID
3346 RxInitializeFcbTable(
3347 IN OUT PRX_FCB_TABLE FcbTable,
3348 IN BOOLEAN CaseInsensitiveMatch)
3349 {
3350 USHORT i;
3351
3352 PAGED_CODE();
3353
3354 FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
3355 FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
3356
3357 ExInitializeResourceLite(&FcbTable->TableLock);
3358 FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
3359 FcbTable->Version = 0;
3360 FcbTable->TableEntryForNull = NULL;
3361
3362 FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
3363 for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
3364 {
3365 InitializeListHead(&FcbTable->HashBuckets[i]);
3366 }
3367
3368 FcbTable->Lookups = 0;
3369 FcbTable->FailedLookups = 0;
3370 FcbTable->Compares = 0;
3371 }
3372
3373 /*
3374 * @implemented
3375 */
3376 VOID
3377 NTAPI
3378 RxInitializeLowIoContext(
3379 OUT PLOWIO_CONTEXT LowIoContext,
3380 IN ULONG Operation)
3381 {
3382 PRX_CONTEXT RxContext;
3383 PIO_STACK_LOCATION Stack;
3384
3385 PAGED_CODE();
3386
3387 RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
3388 ASSERT(LowIoContext = &RxContext->LowIoContext);
3389
3390 Stack = RxContext->CurrentIrpSp;
3391
3392 KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
3393 RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
3394 RxContext->LowIoContext.Operation = Operation;
3395
3396 switch (Operation)
3397 {
3398 case LOWIO_OP_READ:
3399 case LOWIO_OP_WRITE:
3400 /* In case of RW, set a canary, to make sure these fields are properly set
3401 * they will be asserted when lowio request will be submit to mini-rdr
3402 * See LowIoSubmit()
3403 */
3404 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
3405 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
3406 RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
3407
3408 /* Keep track of paging IOs */
3409 if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
3410 {
3411 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
3412 }
3413 else
3414 {
3415 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
3416 }
3417
3418 break;
3419
3420 case LOWIO_OP_FSCTL:
3421 case LOWIO_OP_IOCTL:
3422 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
3423 RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
3424 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
3425 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
3426 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
3427 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
3428 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
3429 break;
3430
3431 /* Nothing to do for these */
3432 case LOWIO_OP_SHAREDLOCK:
3433 case LOWIO_OP_EXCLUSIVELOCK:
3434 case LOWIO_OP_UNLOCK:
3435 case LOWIO_OP_UNLOCK_MULTIPLE:
3436 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
3437 case LOWIO_OP_CLEAROUT:
3438 break;
3439
3440 default:
3441 /* Should never happen */
3442 ASSERT(FALSE);
3443 break;
3444 }
3445 }
3446
3447 /*
3448 * @implemented
3449 */
3450 VOID
3451 RxInitializeLowIoPerFcbInfo(
3452 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
3453 {
3454 PAGED_CODE();
3455
3456 InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
3457 InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
3458 }
3459
3460 /*
3461 * @implemented
3462 */
3463 NTSTATUS
3464 RxInitializeMRxDispatcher(
3465 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
3466 {
3467 PAGED_CODE();
3468
3469 pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
3470 pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
3471
3472 return STATUS_SUCCESS;
3473 }
3474
3475 /*
3476 * @implemented
3477 */
3478 VOID
3479 RxInitializePrefixTable(
3480 IN OUT PRX_PREFIX_TABLE ThisTable,
3481 IN ULONG TableSize OPTIONAL,
3482 IN BOOLEAN CaseInsensitiveMatch)
3483 {
3484 PAGED_CODE();
3485
3486 if (TableSize == 0)
3487 {
3488 TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
3489 }
3490
3491 ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
3492 ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
3493 InitializeListHead(&ThisTable->MemberQueue);
3494 ThisTable->Version = 0;
3495 ThisTable->TableEntryForNull = NULL;
3496 ThisTable->IsNetNameTable = FALSE;
3497 ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
3498 ThisTable->TableSize = TableSize;
3499
3500 if (TableSize > 0)
3501 {
3502 USHORT i;
3503
3504 for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
3505 {
3506 InitializeListHead(&ThisTable->HashBuckets[i]);
3507 }
3508 }
3509 }
3510
3511 /*
3512 * @implemented
3513 */
3514 VOID
3515 RxInitializePurgeSyncronizationContext(
3516 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
3517 {
3518 PAGED_CODE();
3519
3520 InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
3521 PurgeSyncronizationContext->PurgeInProgress = FALSE;
3522 }
3523
3524 NTSTATUS
3525 RxInitializeSrvCallParameters(
3526 IN PRX_CONTEXT RxContext,
3527 IN OUT PSRV_CALL SrvCall)
3528 {
3529 PAGED_CODE();
3530
3531 SrvCall->pPrincipalName = NULL;
3532
3533 /* We only have stuff to initialize for file opening from DFS */
3534 if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
3535 {
3536 return STATUS_SUCCESS;
3537 }
3538
3539 ASSERT(RxContext->Create.EaBuffer != NULL);
3540
3541 UNIMPLEMENTED;
3542 return STATUS_NOT_IMPLEMENTED;
3543 }
3544
3545 NTSTATUS
3546 RxInitializeVNetRootParameters(
3547 PRX_CONTEXT RxContext,
3548 OUT LUID *LogonId,
3549 OUT PULONG SessionId,
3550 OUT PUNICODE_STRING *UserNamePtr,
3551 OUT PUNICODE_STRING *UserDomainNamePtr,
3552 OUT PUNICODE_STRING *PasswordPtr,
3553 OUT PULONG Flags)
3554 {
3555 NTSTATUS Status;
3556 PACCESS_TOKEN Token;
3557
3558 PAGED_CODE();
3559
3560 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
3561 LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
3562
3563 *UserNamePtr = NULL;
3564 *UserDomainNamePtr = NULL;
3565 *PasswordPtr = NULL;
3566 /* By default, that's not CSC instance */
3567 *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
3568
3569 Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
3570 if (SeTokenIsRestricted(Token))
3571 {
3572 return STATUS_ACCESS_DENIED;
3573 }
3574
3575 /* Get LogonId */
3576 Status = SeQueryAuthenticationIdToken(Token, LogonId);
3577 if (!NT_SUCCESS(Status))
3578 {
3579 return Status;
3580 }
3581
3582 /* And SessionId */
3583 Status = SeQuerySessionIdToken(Token, SessionId);
3584 if (!NT_SUCCESS(Status))
3585 {
3586 return Status;
3587 }
3588
3589 if (RxContext->Create.UserName.Buffer != NULL)
3590 {
3591 UNIMPLEMENTED;
3592 Status = STATUS_NOT_IMPLEMENTED;
3593 goto Leave;
3594 }
3595
3596 /* Deal with connection credentials */
3597 if (RxContext->Create.UserDomainName.Buffer != NULL)
3598 {
3599 UNIMPLEMENTED;
3600 Status = STATUS_NOT_IMPLEMENTED;
3601 goto Leave;
3602 }
3603
3604 if (RxContext->Create.Password.Buffer != NULL)
3605 {
3606 UNIMPLEMENTED;
3607 Status = STATUS_NOT_IMPLEMENTED;
3608 goto Leave;
3609 }
3610
3611 Leave:
3612 if (NT_SUCCESS(Status))
3613 {
3614 /* If that's a CSC instance, mark it as such */
3615 if (RxIsThisACscAgentOpen(RxContext))
3616 {
3617 *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
3618 }
3619 return Status;
3620 }
3621
3622 return Status;
3623 }
3624
3625 /*
3626 * @implemented
3627 */
3628 VOID
3629 RxInitializeWorkQueue(
3630 PRX_WORK_QUEUE WorkQueue,
3631 WORK_QUEUE_TYPE WorkQueueType,
3632 ULONG MaximumNumberOfWorkerThreads,
3633 ULONG MinimumNumberOfWorkerThreads)
3634 {
3635 PAGED_CODE();
3636
3637 WorkQueue->Type = WorkQueueType;
3638 WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
3639 WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
3640
3641 WorkQueue->State = RxWorkQueueActive;
3642 WorkQueue->SpinUpRequestPending = FALSE;
3643 WorkQueue->pRundownContext = NULL;
3644 WorkQueue->NumberOfWorkItemsDispatched = 0;
3645 WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
3646 WorkQueue->CumulativeQueueLength = 0;
3647 WorkQueue->NumberOfSpinUpRequests = 0;
3648 WorkQueue->NumberOfActiveWorkerThreads = 0;
3649 WorkQueue->NumberOfIdleWorkerThreads = 0;
3650 WorkQueue->NumberOfFailedSpinUpRequests = 0;
3651 WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
3652 WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
3653 WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
3654 WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
3655 WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
3656 WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
3657 WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
3658 WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
3659 WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
3660 WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
3661 WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
3662 WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
3663 WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
3664
3665 KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
3666 KeInitializeSpinLock(&WorkQueue->SpinLock);
3667 }
3668
3669 /*
3670 * @implemented
3671 */
3672 NTSTATUS
3673 RxInitializeWorkQueueDispatcher(
3674 PRX_WORK_QUEUE_DISPATCHER Dispatcher)
3675 {
3676 NTSTATUS Status;
3677 ULONG MaximumNumberOfWorkerThreads;
3678
3679 PAGED_CODE();
3680
3681 /* Number of threads will depend on system capacity */
3682 if (MmQuerySystemSize() != MmLargeSystem)
3683 {
3684 MaximumNumberOfWorkerThreads = 5;
3685 }
3686 else
3687 {
3688 MaximumNumberOfWorkerThreads = 10;
3689 }
3690
3691 /* Initialize the work queues */
3692 RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
3693 MaximumNumberOfWorkerThreads, 1);
3694 RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
3695 RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
3696
3697 /* And start the worker threads */
3698 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
3699 RxBootstrapWorkerThreadDispatcher,
3700 &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
3701 if (!NT_SUCCESS(Status))
3702 {
3703 return Status;
3704 }
3705
3706 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
3707 RxBootstrapWorkerThreadDispatcher,
3708 &Dispatcher->WorkQueue[CriticalWorkQueue]);
3709 if (!NT_SUCCESS(Status))
3710 {
3711 return Status;
3712 }
3713
3714 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
3715 RxBootstrapWorkerThreadDispatcher,
3716 &Dispatcher->WorkQueue[DelayedWorkQueue]);
3717 return Status;
3718 }
3719
3720 VOID
3721 RxInitiateSrvOpenKeyAssociation (
3722 IN OUT PSRV_OPEN SrvOpen
3723 )
3724 {
3725 UNIMPLEMENTED;
3726 }
3727
3728 /*
3729 * @implemented
3730 */
3731 NTSTATUS
3732 RxInsertWorkQueueItem(
3733 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
3734 WORK_QUEUE_TYPE WorkQueueType,
3735 PRX_WORK_DISPATCH_ITEM DispatchItem)
3736 {
3737 KIRQL OldIrql;
3738 NTSTATUS Status;
3739 BOOLEAN SpinUpThreads;
3740 PRX_WORK_QUEUE WorkQueue;
3741
3742 /* No dispatcher, nothing to insert */
3743 if (RxDispatcher.State != RxDispatcherActive)
3744 {
3745 return STATUS_UNSUCCESSFUL;
3746 }
3747
3748 /* Get the work queue */
3749 WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
3750
3751 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
3752 /* Only insert if the work queue is in decent state */
3753 if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
3754 {
3755 Status = STATUS_UNSUCCESSFUL;
3756 }
3757 else
3758 {
3759 SpinUpThreads = FALSE;
3760 DispatchItem->WorkQueueItem.pDeviceObject = pMRxDeviceObject;
3761 InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
3762 WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
3763 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
3764
3765 /* If required (and possible!), spin up a new worker thread */
3766 if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
3767 WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
3768 !WorkQueue->SpinUpRequestPending)
3769 {
3770 WorkQueue->SpinUpRequestPending = TRUE;
3771 SpinUpThreads = TRUE;
3772 }
3773
3774 Status = STATUS_SUCCESS;
3775 }
3776 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
3777
3778 /* If we failed, return and still not insert item */
3779 if (!NT_SUCCESS(Status))
3780 {
3781 return Status;
3782 }
3783
3784 /* All fine, insert the item */
3785 KeInsertQueue(&WorkQueue->Queue, &DispatchItem->WorkQueueItem.List);
3786
3787 /* And start a new worker thread if needed */
3788 if (SpinUpThreads)
3789 {
3790 RxSpinUpWorkerThreads(WorkQueue);
3791 }
3792
3793 return Status;
3794 }
3795
3796 BOOLEAN
3797 RxIsThisACscAgentOpen(
3798 IN PRX_CONTEXT RxContext)
3799 {
3800 BOOLEAN CscAgent;
3801
3802 CscAgent = FALSE;
3803
3804 /* Client Side Caching is DFS stuff - we don't support it */
3805 if (RxContext->Create.EaLength != 0)
3806 {
3807 UNIMPLEMENTED;
3808 }
3809
3810 if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
3811 ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
3812 {
3813 CscAgent = TRUE;
3814 }
3815
3816 return CscAgent;
3817 }
3818
3819 VOID
3820 RxLockUserBuffer(
3821 IN PRX_CONTEXT RxContext,
3822 IN LOCK_OPERATION Operation,
3823 IN ULONG BufferLength)
3824 {
3825 PIRP Irp;
3826 PMDL Mdl = NULL;
3827
3828 PAGED_CODE();
3829
3830 _SEH2_TRY
3831 {
3832 Irp = RxContext->CurrentIrp;
3833 /* If we already have a MDL, make sure it's locked */
3834 if (Irp->MdlAddress != NULL)
3835 {
3836 ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
3837 }
3838 else
3839 {
3840 /* That likely means the driver asks for buffered IOs - we don't support it! */
3841 ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
3842
3843 /* If we have a real length */
3844 if (BufferLength > 0)
3845 {
3846 /* Allocate a MDL and lock it */
3847 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
3848 if (Mdl == NULL)
3849 {
3850 RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
3851 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3852 }
3853
3854 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
3855 }
3856 }
3857 }
3858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3859 {
3860 NTSTATUS Status;
3861
3862 Status = _SEH2_GetExceptionCode();
3863
3864 /* Free the possible MDL we have allocated */
3865 IoFreeMdl(Mdl);
3866 Irp->MdlAddress = NULL;
3867
3868 RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
3869
3870 /* Fix status */
3871 if (!FsRtlIsNtstatusExpected(Status))
3872 {
3873 Status = STATUS_INVALID_USER_BUFFER;
3874 }
3875
3876 RxContext->IoStatusBlock.Status = Status;
3877 ExRaiseStatus(Status);
3878 }
3879 _SEH2_END;
3880 }
3881
3882 NTSTATUS
3883 RxLowIoCompletionTail(
3884 IN PRX_CONTEXT RxContext)
3885 {
3886 NTSTATUS Status;
3887 USHORT Operation;
3888
3889 PAGED_CODE();
3890
3891 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
3892
3893 /* Only continue if we're at APC_LEVEL or lower */
3894 if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
3895 !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
3896 {
3897 return STATUS_MORE_PROCESSING_REQUIRED;
3898 }
3899
3900 /* Call the completion routine */
3901 DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
3902 Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
3903 if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
3904 {
3905 return Status;
3906 }
3907
3908 /* If it was a RW operation, for a paging file ... */
3909 Operation = RxContext->LowIoContext.Operation;
3910 if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
3911 {
3912 if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
3913 {
3914 UNIMPLEMENTED;
3915 Status = STATUS_NOT_IMPLEMENTED;
3916 }
3917 }
3918 else
3919 {
3920 /* Sanity check: we had known operation */
3921 ASSERT(Operation < LOWIO_OP_MAXIMUM);
3922 }
3923
3924 /* If not sync operation, complete now. Otherwise, caller has already completed */
3925 if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
3926 {
3927 RxCompleteRequest(RxContext, Status);
3928 }
3929
3930 DPRINT("Status: %x\n", Status);
3931 return Status;
3932 }
3933
3934 /*
3935 * @implemented
3936 */
3937 NTSTATUS
3938 NTAPI
3939 RxLowIoPopulateFsctlInfo(
3940 IN PRX_CONTEXT RxContext)
3941 {
3942 PMDL Mdl;
3943 PIRP Irp;
3944 UCHAR Method;
3945 PIO_STACK_LOCATION Stack;
3946
3947 PAGED_CODE();
3948
3949 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
3950
3951 Irp = RxContext->CurrentIrp;
3952 Stack = RxContext->CurrentIrpSp;
3953
3954 /* Copy stack parameters */
3955 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
3956 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
3957 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
3958 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
3959 Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
3960
3961 /* Same buffer in case of buffered */
3962 if (Method == METHOD_BUFFERED)
3963 {
3964 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
3965 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
3966
3967 return STATUS_SUCCESS;
3968 }
3969
3970 /* Two buffers for neither */
3971 if (Method == METHOD_NEITHER)
3972 {
3973 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
3974 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
3975
3976 return STATUS_SUCCESS;
3977 }
3978
3979 /* Only IN/OUT remain */
3980 ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
3981
3982 /* Use system buffer for input */
3983 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
3984 /* And MDL for output */
3985 Mdl = Irp->MdlAddress;
3986 if (Mdl != NULL)
3987 {
3988 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
3989 if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
3990 {
3991 return STATUS_INSUFFICIENT_RESOURCES;
3992 }
3993 }
3994 else
3995 {
3996 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
3997 }
3998
3999 return STATUS_SUCCESS;
4000 }
4001
4002 NTSTATUS
4003 NTAPI
4004 RxLowIoSubmit(
4005 IN PRX_CONTEXT RxContext,
4006 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
4007 {
4008 NTSTATUS Status;
4009 USHORT Operation;
4010 BOOLEAN Synchronous;
4011 PLOWIO_CONTEXT LowIoContext;
4012
4013 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
4014
4015 PAGED_CODE();
4016
4017 LowIoContext = &RxContext->LowIoContext;
4018 Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4019
4020 LowIoContext->CompletionRoutine = CompletionRoutine;
4021
4022 Status = STATUS_SUCCESS;
4023 Operation = LowIoContext->Operation;
4024 switch (Operation)
4025 {
4026 case LOWIO_OP_READ:
4027 case LOWIO_OP_WRITE:
4028 /* Check that the parameters were properly set by caller
4029 * See comment in RxInitializeLowIoContext()
4030 */
4031 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
4032 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
4033
4034 /* Lock the buffer */
4035 RxLockUserBuffer(RxContext,
4036 (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
4037 LowIoContext->ParamsFor.ReadWrite.ByteCount);
4038 if (RxNewMapUserBuffer(RxContext) == NULL)
4039 {
4040 return STATUS_INSUFFICIENT_RESOURCES;
4041 }
4042 LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
4043
4044 /* If that's a paging IO, initialize serial operation */
4045 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
4046 {
4047 PFCB Fcb;
4048
4049 Fcb = (PFCB)RxContext->pFcb;
4050
4051 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
4052 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
4053 if (Operation == LOWIO_OP_READ)
4054 {
4055 InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
4056 }
4057 else
4058 {
4059 InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
4060 }
4061
4062 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
4063 }
4064
4065 break;
4066
4067 case LOWIO_OP_FSCTL:
4068 case LOWIO_OP_IOCTL:
4069 /* Set FSCTL/IOCTL parameters */
4070 Status = RxLowIoPopulateFsctlInfo(RxContext);
4071 /* Check whether we're consistent: a length means a buffer */
4072 if (NT_SUCCESS(Status))
4073 {
4074 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
4075 LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
4076 (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
4077 LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
4078 {
4079 Status = STATUS_INVALID_PARAMETER;
4080 }
4081 }
4082 break;
4083
4084 /* Nothing to do */
4085 case LOWIO_OP_SHAREDLOCK:
4086 case LOWIO_OP_EXCLUSIVELOCK:
4087 case LOWIO_OP_UNLOCK:
4088 case LOWIO_OP_UNLOCK_MULTIPLE:
4089 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
4090 case LOWIO_OP_CLEAROUT:
4091 break;
4092
4093 default:
4094 ASSERT(FALSE);
4095 Status = STATUS_INVALID_PARAMETER;
4096 break;
4097 }
4098
4099 /* No need to perform extra init in case of posting */
4100 RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
4101
4102 /* Preflight checks were OK, time to submit */
4103 if (NT_SUCCESS(Status))
4104 {
4105 PMINIRDR_DISPATCH Dispatch;
4106
4107 if (!Synchronous)
4108 {
4109 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
4110 /* If not synchronous, we're likely to return before the operation is finished */
4111 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
4112 {
4113 IoMarkIrpPending(RxContext->CurrentIrp);
4114 }
4115 }
4116
4117 Dispatch = RxContext->RxDeviceObject->Dispatch;
4118 if (Dispatch != NULL)
4119 {
4120 /* We'll try to execute until the mini-rdr doesn't return pending */
4121 do
4122 {
4123 RxContext->IoStatusBlock.Information = 0;
4124
4125 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
4126 if (Status == STATUS_PENDING)
4127 {
4128 /* Unless it's not synchronous, caller will be happy with pending op */
4129 if (!Synchronous)
4130 {
4131 return Status;
4132 }
4133
4134 RxWaitSync(RxContext);
4135 Status = RxContext->IoStatusBlock.Status;
4136 }
4137 else
4138 {
4139 if (!Synchronous)
4140 {
4141 /* We had marked the IRP pending, whereas the operation finished, drop that */
4142 if (Status != STATUS_RETRY)
4143 {
4144 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
4145 {
4146 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
4147 }
4148
4149 InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
4150 }
4151 }
4152 }
4153 } while (Status == STATUS_PENDING);
4154 }
4155 else
4156 {
4157 Status = STATUS_INVALID_PARAMETER;
4158 }
4159 }
4160
4161 /* Call completion and return */
4162 RxContext->IoStatusBlock.Status = Status;
4163 LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
4164 return RxLowIoCompletionTail(RxContext);
4165 }
4166
4167 /*
4168 * @implemented
4169 */
4170 PVOID
4171 RxMapSystemBuffer(
4172 IN PRX_CONTEXT RxContext)
4173 {
4174 PIRP Irp;
4175
4176 PAGED_CODE();
4177
4178 Irp = RxContext->CurrentIrp;
4179 /* We should have a MDL (buffered IOs are not supported!) */
4180 if (Irp->MdlAddress != NULL)
4181 {
4182 ASSERT(FALSE);
4183 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
4184 }
4185
4186 /* Just return system buffer */
4187 return Irp->AssociatedIrp.SystemBuffer;
4188 }
4189
4190 VOID
4191 RxMarkFobxOnCleanup(
4192 PFOBX pFobx,
4193 PBOOLEAN NeedPurge)
4194 {
4195 UNIMPLEMENTED;
4196 }
4197
4198 VOID
4199 RxMarkFobxOnClose(
4200 PFOBX Fobx)
4201 {
4202 UNIMPLEMENTED;
4203 }
4204
4205 /*
4206 * @implemented
4207 */
4208 PVOID
4209 RxNewMapUserBuffer(
4210 PRX_CONTEXT RxContext)
4211 {
4212 PIRP Irp;
4213
4214 PAGED_CODE();
4215
4216 Irp = RxContext->CurrentIrp;
4217 if (Irp->MdlAddress != NULL)
4218 {
4219 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
4220 }
4221
4222 return Irp->UserBuffer;
4223 }
4224
4225 BOOLEAN
4226 NTAPI
4227 RxNoOpAcquire(
4228 IN PVOID Fcb,
4229 IN BOOLEAN Wait)
4230 {
4231 UNIMPLEMENTED;
4232 return FALSE;
4233 }
4234
4235 VOID
4236 NTAPI
4237 RxNoOpRelease(
4238 IN PVOID Fcb)
4239 {
4240 UNIMPLEMENTED;
4241 }
4242
4243 VOID
4244 RxOrphanThisFcb(
4245 PFCB Fcb)
4246 {
4247 UNIMPLEMENTED;
4248 }
4249
4250 /*
4251 * @implemented
4252 */
4253 BOOLEAN
4254 RxpAcquirePrefixTableLockShared(
4255 PRX_PREFIX_TABLE pTable,
4256 BOOLEAN Wait,
4257 BOOLEAN ProcessBufferingStateChangeRequests)
4258 {
4259 PAGED_CODE();
4260
4261 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
4262 pTable->TableLock.ActiveEntries);
4263
4264 return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
4265 }
4266
4267 /*
4268 * @implemented
4269 */
4270 BOOLEAN
4271 RxpAcquirePrefixTableLockExclusive(
4272 PRX_PREFIX_TABLE pTable,
4273 BOOLEAN Wait,
4274 BOOLEAN ProcessBufferingStateChangeRequests)
4275 {
4276 PAGED_CODE();
4277
4278 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
4279 pTable->TableLock.ActiveEntries);
4280
4281 return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
4282 }
4283
4284 /*
4285 * @implemented
4286 */
4287 BOOLEAN
4288 RxpDereferenceAndFinalizeNetFcb(
4289 OUT PFCB ThisFcb,
4290 IN PRX_CONTEXT RxContext,
4291 IN BOOLEAN RecursiveFinalize,
4292 IN BOOLEAN ForceFinalize)
4293 {
4294 NTSTATUS Status;
4295 ULONG References;
4296 PNET_ROOT NetRoot;
4297 BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
4298
4299 PAGED_CODE();
4300
4301 ASSERT(!ForceFinalize);
4302 ASSERT(NodeTypeIsFcb(ThisFcb));
4303 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
4304
4305 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
4306 References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
4307 if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
4308 {
4309 return FALSE;
4310 }
4311
4312 Freed = FALSE;
4313 Status = STATUS_SUCCESS;
4314 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
4315 ResourceAcquired = FALSE;
4316 NetRootReferenced = FALSE;
4317 /* If FCB isn't orphaned, it still have context attached */
4318 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
4319 {
4320 /* Don't let NetRoot go away before we're done */
4321 RxReferenceNetRoot(NetRoot);
4322 NetRootReferenced = TRUE;
4323
4324 /* Try to acquire the table lock exclusively */
4325 if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
4326 {
4327 RxReferenceNetFcb(ThisFcb);
4328
4329 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
4330 {
4331 if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
4332 {
4333 RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
4334 }
4335
4336 RxReleaseFcb(RxContext, ThisFcb);
4337
4338 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
4339
4340 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
4341 }
4342
4343 References = RxDereferenceNetFcb(ThisFcb);
4344
4345 ResourceAcquired = TRUE;
4346 }
4347 }
4348
4349 /* If locking was OK (or not needed!), attempt finalization */
4350 if (NT_SUCCESS(Status))
4351 {
4352 Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
4353 }
4354
4355 /* Release table lock if acquired */
4356 if (ResourceAcquired)
4357 {
4358 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4359 }
4360
4361 /* We don't need the NetRoot anylonger */
4362 if (NetRootReferenced)
4363 {
4364 RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
4365 }
4366
4367 return Freed;
4368 }
4369
4370 LONG
4371 RxpDereferenceNetFcb(
4372 PFCB Fcb)
4373 {
4374 UNIMPLEMENTED;
4375 return 0;
4376 }
4377
4378 /*
4379 * @implemented
4380 */
4381 PRX_PREFIX_ENTRY
4382 RxPrefixTableInsertName(
4383 IN OUT PRX_PREFIX_TABLE ThisTable,
4384 IN OUT PRX_PREFIX_ENTRY ThisEntry,
4385 IN PVOID Container,
4386 IN PULONG ContainerRefCount,
4387 IN USHORT CaseInsensitiveLength,
4388 IN PRX_CONNECTION_ID ConnectionId
4389 )
4390 {
4391 PAGED_CODE();
4392
4393 DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
4394
4395 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
4396 ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
4397
4398 /* Copy parameters and compute hash */
4399 ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
4400 ThisEntry->ContainingRecord = Container;
4401 ThisEntry->ContainerRefCount = ContainerRefCount;
4402 InterlockedIncrement((volatile long *)ContainerRefCount);
4403 ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
4404 DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
4405
4406 /* If no path length: this is entry for null path */
4407 if (ThisEntry->Prefix.Length == 0)
4408 {
4409 ThisTable->TableEntryForNull = ThisEntry;
4410 }
4411 /* Otherwise, insert in the appropriate bucket */
4412 else
4413 {
4414 InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
4415 }
4416
4417 /* If we had a connection ID, keep track of it */
4418 if (ConnectionId != NULL)
4419 {
4420 ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
4421 }
4422 else
4423 {
4424 ThisEntry->ConnectionId.Luid.LowPart = 0;
4425 ThisEntry->ConnectionId.Luid.HighPart = 0;
4426 }
4427
4428 InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
4429 /* Reflect the changes */
4430 ++ThisTable->Version;
4431
4432 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
4433
4434 return ThisEntry;
4435 }
4436
4437 /*
4438 * @implemented
4439 */
4440 PVOID
4441 RxPrefixTableLookupName(
4442 IN PRX_PREFIX_TABLE ThisTable,
4443 IN PUNICODE_STRING CanonicalName,
4444 OUT PUNICODE_STRING RemainingName,
4445 IN PRX_CONNECTION_ID ConnectionId)
4446 {
4447 PVOID Container;
4448
4449 PAGED_CODE();
4450
4451 ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
4452 ASSERT(CanonicalName->Length > 0);
4453
4454 /* Call the internal helper */
4455 Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
4456 if (Container == NULL)
4457 {
4458 return NULL;
4459 }
4460
4461 /* Reference our container before returning it */
4462 if (RdbssReferenceTracingValue != 0)
4463 {
4464 NODE_TYPE_CODE Type;
4465
4466 Type = NodeType(Container);
4467 switch (Type)
4468 {
4469 case RDBSS_NTC_SRVCALL:
4470 RxReferenceSrvCall(Container);
4471 break;
4472
4473 case RDBSS_NTC_NETROOT:
4474 RxReferenceNetRoot(Container);
4475 break;
4476
4477 case RDBSS_NTC_V_NETROOT:
4478 RxReferenceVNetRoot(Container);
4479 break;
4480
4481 default:
4482 ASSERT(FALSE);
4483 break;
4484 }
4485 }
4486 else
4487 {
4488 RxReference(Container);
4489 }
4490
4491 return Container;
4492 }
4493
4494 LONG
4495 RxpReferenceNetFcb(
4496 PFCB Fcb)
4497 {
4498 UNIMPLEMENTED;
4499 return 0;
4500 }
4501
4502 /*
4503 * @implemented
4504 */
4505 VOID
4506 RxpReleasePrefixTableLock(
4507 PRX_PREFIX_TABLE pTable,
4508 BOOLEAN ProcessBufferingStateChangeRequests)
4509 {
4510 PAGED_CODE();
4511
4512 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
4513 pTable->TableLock.ActiveEntries);
4514
4515 ExReleaseResourceLite(&pTable->TableLock);
4516 }
4517
4518 /*
4519 * @implemented
4520 */
4521 VOID
4522 NTAPI
4523 RxPrepareContextForReuse(
4524 IN OUT PRX_CONTEXT RxContext)
4525 {
4526 PAGED_CODE();
4527
4528 /* When we reach that point, make sure mandatory parts are null-ed */
4529 if (RxContext->MajorFunction == IRP_MJ_CREATE)
4530 {
4531 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
4532 RxContext->Create.RdrFlags = 0;
4533 }
4534 else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
4535 {
4536 ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
4537 ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
4538 }
4539
4540 RxContext->ReferenceCount = 0;
4541 }
4542
4543 VOID
4544 RxProcessFcbChangeBufferingStateRequest(
4545 PFCB Fcb)
4546 {
4547 UNIMPLEMENTED;
4548 }
4549
4550 BOOLEAN
4551 RxpTrackDereference(
4552 _In_ ULONG TraceType,
4553 _In_ PCSTR FileName,
4554 _In_ ULONG Line,
4555 _In_ PVOID Instance)
4556 {
4557 UNIMPLEMENTED;
4558 return FALSE;
4559 }
4560
4561 VOID
4562 RxpTrackReference(
4563 _In_ ULONG TraceType,
4564 _In_ PCSTR FileName,
4565 _In_ ULONG Line,
4566 _In_ PVOID Instance)
4567 {
4568 UNIMPLEMENTED;
4569 }
4570
4571 VOID
4572 RxpUndoScavengerFinalizationMarking(
4573 PVOID Instance)
4574 {
4575 UNIMPLEMENTED;
4576 }
4577
4578 NTSTATUS
4579 RxPurgeFcbInSystemCache(
4580 IN PFCB Fcb,
4581 IN PLARGE_INTEGER FileOffset OPTIONAL,
4582 IN ULONG Length,
4583 IN BOOLEAN UninitializeCacheMaps,
4584 IN BOOLEAN FlushFile)
4585 {
4586 UNIMPLEMENTED;
4587 return STATUS_NOT_IMPLEMENTED;
4588 }
4589
4590 /*
4591 * @implemented
4592 */
4593 VOID
4594 RxpWorkerThreadDispatcher(
4595 IN PRX_WORK_QUEUE WorkQueue,
4596 IN PLARGE_INTEGER WaitInterval)
4597 {
4598 NTSTATUS Status;
4599 PVOID Parameter;
4600 PETHREAD CurrentThread;
4601 BOOLEAN KillThread, Dereference;
4602 PRX_WORK_QUEUE_ITEM WorkQueueItem;
4603 PWORKER_THREAD_ROUTINE WorkerRoutine;
4604
4605 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
4606
4607 /* Reference ourselves */
4608 CurrentThread = PsGetCurrentThread();
4609 Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, PsThreadType, KernelMode);
4610 ASSERT(NT_SUCCESS(Status));
4611
4612 /* Infinite loop for worker */
4613 KillThread = FALSE;
4614 Dereference = FALSE;
4615 do
4616 {
4617 KIRQL OldIrql;
4618 PLIST_ENTRY ListEntry;
4619
4620 /* Remove an entry from the work queue */
4621 ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
4622 if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
4623 {
4624 PRDBSS_DEVICE_OBJECT DeviceObject;
4625
4626 WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
4627
4628 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
4629 InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
4630 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4631
4632 /* Get the parameters, and null-them in the struct */
4633 WorkerRoutine = WorkQueueItem->WorkerRoutine;
4634 Parameter = WorkQueueItem->Parameter;
4635 DeviceObject = WorkQueueItem->pDeviceObject;
4636
4637 WorkQueueItem->List.Flink = NULL;
4638 WorkQueueItem->WorkerRoutine = NULL;
4639 WorkQueueItem->Parameter = NULL;
4640 WorkQueueItem->pDeviceObject = NULL;
4641
4642 /* Call the routine */
4643 DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
4644 WorkerRoutine(Parameter);
4645
4646 /* Are we going down now? */
4647 if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
4648 {
4649 PKEVENT TearDownEvent;
4650
4651 TearDownEvent = InterlockedExchangePointer((volatile PVOID)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
4652 if (TearDownEvent != NULL)
4653 {
4654 KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
4655 }
4656 }
4657
4658 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
4659 }
4660
4661 /* Shall we shutdown... */
4662 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4663 switch (WorkQueue->State)
4664 {
4665 /* Our queue is active, kill it if we have no more items to dispatch
4666 * and more threads than the required minimum
4667 */
4668 case RxWorkQueueActive:
4669 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
4670 {
4671 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
4672 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
4673 {
4674 KillThread = TRUE;
4675 Dereference = TRUE;
4676 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4677 }
4678
4679 if (KillThread)
4680 {
4681 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4682 }
4683 }
4684 break;
4685
4686 /* The queue is inactive: kill it we have more threads than the required minimum */
4687 case RxWorkQueueInactive:
4688 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
4689 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
4690 {
4691 KillThread = TRUE;
4692 Dereference = TRUE;
4693 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4694 }
4695
4696 if (KillThread)
4697 {
4698 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4699 }
4700 break;
4701
4702 /* Rundown in progress..., kill it for sure! */
4703 case RxWorkQueueRundownInProgress:
4704 {
4705 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
4706
4707 ASSERT(WorkQueue->pRundownContext != NULL);
4708
4709 RundownContext = WorkQueue->pRundownContext;
4710 RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
4711
4712 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4713 KillThread = TRUE;
4714 Dereference = FALSE;
4715
4716 if (WorkQueue->NumberOfActiveWorkerThreads == 0)
4717 {
4718 KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
4719 }
4720
4721 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4722 }
4723 break;
4724
4725 default:
4726 break;
4727 }
4728 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4729 } while (!KillThread);
4730
4731 DPRINT("Killed worker thread\n");
4732
4733 /* Do we have to dereference ourselves? */
4734 if (Dereference)
4735 {
4736 ObDereferenceObject(CurrentThread);
4737 }
4738
4739 /* Dump last executed routine */
4740 if (DumpDispatchRoutine)
4741 {
4742 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
4743 }
4744
4745 PsTerminateSystemThread(STATUS_SUCCESS);
4746 }
4747
4748 VOID
4749 RxReference(
4750 IN OUT PVOID Instance)
4751 {
4752 NODE_TYPE_CODE NodeType;
4753 PNODE_TYPE_AND_SIZE Node;
4754
4755 PAGED_CODE();
4756
4757 RxAcquireScavengerMutex();
4758
4759 /* We can only reference a few structs */
4760 NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
4761 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
4762 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
4763 (NodeType == RDBSS_NTC_FOBX));
4764
4765 Node = (PNODE_TYPE_AND_SIZE)Instance;
4766 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
4767
4768 /* Trace refcount if asked */
4769 switch (NodeType)
4770 {
4771 case RDBSS_NTC_SRVCALL:
4772 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
4773 break;
4774
4775 case RDBSS_NTC_NETROOT:
4776 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
4777 break;
4778
4779 case RDBSS_NTC_V_NETROOT:
4780 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
4781 break;
4782
4783 case RDBSS_NTC_SRVOPEN:
4784 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
4785 break;
4786
4787 case RDBSS_NTC_FOBX:
4788 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
4789 break;
4790
4791 default:
4792 ASSERT(FALSE);
4793 break;
4794 }
4795
4796 RxpUndoScavengerFinalizationMarking(Instance);
4797 RxReleaseScavengerMutex();
4798 }
4799
4800 VOID
4801 NTAPI
4802 RxResumeBlockedOperations_Serially(
4803 IN OUT PRX_CONTEXT RxContext,
4804 IN OUT PLIST_ENTRY BlockingIoQ)
4805 {
4806 PAGED_CODE();
4807
4808 RxAcquireSerializationMutex();
4809
4810 /* This can only happen on pipes */
4811 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
4812 {
4813 RxReleaseSerializationMutex();
4814 return;
4815 }
4816
4817 UNIMPLEMENTED;
4818
4819 RxReleaseSerializationMutex();
4820 }
4821
4822 BOOLEAN
4823 RxScavengeRelatedFobxs(
4824 PFCB Fcb)
4825 {
4826 UNIMPLEMENTED;
4827 return FALSE;
4828 }
4829
4830 BOOLEAN
4831 RxScavengeVNetRoots(
4832 PRDBSS_DEVICE_OBJECT RxDeviceObject)
4833 {
4834 UNIMPLEMENTED;
4835 return FALSE;
4836 }
4837
4838 /*
4839 * @implemented
4840 */
4841 VOID
4842 NTAPI
4843 RxSpinUpRequestsDispatcher(
4844 PVOID Dispatcher)
4845 {
4846 NTSTATUS Status;
4847 PRX_DISPATCHER RxDispatcher;
4848
4849 Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, PsThreadType, KernelMode);
4850 if (!NT_SUCCESS(Status))
4851 {
4852 PsTerminateSystemThread(STATUS_SUCCESS);
4853 }
4854
4855 RxDispatcher = Dispatcher;
4856
4857 do
4858 {
4859 KIRQL OldIrql;
4860 PLIST_ENTRY ListEntry;
4861
4862 Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
4863 KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
4864 ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
4865
4866 KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
4867 if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
4868 {
4869 ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
4870 }
4871 else
4872 {
4873 ListEntry = &RxDispatcher->SpinUpRequests;
4874 }
4875 KeResetEvent(&RxDispatcher->SpinUpRequestsEvent);
4876 KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
4877
4878 while (ListEntry != &RxDispatcher->SpinUpRequests)
4879 {
4880 PWORK_QUEUE_ITEM WorkItem;
4881 PRX_WORK_QUEUE WorkQueue;
4882
4883 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
4884 WorkQueue = WorkItem->Parameter;
4885
4886 InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
4887
4888 DPRINT1("WORKQ:SR %lx %lx\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
4889 WorkItem->WorkerRoutine(WorkItem->Parameter);
4890 }
4891 } while (RxDispatcher->State == RxDispatcherActive);
4892
4893 KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
4894 PsTerminateSystemThread(STATUS_SUCCESS);
4895 }
4896
4897 /*
4898 * @implemented
4899 */
4900 NTSTATUS
4901 RxSpinUpWorkerThread(
4902 PRX_WORK_QUEUE WorkQueue,
4903 PRX_WORKERTHREAD_ROUTINE Routine,
4904 PVOID Parameter)
4905 {
4906 KIRQL OldIrql;
4907 NTSTATUS Status;
4908 HANDLE ThreadHandle;
4909
4910 PAGED_CODE();
4911
4912 /* If work queue is inactive, that cannot work */
4913 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4914 if (WorkQueue->State != RxWorkQueueActive)
4915 {
4916 Status = STATUS_UNSUCCESSFUL;
4917 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
4918 }
4919 else
4920 {
4921 ++WorkQueue->NumberOfActiveWorkerThreads;
4922 Status = STATUS_SUCCESS;
4923 }
4924 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4925
4926 /* Quit on failure */
4927 if (!NT_SUCCESS(Status))
4928 {
4929 return Status;
4930 }
4931
4932 /* Spin up the worker thread */
4933 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
4934 if (NT_SUCCESS(Status))
4935 {
4936 ZwClose(ThreadHandle);
4937 return Status;
4938 }
4939 /* Read well: we reached that point because it failed! */
4940 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
4941
4942 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4943 --WorkQueue->NumberOfActiveWorkerThreads;
4944 ++WorkQueue->NumberOfFailedSpinUpRequests;
4945
4946 /* Rundown, no more active threads, set the event! */
4947 if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
4948 WorkQueue->State == RxWorkQueueRundownInProgress)
4949 {
4950 KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
4951 }
4952
4953 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
4954
4955 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4956
4957 return Status;
4958 }
4959
4960 VOID
4961 RxSpinUpWorkerThreads(
4962 PRX_WORK_QUEUE WorkQueue)
4963 {
4964 UNIMPLEMENTED;
4965 }
4966
4967 VOID
4968 RxSynchronizeWithScavenger(
4969 IN PRX_CONTEXT RxContext)
4970 {
4971 UNIMPLEMENTED;
4972 }
4973
4974 /*
4975 * @implemented
4976 */
4977 ULONG
4978 RxTableComputeHashValue(
4979 IN PUNICODE_STRING Name)
4980 {
4981 ULONG Hash;
4982 SHORT Loops[8];
4983 USHORT MaxChar, i;
4984
4985 PAGED_CODE();
4986
4987 MaxChar = Name->Length / sizeof(WCHAR);
4988
4989 Loops[0] = 1;
4990 Loops[1] = MaxChar - 1;
4991 Loops[2] = MaxChar - 2;
4992 Loops[3] = MaxChar - 3;
4993 Loops[4] = MaxChar - 4;
4994 Loops[5] = MaxChar / 4;
4995 Loops[6] = 2 * MaxChar / 4;
4996 Loops[7] = 3 * MaxChar / 4;
4997
4998 Hash = 0;
4999 for (i = 0; i < 8; ++i)
5000 {
5001 SHORT Idx;
5002
5003 Idx = Loops[i];
5004 if (Idx >= 0 && Idx < MaxChar)
5005 {
5006 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
5007 }
5008 }
5009
5010 return Hash;
5011 }
5012
5013 /*
5014 * @implemented
5015 */
5016 ULONG
5017 RxTableComputePathHashValue(
5018 IN PUNICODE_STRING Name)
5019 {
5020 ULONG Hash;
5021 SHORT Loops[8];
5022 USHORT MaxChar, i;
5023
5024 PAGED_CODE();
5025
5026 MaxChar = Name->Length / sizeof(WCHAR);
5027
5028 Loops[0] = 1;
5029 Loops[1] = MaxChar - 1;
5030 Loops[2] = MaxChar - 2;
5031 Loops[3] = MaxChar - 3;
5032 Loops[4] = MaxChar - 4;
5033 Loops[5] = MaxChar / 4;
5034 Loops[6] = 2 * MaxChar / 4;
5035 Loops[7] = 3 * MaxChar / 4;
5036
5037 Hash = 0;
5038 for (i = 0; i < 8; ++i)
5039 {
5040 SHORT Idx;
5041
5042 Idx = Loops[i];
5043 if (Idx >= 0 && Idx < MaxChar)
5044 {
5045 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
5046 }
5047 }
5048
5049 return Hash;
5050 }
5051
5052 PVOID
5053 RxTableLookupName(
5054 IN PRX_PREFIX_TABLE ThisTable,
5055 IN PUNICODE_STRING Name,
5056 OUT PUNICODE_STRING RemainingName,
5057 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
5058 {
5059 PVOID Container;
5060 USHORT i, MaxChar;
5061 PRX_PREFIX_ENTRY Entry;
5062 RX_CONNECTION_ID NullId;
5063 UNICODE_STRING LookupString;
5064
5065 PAGED_CODE();
5066
5067 /* If caller didn't provide a connection ID, setup one */
5068 if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
5069 {
5070 NullId.Luid.LowPart = 0;
5071 NullId.Luid.HighPart = 0;
5072 RxConnectionId = &NullId;
5073 }
5074
5075 /* Validate name */
5076 ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
5077
5078 Entry = NULL;
5079 Container = NULL;
5080 LookupString.Buffer = Name->Buffer;
5081 MaxChar = Name->Length / sizeof(WCHAR);
5082 /* We'll perform the lookup, path component after another */
5083 for (i = 1; i < MaxChar; ++i)
5084 {
5085 ULONG Hash;
5086 PRX_PREFIX_ENTRY CurEntry;
5087
5088 /* Don't cut in the middle of a path element */
5089 if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
5090 {
5091 continue;
5092 }
5093
5094 /* Perform lookup in the table */
5095 LookupString.Length = i * sizeof(WCHAR);
5096 Hash = RxTableComputeHashValue(&LookupString);
5097 CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
5098 #if DBG
5099 ++ThisTable->Lookups;
5100 #endif
5101 /* Entry not found, move to the next component */
5102 if (CurEntry == NULL)
5103 {
5104 #if DBG
5105 ++ThisTable->FailedLookups;
5106 #endif
5107 continue;
5108 }
5109
5110 Entry = CurEntry;
5111 ASSERT(Entry->ContainingRecord != NULL);
5112 Container = Entry->ContainingRecord;
5113
5114 /* Need to handle NetRoot specific case... */
5115 if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
5116 {
5117 UNIMPLEMENTED;
5118 break;
5119 }
5120 else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
5121 {
5122 break;
5123 }
5124 else
5125 {
5126 ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
5127 }
5128 }
5129
5130 /* Entry was found */
5131 if (Entry != NULL)
5132 {
5133 DPRINT("Found\n");
5134
5135 ASSERT(Name->Length >= Entry->Prefix.Length);
5136
5137 /* Setup remaining name */
5138 RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
5139 RemainingName->Length = Name->Length - Entry->Prefix.Length;
5140 RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
5141 }
5142 else
5143 {
5144 /* Otherwise, that's the whole name */
5145 RemainingName = Name;
5146 }
5147
5148 return Container;
5149 }
5150
5151 /*
5152 * @implemented
5153 */
5154 PRX_PREFIX_ENTRY
5155 RxTableLookupName_ExactLengthMatch(
5156 IN PRX_PREFIX_TABLE ThisTable,
5157 IN PUNICODE_STRING Name,
5158 IN ULONG HashValue,
5159 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
5160 {
5161 PLIST_ENTRY ListEntry, HashBucket;
5162
5163 PAGED_CODE();
5164
5165 ASSERT(RxConnectionId != NULL);
5166
5167 /* Select the right bucket */
5168 HashBucket = HASH_BUCKET(ThisTable, HashValue);
5169 DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
5170 /* If bucket is empty, no match */
5171 if (IsListEmpty(HashBucket))
5172 {
5173 return NULL;
5174 }
5175
5176 /* Browse all the entries in the bucket */
5177 for (ListEntry = HashBucket->Flink;
5178 ListEntry != HashBucket;
5179 ListEntry = ListEntry->Flink)
5180 {
5181 PVOID Container;
5182 PRX_PREFIX_ENTRY Entry;
5183 BOOLEAN CaseInsensitive;
5184 PUNICODE_STRING CmpName, CmpPrefix;
5185 UNICODE_STRING InsensitiveName, InsensitivePrefix;
5186
5187 Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
5188 ++ThisTable->Considers;
5189 ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
5190
5191 Container = Entry->ContainingRecord;
5192 ASSERT(Container != NULL);
5193
5194 /* Not the same hash, not the same length, move on */
5195 if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
5196 {
5197 continue;
5198 }
5199
5200 ++ThisTable->Compares;
5201 /* If we have to perform a case insensitive compare on a portion... */
5202 if (Entry->CaseInsensitiveLength != 0)
5203 {
5204 ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
5205
5206 /* Perform the case insensitive check on the asked length */
5207 InsensitiveName.Buffer = Name->Buffer;
5208 InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
5209 InsensitiveName.Length = Entry->CaseInsensitiveLength;
5210 InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
5211 /* No match, move to the next entry */
5212 if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
5213 {
5214 continue;
5215 }
5216
5217 /* Was the case insensitive covering the whole name? */
5218 if (Name->Length == Entry->CaseInsensitiveLength)
5219 {
5220 /* If connection ID also matches, that a complete match! */
5221 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
5222 {
5223 return Entry;
5224 }
5225 }
5226
5227 /* Otherwise, we have to continue with the sensitive match.... */
5228 InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
5229 InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
5230 InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
5231 InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
5232
5233 CmpName = &InsensitiveName;
5234 CmpPrefix = &InsensitivePrefix;
5235 CaseInsensitive = FALSE;
5236 }
5237 else
5238 {
5239 CmpName = Name;
5240 CmpPrefix = &Entry->Prefix;
5241 CaseInsensitive = ThisTable->CaseInsensitiveMatch;
5242 }
5243
5244 /* Perform the compare, if there's a match, also check for connection ID */
5245 if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
5246 {
5247 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
5248 {
5249 return Entry;
5250 }
5251 }
5252 }
5253
5254 return NULL;
5255 }
5256
5257 VOID
5258 RxTrackerUpdateHistory(
5259 _Inout_opt_ PRX_CONTEXT RxContext,
5260 _Inout_ PMRX_FCB MrxFcb,
5261 _In_ ULONG Operation,
5262 _In_ ULONG LineNumber,
5263 _In_ PCSTR FileName,
5264 _In_ ULONG SerialNumber)
5265 {
5266 UNIMPLEMENTED;
5267 }
5268
5269 VOID
5270 RxTrackPagingIoResource(
5271 _Inout_ PVOID Instance,
5272 _In_ ULONG Type,
5273 _In_ ULONG Line,
5274 _In_ PCSTR File)
5275 {
5276 UNIMPLEMENTED;
5277 }
5278
5279 /*
5280 * @implemented
5281 */
5282 VOID
5283 RxUninitializeVNetRootParameters(
5284 IN PUNICODE_STRING UserName,
5285 IN PUNICODE_STRING UserDomainName,
5286 IN PUNICODE_STRING Password,
5287 OUT PULONG Flags)
5288 {
5289 PAGED_CODE();
5290
5291 /* Only free what could have been allocated */
5292 if (UserName != NULL)
5293 {
5294 ExFreePool(UserName);
5295 }
5296
5297 if (UserDomainName != NULL)
5298 {
5299 ExFreePool(UserDomainName);
5300 }
5301
5302 if (Password != NULL)
5303 {
5304 ExFreePool(Password);
5305 }
5306
5307 /* And remove the possibly set CSC agent flag */
5308 if (Flags != NULL)
5309 {
5310 (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
5311 }
5312 }
5313
5314 /*
5315 * @implemented
5316 */
5317 VOID
5318 RxUpdateCondition(
5319 IN RX_BLOCK_CONDITION NewConditionValue,
5320 OUT PRX_BLOCK_CONDITION Condition,
5321 IN OUT PLIST_ENTRY TransitionWaitList)
5322 {
5323 PRX_CONTEXT Context;
5324 LIST_ENTRY SerializationQueue;
5325
5326 PAGED_CODE();
5327
5328 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
5329
5330 /* Set the new condition */
5331 RxAcquireSerializationMutex();
5332 ASSERT(NewConditionValue != Condition_InTransition);
5333 *Condition = NewConditionValue;
5334 /* And get the serialization queue for treatment */
5335 RxTransferList(&SerializationQueue, TransitionWaitList);
5336 RxReleaseSerializationMutex();
5337
5338 /* Handle the serialization queue */
5339 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
5340 while (Context != NULL)
5341 {
5342 /* If the caller asked for post, post the request */
5343 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
5344 {
5345 Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
5346 RxFsdPostRequest(Context);
5347 }
5348 /* Otherwise, wake up sleeping waiters */
5349 else
5350 {
5351 RxSignalSynchronousWaiter(Context);
5352 }
5353
5354 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
5355 }
5356 }
5357
5358 VOID
5359 RxVerifyOperationIsLegal(
5360 IN PRX_CONTEXT RxContext)
5361 {
5362 UNIMPLEMENTED;
5363 }
5364
5365 /*
5366 * @implemented
5367 */
5368 VOID
5369 RxWaitForStableCondition(
5370 IN PRX_BLOCK_CONDITION Condition,
5371 IN OUT PLIST_ENTRY TransitionWaitList,
5372 IN OUT PRX_CONTEXT RxContext,
5373 OUT NTSTATUS *AsyncStatus OPTIONAL)
5374 {
5375 BOOLEAN Wait;
5376 NTSTATUS LocalStatus;
5377
5378 PAGED_CODE();
5379
5380 /* Make sure to always get status */
5381 if (AsyncStatus == NULL)
5382 {
5383 AsyncStatus = &LocalStatus;
5384 }
5385
5386 /* By default, it's a success */
5387 *AsyncStatus = STATUS_SUCCESS;
5388
5389 Wait = FALSE;
5390 /* If it's not stable, we've to wait */
5391 if (!StableCondition(*Condition))
5392 {
5393 /* Lock the mutex */
5394 RxAcquireSerializationMutex();
5395 /* Still not stable? */
5396 if (!StableCondition(*Condition))
5397 {
5398 /* Insert us in the wait list for processing on stable condition */
5399 RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
5400
5401 /* If we're asked to post on stable, don't wait, and just return pending */
5402 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
5403 {
5404 *AsyncStatus = STATUS_PENDING;
5405 }
5406 else
5407 {
5408 Wait = TRUE;
5409 }
5410 }
5411 RxReleaseSerializationMutex();
5412
5413 /* We don't post on stable, so, just wait... */
5414 if (Wait)
5415 {
5416 RxWaitSync(RxContext);
5417 }
5418 }
5419 }
5420
5421 /*
5422 * @implemented
5423 */
5424 VOID
5425 NTAPI
5426 RxWorkItemDispatcher(
5427 PVOID Context)
5428 {
5429 PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
5430
5431 DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
5432
5433 DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
5434
5435 ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
5436 }
5437
5438 NTSTATUS
5439 __RxAcquireFcb(
5440 _Inout_ PFCB Fcb,
5441 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
5442 _In_ ULONG Mode
5443 #ifdef RDBSS_TRACKER
5444 ,
5445 _In_ ULONG LineNumber,
5446 _In_ PCSTR FileName,
5447 _In_ ULONG SerialNumber
5448 #endif
5449 )
5450 {
5451 NTSTATUS Status;
5452 BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
5453
5454 PAGED_CODE();
5455
5456 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
5457
5458 SpecialContext = FALSE;
5459 ContextIsPresent = FALSE;
5460 /* Check for special context */
5461 if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
5462 {
5463 SpecialContext = TRUE;
5464 }
5465
5466 /* We don't handle buffering state change yet... */
5467 if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
5468 BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
5469 {
5470 UNIMPLEMENTED;
5471 }
5472
5473 /* Nor special contexts */
5474 if (SpecialContext)
5475 {
5476 UNIMPLEMENTED;
5477 }
5478
5479 /* Nor missing contexts... */
5480 if (RxContext == NULL)
5481 {
5482 UNIMPLEMENTED;
5483 }
5484
5485 /* That said: we have a real context! */
5486 ContextIsPresent = TRUE;
5487
5488 /* If we've been cancelled in between, give up */
5489 Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
5490 if (!NT_SUCCESS(Status))
5491 {
5492 return Status;
5493 }
5494
5495 /* Can we wait? */
5496 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
5497
5498 while (TRUE)
5499 {
5500 /* Assume we cannot lock */
5501 Status = STATUS_LOCK_NOT_GRANTED;
5502
5503 /* Lock according to what the caller asked */
5504 switch (Mode)
5505 {
5506 case FCB_MODE_EXCLUSIVE:
5507 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
5508 break;
5509
5510 case FCB_MODE_SHARED:
5511 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
5512 break;
5513
5514 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
5515 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
5516 break;
5517
5518 default:
5519 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
5520 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
5521 break;
5522 }
5523
5524 /* Lock granted! */
5525 if (Acquired)
5526 {
5527 Status = STATUS_SUCCESS;
5528 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
5529
5530 /* Handle paging write - not implemented */
5531 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
5532 {
5533 UNIMPLEMENTED;
5534 }
5535 }
5536
5537 /* And break, that cool! */
5538 if (Acquired)
5539 {
5540 break;
5541 }
5542
5543 /* If it failed, return immediately */
5544 if (!NT_SUCCESS(Status))
5545 {
5546 return Status;
5547 }
5548 }
5549
5550 /* If we don't have to check for valid operation, job done, nothing more to do */
5551 if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
5552 {
5553 if (NT_SUCCESS(Status))
5554 {
5555 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
5556 }
5557
5558 return Status;
5559 }
5560
5561 /* Verify operation */
5562 _SEH2_TRY
5563 {
5564 RxVerifyOperationIsLegal(RxContext);
5565 }
5566 _SEH2_FINALLY
5567 {
5568 /* If it failed, release lock and fail */
5569 if (_SEH2_AbnormalTermination())
5570 {
5571 ExReleaseResourceLite(Fcb->Header.Resource);
5572 Status = STATUS_LOCK_NOT_GRANTED;
5573 }
5574 }
5575 _SEH2_END;
5576
5577 if (NT_SUCCESS(Status))
5578 {
5579 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
5580 }
5581
5582 DPRINT("Status: %x\n", Status);
5583 return Status;
5584 }
5585
5586 /*
5587 * @implemented
5588 */
5589 VOID
5590 __RxItsTheSameContext(
5591 _In_ PRX_CONTEXT RxContext,
5592 _In_ ULONG CapturedRxContextSerialNumber,
5593 _In_ ULONG Line,
5594 _In_ PCSTR File)
5595 {
5596 /* Check we have a context with the same serial number */
5597 if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
5598 RxContext->SerialNumber != CapturedRxContextSerialNumber)
5599 {
5600 /* Just be noisy */
5601 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
5602 }
5603 }
5604
5605 VOID
5606 __RxReleaseFcb(
5607 _Inout_opt_ PRX_CONTEXT RxContext,
5608 _Inout_ PMRX_FCB MrxFcb
5609 #ifdef RDBSS_TRACKER
5610 ,
5611 _In_ ULONG LineNumber,
5612 _In_ PCSTR FileName,
5613 _In_ ULONG SerialNumber
5614 #endif
5615 )
5616 {
5617 BOOLEAN IsExclusive, BufferingPending;
5618
5619 RxAcquireSerializationMutex();
5620
5621 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
5622 IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
5623
5624 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5625 * then just release the FCB
5626 */
5627 if (!BufferingPending || !IsExclusive)
5628 {
5629 RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
5630 LineNumber, FileName, SerialNumber);
5631 ExReleaseResourceLite(MrxFcb->Header.Resource);
5632 }
5633
5634 RxReleaseSerializationMutex();
5635
5636 /* And finally leave */
5637 if (!BufferingPending || !IsExclusive)
5638 {
5639 return;
5640 }
5641
5642 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
5643
5644 /* Otherwise, handle buffering state and release */
5645 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
5646
5647 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
5648 ExReleaseResourceLite(MrxFcb->Header.Resource);
5649 }
5650
5651 VOID
5652 __RxReleaseFcbForThread(
5653 _Inout_opt_ PRX_CONTEXT RxContext,
5654 _Inout_ PMRX_FCB MrxFcb,
5655 _In_ ERESOURCE_THREAD ResourceThreadId
5656 #ifdef RDBSS_TRACKER
5657 ,
5658 _In_ ULONG LineNumber,
5659 _In_ PCSTR FileName,
5660 _In_ ULONG SerialNumber
5661 #endif
5662 )
5663 {
5664 BOOLEAN IsExclusive, BufferingPending;
5665
5666 RxAcquireSerializationMutex();
5667
5668 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
5669 IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
5670
5671 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5672 * then just release the FCB
5673 */
5674 if (!BufferingPending || !IsExclusive)
5675 {
5676 RxTrackerUpdateHistory(RxContext, MrxFcb,
5677 (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
5678 LineNumber, FileName, SerialNumber);
5679 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
5680 }
5681
5682 RxReleaseSerializationMutex();
5683
5684 /* And finally leave */
5685 if (!BufferingPending || !IsExclusive)
5686 {
5687 return;
5688 }
5689
5690 /* Otherwise, handle buffering state and release */
5691 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
5692 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
5693 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
5694 }