9cffb083ddf672832498de14f26a8d54de4168b4
[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 /* TODO: trace */
1722 switch (NodeType)
1723 {
1724 case RDBSS_NTC_SRVCALL:
1725 case RDBSS_NTC_NETROOT:
1726 case RDBSS_NTC_V_NETROOT:
1727 case RDBSS_NTC_SRVOPEN:
1728 case RDBSS_NTC_FOBX:
1729 UNIMPLEMENTED;
1730 break;
1731 default:
1732 ASSERT(FALSE);
1733 break;
1734 }
1735
1736 /* No need to free - still in use */
1737 if (RefCount > 1)
1738 {
1739 RxReleaseScavengerMutex();
1740 return;
1741 }
1742
1743 /* We have to be locked exclusively */
1744 if (LockHoldingState != LHS_ExclusiveLockHeld)
1745 {
1746 UNIMPLEMENTED;
1747 RxReleaseScavengerMutex();
1748 return;
1749 }
1750
1751 RxReleaseScavengerMutex();
1752
1753 /* TODO: Really deallocate stuff - we're leaking as hell! */
1754 switch (NodeType)
1755 {
1756 case RDBSS_NTC_SRVCALL:
1757 {
1758 PSRV_CALL SrvCall;
1759
1760 SrvCall = (PSRV_CALL)Instance;
1761
1762 ASSERT(SrvCall->RxDeviceObject != NULL);
1763 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
1764 RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
1765 break;
1766 }
1767
1768 case RDBSS_NTC_NETROOT:
1769 UNIMPLEMENTED;
1770 break;
1771
1772 case RDBSS_NTC_V_NETROOT:
1773 UNIMPLEMENTED;
1774 break;
1775
1776 case RDBSS_NTC_SRVOPEN:
1777 UNIMPLEMENTED;
1778 break;
1779
1780 case RDBSS_NTC_FOBX:
1781 UNIMPLEMENTED;
1782 break;
1783 }
1784 }
1785
1786 /*
1787 * @implemented
1788 */
1789 VOID
1790 NTAPI
1791 RxDereferenceAndDeleteRxContext_Real(
1792 IN PRX_CONTEXT RxContext)
1793 {
1794 KIRQL OldIrql;
1795 ULONG RefCount;
1796 BOOLEAN Allocated;
1797 PRX_CONTEXT StopContext = NULL;
1798
1799 /* Make sure we really have a context */
1800 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1801 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
1802 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
1803 /* If refcount is 0, start releasing stuff that needs spinlock held */
1804 if (RefCount == 0)
1805 {
1806 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1807
1808 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1809
1810 /* If that's stop context from DO, remove it */
1811 RxDeviceObject = RxContext->RxDeviceObject;
1812 if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
1813 {
1814 RxDeviceObject->StartStopContext.pStopContext = NULL;
1815 }
1816 else
1817 {
1818 /* Remove it from the list */
1819 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
1820 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
1821 RemoveEntryList(&RxContext->ContextListEntry);
1822
1823 /* If that was the last active context, save the stop context */
1824 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
1825 {
1826 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
1827 {
1828 StopContext = RxDeviceObject->StartStopContext.pStopContext;
1829 }
1830 }
1831 }
1832 }
1833 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1834
1835 /* Now, deal with what can be done without spinlock held */
1836 if (RefCount == 0)
1837 {
1838 /* Refcount shouldn't have changed */
1839 ASSERT(RxContext->ReferenceCount == 0);
1840 /* Reset everything that can be */
1841 RxPrepareContextForReuse(RxContext);
1842
1843 #ifdef RDBSS_TRACKER
1844 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
1845 #endif
1846 /* If that was the last active, set the event */
1847 if (StopContext != NULL)
1848 {
1849 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
1850 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
1851 }
1852
1853 /* Is ShadowCrit still owned? Shouldn't happen! */
1854 if (RxContext->ShadowCritOwner != 0)
1855 {
1856 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
1857 ASSERT(FALSE);
1858 }
1859
1860 /* If it was allocated, free it */
1861 if (Allocated)
1862 {
1863 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
1864 }
1865 }
1866 }
1867
1868 /*
1869 * @implemented
1870 */
1871 NTSTATUS
1872 NTAPI
1873 RxDispatchToWorkerThread(
1874 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
1875 IN WORK_QUEUE_TYPE WorkQueueType,
1876 IN PRX_WORKERTHREAD_ROUTINE Routine,
1877 IN PVOID pContext)
1878 {
1879 NTSTATUS Status;
1880 PRX_WORK_DISPATCH_ITEM DispatchItem;
1881
1882 /* Allocate a bit of context */
1883 DispatchItem = ExAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
1884 if (DispatchItem == NULL)
1885 {
1886 return STATUS_INSUFFICIENT_RESOURCES;
1887 }
1888
1889 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1890 DispatchItem->DispatchRoutine = Routine;
1891 DispatchItem->DispatchRoutineParameter = pContext;
1892 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
1893 DispatchItem->WorkQueueItem.Parameter = DispatchItem;
1894
1895 /* Insert item */
1896 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, DispatchItem);
1897 if (!NT_SUCCESS(Status))
1898 {
1899 ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
1900 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
1901 }
1902
1903 DPRINT("Dispatching: %p, %p\n", Routine, pContext);
1904
1905 return Status;
1906 }
1907
1908 /*
1909 * @implemented
1910 */
1911 VOID
1912 RxExclusivePrefixTableLockToShared(
1913 PRX_PREFIX_TABLE Table)
1914 {
1915 PAGED_CODE();
1916
1917 ExConvertExclusiveToSharedLite(&Table->TableLock);
1918 }
1919
1920 /*
1921 * @implemented
1922 */
1923 VOID
1924 RxExtractServerName(
1925 IN PUNICODE_STRING FilePathName,
1926 OUT PUNICODE_STRING SrvCallName,
1927 OUT PUNICODE_STRING RestOfName)
1928 {
1929 USHORT i, Length;
1930
1931 PAGED_CODE();
1932
1933 ASSERT(SrvCallName != NULL);
1934
1935 /* SrvCall name will start from the begin up to the first separator */
1936 SrvCallName->Buffer = FilePathName->Buffer;
1937 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
1938 {
1939 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
1940 {
1941 break;
1942 }
1943 }
1944
1945 /* Compute length */
1946 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
1947 SrvCallName->MaximumLength = Length;
1948 SrvCallName->Length = Length;
1949
1950 /* Return the rest if asked */
1951 if (RestOfName != NULL)
1952 {
1953 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
1954 RestOfName->Buffer = &FilePathName->Buffer[i];
1955 RestOfName->MaximumLength = Length;
1956 RestOfName->Length = Length;
1957 }
1958 }
1959
1960 /*
1961 * @implemented
1962 */
1963 NTSTATUS
1964 RxFcbTableInsertFcb(
1965 IN OUT PRX_FCB_TABLE FcbTable,
1966 IN OUT PFCB Fcb)
1967 {
1968 PAGED_CODE();
1969
1970 /* We deal with the table, make sure it's locked */
1971 ASSERT(RxIsFcbTableLockExclusive(FcbTable));
1972
1973 /* Compute the hash */
1974 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
1975
1976 RxReferenceNetFcb(Fcb);
1977
1978 /* If no length, it will be our null entry */
1979 if (Fcb->FcbTableEntry.Path.Length == 0)
1980 {
1981 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
1982 }
1983 /* Otherwise, insert in the appropriate bucket */
1984 else
1985 {
1986 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
1987 &Fcb->FcbTableEntry.HashLinks);
1988 }
1989
1990 /* Propagate the change by incrementing the version number */
1991 InterlockedIncrement((volatile long *)&FcbTable->Version);
1992
1993 return STATUS_SUCCESS;
1994 }
1995
1996 /*
1997 * @implemented
1998 */
1999 PFCB
2000 RxFcbTableLookupFcb(
2001 IN PRX_FCB_TABLE FcbTable,
2002 IN PUNICODE_STRING Path)
2003 {
2004 PFCB Fcb;
2005 PRX_FCB_TABLE_ENTRY TableEntry;
2006
2007 PAGED_CODE();
2008
2009 /* No path - easy, that's null entry */
2010 if (Path == NULL)
2011 {
2012 TableEntry = FcbTable->TableEntryForNull;
2013 }
2014 else
2015 {
2016 ULONG Hash;
2017 PLIST_ENTRY HashBucket, ListEntry;
2018
2019 /* Otherwise, compute the hash value and find the associated bucket */
2020 Hash = RxTableComputePathHashValue(Path);
2021 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2022 /* If the bucket is empty, it means there's no entry yet */
2023 if (IsListEmpty(HashBucket))
2024 {
2025 TableEntry = NULL;
2026 }
2027 else
2028 {
2029 /* Otherwise, browse all the entry */
2030 for (ListEntry = HashBucket->Flink;
2031 ListEntry != HashBucket;
2032 ListEntry = ListEntry->Flink)
2033 {
2034 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2035 InterlockedIncrement(&FcbTable->Compares);
2036
2037 /* If entry hash and string are equal, thatt's the one! */
2038 if (TableEntry->HashValue == Hash &&
2039 TableEntry->Path.Length == Path->Length &&
2040 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2041 {
2042 break;
2043 }
2044 }
2045
2046 /* We reached the end? Not found */
2047 if (ListEntry == HashBucket)
2048 {
2049 TableEntry = NULL;
2050 }
2051 }
2052 }
2053
2054 InterlockedIncrement(&FcbTable->Lookups);
2055
2056 /* If table entry isn't null, return the FCB */
2057 if (TableEntry != NULL)
2058 {
2059 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2060 RxReferenceNetFcb(Fcb);
2061 }
2062 else
2063 {
2064 Fcb = NULL;
2065 InterlockedIncrement(&FcbTable->FailedLookups);
2066 }
2067
2068 return Fcb;
2069 }
2070
2071 /*
2072 * @implemented
2073 */
2074 NTSTATUS
2075 RxFcbTableRemoveFcb(
2076 IN OUT PRX_FCB_TABLE FcbTable,
2077 IN OUT PFCB Fcb)
2078 {
2079 PAGED_CODE();
2080
2081 ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2082
2083 /* If no path, then remove entry for null */
2084 if (Fcb->FcbTableEntry.Path.Length == 0)
2085 {
2086 FcbTable->TableEntryForNull = NULL;
2087 }
2088 /* Otherwise, remove from the bucket */
2089 else
2090 {
2091 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2092 }
2093
2094 /* Reset its list entry */
2095 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2096
2097 /* Propagate the change by incrementing the version number */
2098 InterlockedIncrement((volatile long *)&FcbTable->Version);
2099
2100 return STATUS_SUCCESS;
2101 }
2102
2103 /*
2104 * @implemented
2105 */
2106 BOOLEAN
2107 RxFinalizeNetFcb(
2108 OUT PFCB ThisFcb,
2109 IN BOOLEAN RecursiveFinalize,
2110 IN BOOLEAN ForceFinalize,
2111 IN LONG ReferenceCount)
2112 {
2113 PAGED_CODE();
2114
2115 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2116 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2117
2118 /* Make sure we have an exclusively acquired FCB */
2119 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2120 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2121
2122 /* We shouldn't force finalization... */
2123 ASSERT(!ForceFinalize);
2124
2125 /* If recurisve, finalize all the associated SRV_OPEN */
2126 if (RecursiveFinalize)
2127 {
2128 PLIST_ENTRY ListEntry;
2129
2130 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2131 ListEntry != &ThisFcb->SrvOpenList;
2132 ListEntry = ListEntry->Flink)
2133 {
2134 PSRV_OPEN SrvOpen;
2135
2136 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2137 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2138 }
2139 }
2140 /* If FCB is still in use, that's over */
2141 else
2142 {
2143 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2144 {
2145 ASSERT(ReferenceCount > 0);
2146
2147 return FALSE;
2148 }
2149 }
2150
2151 ASSERT(ReferenceCount >= 1);
2152
2153 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2154 if (ReferenceCount != 1 && !ForceFinalize)
2155 {
2156 return FALSE;
2157 }
2158
2159 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2160
2161 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
2162
2163 /* If finalization was not already initiated, go ahead */
2164 if (!ThisFcb->UpperFinalizationDone)
2165 {
2166 /* Free any FCB_LOCK */
2167 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2168 {
2169 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2170
2171 while (ThisFcb->BufferedLocks.List != NULL)
2172 {
2173 PFCB_LOCK Entry;
2174
2175 Entry = ThisFcb->BufferedLocks.List;
2176 ThisFcb->BufferedLocks.List = Entry->Next;
2177
2178 ExFreePool(Entry);
2179 }
2180 }
2181
2182 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2183 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2184 {
2185 PNET_ROOT NetRoot;
2186
2187 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2188
2189 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2190 /* So, remove it */
2191 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2192 {
2193 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2194 }
2195 }
2196
2197 ThisFcb->UpperFinalizationDone = TRUE;
2198 }
2199
2200 ASSERT(ReferenceCount >= 1);
2201
2202 /* Even if forced, don't allow broken free */
2203 if (ReferenceCount != 1)
2204 {
2205 return FALSE;
2206 }
2207
2208 /* Now, release everything */
2209 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2210 {
2211 ExFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2212 }
2213
2214 if (ThisFcb->MRxDispatch != NULL)
2215 {
2216 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2217 }
2218
2219 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2220 ExDeleteResourceLite(ThisFcb->Header.Resource);
2221 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2222
2223 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2224 RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
2225
2226 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2227 ASSERT(!ThisFcb->fMiniInited);
2228
2229 /* And free the object */
2230 RxFreeFcbObject(ThisFcb);
2231
2232 return TRUE;
2233 }
2234
2235 BOOLEAN
2236 RxFinalizeNetRoot(
2237 OUT PNET_ROOT ThisNetRoot,
2238 IN BOOLEAN RecursiveFinalize,
2239 IN BOOLEAN ForceFinalize
2240 )
2241 {
2242 UNIMPLEMENTED;
2243 return FALSE;
2244 }
2245
2246 BOOLEAN
2247 RxFinalizeSrvCall(
2248 OUT PSRV_CALL ThisSrvCall,
2249 IN BOOLEAN RecursiveFinalize,
2250 IN BOOLEAN ForceFinalize)
2251 {
2252 UNIMPLEMENTED;
2253 return FALSE;
2254 }
2255
2256 BOOLEAN
2257 RxFinalizeSrvOpen(
2258 OUT PSRV_OPEN ThisSrvOpen,
2259 IN BOOLEAN RecursiveFinalize,
2260 IN BOOLEAN ForceFinalize)
2261 {
2262 UNIMPLEMENTED;
2263 return FALSE;
2264 }
2265
2266 NTSTATUS
2267 RxFindOrConstructVirtualNetRoot(
2268 IN PRX_CONTEXT RxContext,
2269 IN PUNICODE_STRING CanonicalName,
2270 IN NET_ROOT_TYPE NetRootType,
2271 IN PUNICODE_STRING RemainingName)
2272 {
2273 ULONG Flags;
2274 NTSTATUS Status;
2275 PVOID Container;
2276 BOOLEAN Construct;
2277 PV_NET_ROOT VNetRoot;
2278 RX_CONNECTION_ID ConnectionID;
2279 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2280 LOCK_HOLDING_STATE LockHoldingState;
2281
2282 PAGED_CODE();
2283
2284 RxDeviceObject = RxContext->RxDeviceObject;
2285 ASSERT(RxDeviceObject->Dispatch != NULL);
2286 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
2287
2288 /* Ask the mini-rdr for connection ID */
2289 ConnectionID.SessionID = 0;
2290 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
2291 {
2292 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
2293 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
2294 {
2295 /* mini-rdr is expected not to fail - unless it's not implemented */
2296 DPRINT1("Failed to initialize connection ID\n");
2297 ASSERT(FALSE);
2298 }
2299 }
2300
2301 RxContext->Create.NetNamePrefixEntry = NULL;
2302
2303 Status = STATUS_MORE_PROCESSING_REQUIRED;
2304 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
2305 LockHoldingState = LHS_SharedLockHeld;
2306 Construct = TRUE;
2307 Flags = 0;
2308
2309 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2310 while (TRUE)
2311 {
2312 PNET_ROOT NetRoot;
2313 PV_NET_ROOT SavedVNetRoot;
2314
2315 /* Look in prefix table */
2316 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
2317 if (Container != NULL)
2318 {
2319 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2320 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
2321 {
2322 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2323 RxDereferenceSrvCall(Container, LockHoldingState);
2324 }
2325 else
2326 {
2327 VNetRoot = Container;
2328 NetRoot = VNetRoot->NetRoot;
2329
2330 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2331 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
2332 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2333 {
2334 Status = STATUS_BAD_NETWORK_PATH;
2335 SavedVNetRoot = NULL;
2336 }
2337 else
2338 {
2339 LUID LogonId;
2340 ULONG SessionId;
2341 PUNICODE_STRING UserName, UserDomain, Password;
2342
2343 /* We can reuse if we use same credentials */
2344 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
2345 &SessionId, &UserName,
2346 &UserDomain, &Password,
2347 &Flags);
2348 if (NT_SUCCESS(Status))
2349 {
2350 SavedVNetRoot = VNetRoot;
2351 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
2352 &LogonId, UserName,
2353 UserDomain, Password,
2354 Flags);
2355 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
2356 {
2357 PLIST_ENTRY ListEntry;
2358
2359 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
2360 ListEntry != &NetRoot->VirtualNetRoots;
2361 ListEntry = ListEntry->Flink)
2362 {
2363 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
2364 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
2365 &LogonId, UserName,
2366 UserDomain, Password,
2367 Flags);
2368 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2369 {
2370 break;
2371 }
2372 }
2373
2374 if (ListEntry == &NetRoot->VirtualNetRoots)
2375 {
2376 SavedVNetRoot = NULL;
2377 }
2378 }
2379
2380 if (!NT_SUCCESS(Status))
2381 {
2382 SavedVNetRoot = NULL;
2383 }
2384
2385 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
2386 }
2387 }
2388
2389 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2390 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
2391 {
2392 if (SavedVNetRoot == NULL)
2393 {
2394 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2395 }
2396 }
2397 /* Reference VNetRoot we'll keep, and dereference current */
2398 else if (SavedVNetRoot != VNetRoot)
2399 {
2400 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
2401 if (SavedVNetRoot != NULL)
2402 {
2403 RxReferenceVNetRoot(SavedVNetRoot);
2404 }
2405 }
2406 }
2407
2408 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2409 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2410 {
2411 Construct = FALSE;
2412 break;
2413 }
2414 }
2415
2416 /* If we're locked exclusive, we won't loop again, it was the second pass */
2417 if (LockHoldingState != LHS_SharedLockHeld)
2418 {
2419 break;
2420 }
2421
2422 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2423 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
2424 {
2425 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2426 LockHoldingState = LHS_ExclusiveLockHeld;
2427 break;
2428 }
2429
2430 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2431 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
2432 LockHoldingState = LHS_ExclusiveLockHeld;
2433 }
2434
2435 /* We didn't fail, and didn't find any VNetRoot, construct one */
2436 if (Construct)
2437 {
2438 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
2439
2440 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
2441 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
2442
2443 if (Status == STATUS_SUCCESS)
2444 {
2445 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
2446 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
2447 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
2448
2449 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2450 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
2451 RemainingName->MaximumLength = RemainingName->Length;
2452
2453 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
2454 {
2455 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
2456 }
2457 VNetRoot->Flags |= Flags;
2458 }
2459 }
2460
2461 /* Release the prefix table - caller expects it to be released */
2462 if (LockHoldingState != LHS_LockNotHeld)
2463 {
2464 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
2465 }
2466
2467 /* If we failed creating, quit */
2468 if (Status != STATUS_SUCCESS)
2469 {
2470 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
2471 return Status;
2472 }
2473
2474 /* Otherwise, wait until the VNetRoot is stable */
2475 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
2476 RxWaitForStableVNetRoot(VNetRoot, RxContext);
2477 /* It's all good, update the RX_CONTEXT with all our structs */
2478 if (VNetRoot->Condition == Condition_Good)
2479 {
2480 PNET_ROOT NetRoot;
2481
2482 NetRoot = VNetRoot->NetRoot;
2483 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2484 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2485 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
2486 }
2487 else
2488 {
2489 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2490 RxContext->Create.pVNetRoot = NULL;
2491 Status = STATUS_BAD_NETWORK_PATH;
2492 }
2493
2494 return Status;
2495 }
2496
2497 /*
2498 * @implemented
2499 */
2500 NTSTATUS
2501 RxFindOrCreateConnections(
2502 _In_ PRX_CONTEXT RxContext,
2503 _In_ PUNICODE_STRING CanonicalName,
2504 _In_ NET_ROOT_TYPE NetRootType,
2505 _Out_ PUNICODE_STRING LocalNetRootName,
2506 _Out_ PUNICODE_STRING FilePathName,
2507 _Inout_ PLOCK_HOLDING_STATE LockState,
2508 _In_ PRX_CONNECTION_ID RxConnectionId)
2509 {
2510 PVOID Container;
2511 PSRV_CALL SrvCall;
2512 PNET_ROOT NetRoot;
2513 PV_NET_ROOT VNetRoot;
2514 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2515 PRX_PREFIX_TABLE PrefixTable;
2516 UNICODE_STRING RemainingName, NetRootName;
2517
2518 PAGED_CODE();
2519
2520 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2521 RxContext, CanonicalName, NetRootType, LocalNetRootName,
2522 FilePathName, LockState, RxConnectionId);
2523
2524 *FilePathName = *CanonicalName;
2525 LocalNetRootName->Length = 0;
2526 LocalNetRootName->MaximumLength = 0;
2527 LocalNetRootName->Buffer = CanonicalName->Buffer;
2528
2529 /* UNC path, split it */
2530 if (FilePathName->Buffer[1] == ';')
2531 {
2532 BOOLEAN Slash;
2533 USHORT i, Length;
2534
2535 Slash = FALSE;
2536 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
2537 {
2538 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2539 {
2540 Slash = TRUE;
2541 break;
2542 }
2543 }
2544
2545 if (!Slash)
2546 {
2547 return STATUS_OBJECT_NAME_INVALID;
2548 }
2549
2550 FilePathName->Buffer = &FilePathName->Buffer[i];
2551 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
2552 LocalNetRootName->Length = Length;
2553 LocalNetRootName->MaximumLength = Length;
2554 FilePathName->Length -= Length;
2555
2556 DPRINT("CanonicalName: %wZ\n", CanonicalName);
2557 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
2558 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
2559 }
2560
2561 Container = NULL;
2562 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
2563
2564 _SEH2_TRY
2565 {
2566 RetryLookup:
2567 ASSERT(*LockState != LHS_LockNotHeld);
2568
2569 /* If previous lookup left something, dereference it */
2570 if (Container != NULL)
2571 {
2572 switch (NodeType(Container))
2573 {
2574 case RDBSS_NTC_SRVCALL:
2575 RxDereferenceSrvCall(Container, *LockState);
2576 break;
2577
2578 case RDBSS_NTC_NETROOT:
2579 RxDereferenceNetRoot(Container, *LockState);
2580 break;
2581
2582 case RDBSS_NTC_V_NETROOT:
2583 RxDereferenceVNetRoot(Container, *LockState);
2584 break;
2585
2586 default:
2587 /* Should never happen */
2588 ASSERT(FALSE);
2589 break;
2590 }
2591 }
2592
2593 /* Look for our NetRoot in prefix table */
2594 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
2595 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
2596
2597 while (TRUE)
2598 {
2599 UNICODE_STRING SrvCallName;
2600
2601 SrvCall = NULL;
2602 NetRoot = NULL;
2603 VNetRoot = NULL;
2604
2605 /* Assume we didn't succeed */
2606 RxContext->Create.pVNetRoot = NULL;
2607 RxContext->Create.pNetRoot = NULL;
2608 RxContext->Create.pSrvCall = NULL;
2609 RxContext->Create.Type = NetRootType;
2610
2611 /* If we found something */
2612 if (Container != NULL)
2613 {
2614 /* A VNetRoot */
2615 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
2616 {
2617 VNetRoot = Container;
2618 /* Use its NetRoot */
2619 NetRoot = VNetRoot->NetRoot;
2620
2621 /* If it's not stable, wait for it to be stable */
2622 if (NetRoot->Condition == Condition_InTransition)
2623 {
2624 RxReleasePrefixTableLock(PrefixTable);
2625 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
2626 RxWaitForStableNetRoot(NetRoot, RxContext);
2627 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2628 *LockState = LHS_ExclusiveLockHeld;
2629
2630 /* Now that's it's ok, retry lookup to find what we want */
2631 if (NetRoot->Condition == Condition_Good)
2632 {
2633 goto RetryLookup;
2634 }
2635 }
2636
2637 /* Is the associated netroot good? */
2638 if (NetRoot->Condition == Condition_Good)
2639 {
2640 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
2641
2642 /* If it is, and SrvCall as well, then, we have our active connection */
2643 if (SrvCall->Condition == Condition_Good &&
2644 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
2645 {
2646 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2647 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2648 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2649
2650 Status = STATUS_CONNECTION_ACTIVE;
2651 _SEH2_LEAVE;
2652 }
2653 }
2654
2655 /* If VNetRoot was well constructed, it means the connection is active */
2656 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
2657 {
2658 Status = STATUS_CONNECTION_ACTIVE;
2659 }
2660 else
2661 {
2662 Status = VNetRoot->ConstructionStatus;
2663 }
2664
2665 RxDereferenceVNetRoot(VNetRoot, *LockState);
2666 _SEH2_LEAVE;
2667 }
2668 /* Can only be a SrvCall */
2669 else
2670 {
2671 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
2672 SrvCall = Container;
2673
2674 /* Wait for the SRV_CALL to be stable */
2675 if (SrvCall->Condition == Condition_InTransition)
2676 {
2677 RxReleasePrefixTableLock(PrefixTable);
2678 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
2679 RxWaitForStableSrvCall(SrvCall, RxContext);
2680 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2681 *LockState = LHS_ExclusiveLockHeld;
2682
2683 /* It went good, loop again to find what we look for */
2684 if (SrvCall->Condition == Condition_Good)
2685 {
2686 goto RetryLookup;
2687 }
2688 }
2689
2690 /* If it's not good... */
2691 if (SrvCall->Condition != Condition_Good)
2692 {
2693 /* But SRV_CALL was well constructed, assume a connection was active */
2694 if (SrvCall->Status == STATUS_SUCCESS)
2695 {
2696 Status = STATUS_CONNECTION_ACTIVE;
2697 }
2698 else
2699 {
2700 Status = SrvCall->Status;
2701 }
2702
2703 RxDereferenceSrvCall(SrvCall, *LockState);
2704 _SEH2_LEAVE;
2705 }
2706 }
2707 }
2708
2709 /* If we found a SRV_CALL not matching our DO, quit */
2710 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
2711 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
2712 {
2713 RxDereferenceSrvCall(SrvCall, *LockState);
2714 Status = STATUS_BAD_NETWORK_NAME;
2715 _SEH2_LEAVE;
2716 }
2717
2718 /* Now, we want exclusive lock */
2719 if (*LockState == LHS_SharedLockHeld)
2720 {
2721 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
2722 {
2723 RxReleasePrefixTableLock(PrefixTable);
2724 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2725 *LockState = LHS_ExclusiveLockHeld;
2726 goto RetryLookup;
2727 }
2728
2729 RxReleasePrefixTableLock(PrefixTable);
2730 *LockState = LHS_ExclusiveLockHeld;
2731 }
2732
2733 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2734
2735 /* If we reach that point, we found something, no need to create something */
2736 if (Container != NULL)
2737 {
2738 break;
2739 }
2740
2741 /* Get the name for the SRV_CALL */
2742 RxExtractServerName(FilePathName, &SrvCallName, NULL);
2743 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
2744 /* And create the SRV_CALL */
2745 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
2746 if (SrvCall == NULL)
2747 {
2748 Status = STATUS_INSUFFICIENT_RESOURCES;
2749 _SEH2_LEAVE;
2750 }
2751
2752 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2753 RxReferenceSrvCall(SrvCall);
2754 RxContext->Create.pVNetRoot = NULL;
2755 RxContext->Create.pNetRoot = NULL;
2756 RxContext->Create.pSrvCall = NULL;
2757 RxContext->Create.Type = NetRootType;
2758 Container = SrvCall;
2759
2760 /* Construct SRV_CALL, ie, use mini-rdr */
2761 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
2762 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
2763 if (Status != STATUS_SUCCESS)
2764 {
2765 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
2766 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2767 RxDereferenceSrvCall(SrvCall, *LockState);
2768 RxReleasePrefixTableLock(PrefixTable);
2769 _SEH2_LEAVE;
2770 }
2771
2772 /* Loop again to make use of SRV_CALL stable condition wait */
2773 }
2774
2775 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2776 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
2777 ASSERT(NetRoot == NULL && VNetRoot == NULL);
2778 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
2779
2780 /* Call mini-rdr to get NetRoot name */
2781 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
2782 /* And create the NetRoot with that name */
2783 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
2784 if (NetRoot == NULL)
2785 {
2786 Status = STATUS_INSUFFICIENT_RESOURCES;
2787 _SEH2_LEAVE;
2788 }
2789 NetRoot->Type = NetRootType;
2790
2791 RxDereferenceSrvCall(SrvCall, *LockState);
2792
2793 /* Finally, create the associated VNetRoot */
2794 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
2795 if (VNetRoot == NULL)
2796 {
2797 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2798 Status = STATUS_INSUFFICIENT_RESOURCES;
2799 _SEH2_LEAVE;
2800 }
2801 RxReferenceVNetRoot(VNetRoot);
2802
2803 /* We're get closer! */
2804 NetRoot->Condition = Condition_InTransition;
2805 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
2806 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
2807 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2808
2809 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2810 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
2811 if (!NT_SUCCESS(Status))
2812 {
2813 RxTransitionVNetRoot(VNetRoot, Condition_Bad);
2814 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
2815 RxDereferenceVNetRoot(VNetRoot, *LockState);
2816
2817 RxContext->Create.pNetRoot = NULL;
2818 RxContext->Create.pVNetRoot = NULL;
2819 }
2820 else
2821 {
2822 PIO_STACK_LOCATION Stack;
2823
2824 ASSERT(*LockState == LHS_ExclusiveLockHeld);
2825
2826 Stack = RxContext->CurrentIrpSp;
2827 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2828 {
2829 RxExclusivePrefixTableLockToShared(PrefixTable);
2830 *LockState = LHS_SharedLockHeld;
2831 }
2832 }
2833 }
2834 _SEH2_FINALLY
2835 {
2836 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
2837 {
2838 if (*LockState != LHS_LockNotHeld)
2839 {
2840 RxReleasePrefixTableLock(PrefixTable);
2841 *LockState = LHS_LockNotHeld;
2842 }
2843 }
2844 }
2845 _SEH2_END;
2846
2847 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
2848 return Status;
2849 }
2850
2851 /*
2852 * @implemented
2853 */
2854 VOID
2855 NTAPI
2856 RxFinishFcbInitialization(
2857 IN OUT PMRX_FCB Fcb,
2858 IN RX_FILE_TYPE FileType,
2859 IN PFCB_INIT_PACKET InitPacket OPTIONAL)
2860 {
2861 NODE_TYPE_CODE OldType;
2862
2863 PAGED_CODE();
2864
2865 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
2866
2867 OldType = Fcb->Header.NodeTypeCode;
2868 Fcb->Header.NodeTypeCode = FileType;
2869 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2870 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
2871 {
2872 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2873 }
2874 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2875 else if (InitPacket != NULL)
2876 {
2877 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
2878 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
2879 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
2880 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
2881 InitPacket->pValidDataLength->QuadPart);
2882 }
2883
2884 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2885 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2886 {
2887 /* If our FCB newly points to a file, initiliaz everything related */
2888 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
2889 !OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
2890 {
2891 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
2892 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
2893 &RxUnlockOperation);
2894
2895 ((PFCB)Fcb)->BufferedLocks.List = NULL;
2896 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
2897
2898 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
2899 }
2900 else
2901 {
2902 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
2903 }
2904 }
2905 }
2906
2907 /*
2908 * @implemented
2909 */
2910 NTSTATUS
2911 RxFinishSrvCallConstruction(
2912 PMRX_SRVCALLDOWN_STRUCTURE Calldown)
2913 {
2914 NTSTATUS Status;
2915 PSRV_CALL SrvCall;
2916 PRX_CONTEXT Context;
2917 RX_BLOCK_CONDITION Condition;
2918 PRX_PREFIX_TABLE PrefixTable;
2919
2920 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
2921
2922 SrvCall = (PSRV_CALL)Calldown->SrvCall;
2923 Context = Calldown->RxContext;
2924 PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
2925
2926 /* We have a winner, notify him */
2927 if (Calldown->BestFinisher != NULL)
2928 {
2929 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
2930
2931 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
2932
2933 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
2934 MRxSrvCallWinnerNotify,
2935 ((PMRX_SRV_CALL)SrvCall, TRUE,
2936 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
2937 if (Status != STATUS_SUCCESS)
2938 {
2939 Condition = Condition_Bad;
2940 }
2941 else
2942 {
2943 Condition = Condition_Good;
2944 }
2945 }
2946 /* Otherwise, just fail our SRV_CALL */
2947 else
2948 {
2949 Status = Calldown->CallbackContexts[0].Status;
2950 Condition = Condition_Bad;
2951 }
2952
2953 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2954 RxTransitionSrvCall(SrvCall, Condition);
2955 ExFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
2956
2957 /* If async, finish it here, otherwise, caller has already finished the stuff */
2958 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
2959 {
2960 DPRINT("Finishing async call\n");
2961
2962 RxReleasePrefixTableLock(PrefixTable);
2963
2964 /* Make sure we weren't cancelled in-between */
2965 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
2966 {
2967 Status = STATUS_CANCELLED;
2968 }
2969
2970 /* In case that was a create, context can be reused */
2971 if (Context->MajorFunction == IRP_MJ_CREATE)
2972 {
2973 RxpPrepareCreateContextForReuse(Context);
2974 }
2975
2976 /* If that's a failure, reset everything and return failure */
2977 if (Status != STATUS_SUCCESS)
2978 {
2979 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
2980 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
2981 {
2982 if (Context->Info.Buffer != NULL)
2983 {
2984 ExFreePool(Context->Info.Buffer);
2985 Context->Info.Buffer = NULL;
2986 }
2987 }
2988 Context->CurrentIrp->IoStatus.Information = 0;
2989 Context->CurrentIrp->IoStatus.Status = Status;
2990 RxCompleteRequest(Context, Status);
2991 }
2992 /* Otherwise, call resume routine and done! */
2993 else
2994 {
2995 Status = Context->ResumeRoutine(Context);
2996 if (Status != STATUS_PENDING)
2997 {
2998 RxCompleteRequest(Context, Status);
2999 }
3000
3001 DPRINT("Not completing, pending\n");
3002 }
3003 }
3004
3005 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
3006 return Status;
3007 }
3008
3009 /*
3010 * @implemented
3011 */
3012 VOID
3013 NTAPI
3014 RxFinishSrvCallConstructionDispatcher(
3015 IN PVOID Context)
3016 {
3017 KIRQL OldIrql;
3018 BOOLEAN Direct, KeepLoop;
3019
3020 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
3021
3022 /* In case of failure of starting dispatcher, context is not set
3023 * We keep track of it to fail associated SRV_CALL
3024 */
3025 Direct = (Context == NULL);
3026
3027 /* Separated thread, loop forever */
3028 while (TRUE)
3029 {
3030 PLIST_ENTRY ListEntry;
3031 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
3032
3033 /* If there are no SRV_CALL to finalize left, just finish thread */
3034 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
3035 if (IsListEmpty(&RxSrvCalldownList))
3036 {
3037 KeepLoop = FALSE;
3038 RxSrvCallConstructionDispatcherActive = FALSE;
3039 }
3040 /* Otherwise, get the SRV_CALL to finish construction */
3041 else
3042 {
3043 ListEntry = RemoveHeadList(&RxSrvCalldownList);
3044 KeepLoop = TRUE;
3045 }
3046 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
3047
3048 /* Nothing to do */
3049 if (!KeepLoop)
3050 {
3051 break;
3052 }
3053
3054 /* If direct is set, reset the finisher to avoid electing a winner
3055 * and fail SRV_CALL (see upper comment)
3056 */
3057 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
3058 if (Direct)
3059 {
3060 Calldown->BestFinisher = NULL;
3061 }
3062 /* Finish SRV_CALL construction */
3063 RxFinishSrvCallConstruction(Calldown);
3064 }
3065 }
3066
3067 VOID
3068 RxFreeFcbObject(
3069 PVOID Object)
3070 {
3071 UNIMPLEMENTED;
3072 }
3073
3074 VOID
3075 RxFreeObject(
3076 PVOID pObject)
3077 {
3078 UNIMPLEMENTED;
3079 }
3080
3081 /*
3082 * @implemented
3083 */
3084 VOID
3085 RxGetFileSizeWithLock(
3086 IN PFCB Fcb,
3087 OUT PLONGLONG FileSize)
3088 {
3089 PAGED_CODE();
3090
3091 *FileSize = Fcb->Header.FileSize.QuadPart;
3092 }
3093
3094 /*
3095 * @implemented
3096 */
3097 PEPROCESS
3098 NTAPI
3099 RxGetRDBSSProcess(
3100 VOID)
3101 {
3102 return RxData.OurProcess;
3103 }
3104
3105 /*
3106 * @implemented
3107 */
3108 NTSTATUS
3109 RxInitializeBufferingManager(
3110 PSRV_CALL SrvCall)
3111 {
3112 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
3113 InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
3114 InitializeListHead(&SrvCall->BufferingManager.HandlerList);
3115 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
3116 SrvCall->BufferingManager.DispatcherActive = FALSE;
3117 SrvCall->BufferingManager.HandlerInactive = FALSE;
3118 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
3119 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
3120 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
3121 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
3122
3123 return STATUS_SUCCESS;
3124 }
3125
3126 /*
3127 * @implemented
3128 */
3129 VOID
3130 NTAPI
3131 RxInitializeContext(
3132 IN PIRP Irp,
3133 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
3134 IN ULONG InitialContextFlags,
3135 IN OUT PRX_CONTEXT RxContext)
3136 {
3137 PIO_STACK_LOCATION Stack;
3138
3139 /* Initialize our various fields */
3140 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
3141 RxContext->NodeByteSize = sizeof(RX_CONTEXT);
3142 RxContext->ReferenceCount = 1;
3143 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
3144 RxContext->RxDeviceObject = RxDeviceObject;
3145 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
3146 RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
3147 InitializeListHead(&RxContext->BlockedOperations);
3148 RxContext->MRxCancelRoutine = NULL;
3149 RxContext->ResumeRoutine = NULL;
3150 RxContext->Flags |= InitialContextFlags;
3151 RxContext->CurrentIrp = Irp;
3152 RxContext->LastExecutionThread = PsGetCurrentThread();
3153 RxContext->OriginalThread = RxContext->LastExecutionThread;
3154
3155 /* If've got no IRP, mark RX_CONTEXT */
3156 if (Irp == NULL)
3157 {
3158 RxContext->CurrentIrpSp = NULL;
3159 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
3160 RxContext->MinorFunction = 0;
3161 }
3162 else
3163 {
3164 /* Otherwise, first determine whether we are performing async operation */
3165 Stack = IoGetCurrentIrpStackLocation(Irp);
3166 if (Stack->FileObject != NULL)
3167 {
3168 PFCB Fcb;
3169
3170 Fcb = Stack->FileObject->FsContext;
3171 if (!IoIsOperationSynchronous(Irp) ||
3172 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
3173 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
3174 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
3175 {
3176 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3177 }
3178 }
3179
3180 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
3181 {
3182 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3183 }
3184 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
3185 {
3186 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
3187 }
3188
3189 /* Set proper flags if TopLevl IRP/Device */
3190 if (!RxIsThisTheTopLevelIrp(Irp))
3191 {
3192 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
3193 }
3194 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
3195 {
3196 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
3197 }
3198
3199 /* Copy stack information */
3200 RxContext->MajorFunction = Stack->MajorFunction;
3201 RxContext->MinorFunction = Stack->MinorFunction;
3202 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
3203 RxContext->CurrentIrpSp = Stack;
3204
3205 /* If we have a FO associated, learn for more */
3206 if (Stack->FileObject != NULL)
3207 {
3208 PFCB Fcb;
3209 PFOBX Fobx;
3210
3211 /* Get the FCB and CCB (FOBX) */
3212 Fcb = Stack->FileObject->FsContext;
3213 Fobx = Stack->FileObject->FsContext2;
3214 RxContext->pFcb = (PMRX_FCB)Fcb;
3215 if (Fcb != NULL && NodeTypeIsFcb(Fcb))
3216 {
3217 RxContext->NonPagedFcb = Fcb->NonPaged;
3218 }
3219
3220 /* We have a FOBX, this not a DFS opening, keep track of it */
3221 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
3222 {
3223 RxContext->pFobx = (PMRX_FOBX)Fobx;
3224 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
3225 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3226 {
3227 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
3228 }
3229 }
3230 else
3231 {
3232 RxContext->pFobx = NULL;
3233 }
3234
3235 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3236 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
3237 Fobx != NULL)
3238 {
3239 PV_NET_ROOT VNetRoot = NULL;
3240
3241 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
3242 {
3243 VNetRoot = Fcb->VNetRoot;
3244 }
3245 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
3246 {
3247 VNetRoot = (PV_NET_ROOT)Fobx;
3248 }
3249
3250 if (VNetRoot != NULL)
3251 {
3252 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3253 }
3254 }
3255
3256 /* Remember if that's a write through file */
3257 RxContext->RealDevice = Stack->FileObject->DeviceObject;
3258 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
3259 {
3260 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
3261 }
3262 }
3263 }
3264
3265 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
3266 {
3267 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3268 RxContext, RxContext->MinorFunction, Irp,
3269 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
3270 RxContext->SerialNumber);
3271 }
3272 }
3273
3274 /*
3275 * @implemented
3276 */
3277 NTSTATUS
3278 NTAPI
3279 RxInitializeDispatcher(
3280 VOID)
3281 {
3282 NTSTATUS Status;
3283 HANDLE ThreadHandle;
3284
3285 PAGED_CODE();
3286
3287 RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
3288 RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
3289
3290 /* Set appropriate timeouts: 10s & 60s */
3291 RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3292 RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3293 RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
3294 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
3295
3296 RxDispatcher.NumberOfProcessors = 1;
3297 RxDispatcher.OwnerProcess = IoGetCurrentProcess();
3298 RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
3299
3300 /* Initialize our dispatchers */
3301 Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
3302 if (!NT_SUCCESS(Status))
3303 {
3304 return Status;
3305 }
3306
3307 Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
3308 if (!NT_SUCCESS(Status))
3309 {
3310 return Status;
3311 }
3312
3313 /* And start them */
3314 RxDispatcher.State = RxDispatcherActive;
3315 InitializeListHead(&RxDispatcher.SpinUpRequests);
3316 KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
3317 KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
3318 KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
3319 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
3320 NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
3321 if (NT_SUCCESS(Status))
3322 {
3323 ZwClose(ThreadHandle);
3324 }
3325
3326 return Status;
3327 }
3328
3329 /*
3330 * @implemented
3331 */
3332 VOID
3333 RxInitializeFcbTable(
3334 IN OUT PRX_FCB_TABLE FcbTable,
3335 IN BOOLEAN CaseInsensitiveMatch)
3336 {
3337 USHORT i;
3338
3339 PAGED_CODE();
3340
3341 FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
3342 FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
3343
3344 ExInitializeResourceLite(&FcbTable->TableLock);
3345 FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
3346 FcbTable->Version = 0;
3347 FcbTable->TableEntryForNull = NULL;
3348
3349 FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
3350 for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
3351 {
3352 InitializeListHead(&FcbTable->HashBuckets[i]);
3353 }
3354
3355 FcbTable->Lookups = 0;
3356 FcbTable->FailedLookups = 0;
3357 FcbTable->Compares = 0;
3358 }
3359
3360 /*
3361 * @implemented
3362 */
3363 VOID
3364 NTAPI
3365 RxInitializeLowIoContext(
3366 OUT PLOWIO_CONTEXT LowIoContext,
3367 IN ULONG Operation)
3368 {
3369 PRX_CONTEXT RxContext;
3370 PIO_STACK_LOCATION Stack;
3371
3372 PAGED_CODE();
3373
3374 RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
3375 ASSERT(LowIoContext = &RxContext->LowIoContext);
3376
3377 Stack = RxContext->CurrentIrpSp;
3378
3379 KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
3380 RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
3381 RxContext->LowIoContext.Operation = Operation;
3382
3383 switch (Operation)
3384 {
3385 case LOWIO_OP_READ:
3386 case LOWIO_OP_WRITE:
3387 /* In case of RW, set a canary, to make sure these fields are properly set
3388 * they will be asserted when lowio request will be submit to mini-rdr
3389 * See LowIoSubmit()
3390 */
3391 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
3392 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
3393 RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
3394
3395 /* Keep track of paging IOs */
3396 if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
3397 {
3398 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
3399 }
3400 else
3401 {
3402 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
3403 }
3404
3405 break;
3406
3407 case LOWIO_OP_FSCTL:
3408 case LOWIO_OP_IOCTL:
3409 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
3410 RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
3411 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
3412 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
3413 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
3414 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
3415 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
3416 break;
3417
3418 /* Nothing to do for these */
3419 case LOWIO_OP_SHAREDLOCK:
3420 case LOWIO_OP_EXCLUSIVELOCK:
3421 case LOWIO_OP_UNLOCK:
3422 case LOWIO_OP_UNLOCK_MULTIPLE:
3423 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
3424 case LOWIO_OP_CLEAROUT:
3425 break;
3426
3427 default:
3428 /* Should never happen */
3429 ASSERT(FALSE);
3430 break;
3431 }
3432 }
3433
3434 /*
3435 * @implemented
3436 */
3437 VOID
3438 RxInitializeLowIoPerFcbInfo(
3439 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
3440 {
3441 PAGED_CODE();
3442
3443 InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
3444 InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
3445 }
3446
3447 /*
3448 * @implemented
3449 */
3450 NTSTATUS
3451 RxInitializeMRxDispatcher(
3452 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
3453 {
3454 PAGED_CODE();
3455
3456 pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
3457 pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
3458
3459 return STATUS_SUCCESS;
3460 }
3461
3462 /*
3463 * @implemented
3464 */
3465 VOID
3466 RxInitializePrefixTable(
3467 IN OUT PRX_PREFIX_TABLE ThisTable,
3468 IN ULONG TableSize OPTIONAL,
3469 IN BOOLEAN CaseInsensitiveMatch)
3470 {
3471 PAGED_CODE();
3472
3473 if (TableSize == 0)
3474 {
3475 TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
3476 }
3477
3478 ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
3479 ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
3480 InitializeListHead(&ThisTable->MemberQueue);
3481 ThisTable->Version = 0;
3482 ThisTable->TableEntryForNull = NULL;
3483 ThisTable->IsNetNameTable = FALSE;
3484 ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
3485 ThisTable->TableSize = TableSize;
3486
3487 if (TableSize > 0)
3488 {
3489 USHORT i;
3490
3491 for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
3492 {
3493 InitializeListHead(&ThisTable->HashBuckets[i]);
3494 }
3495 }
3496 }
3497
3498 /*
3499 * @implemented
3500 */
3501 VOID
3502 RxInitializePurgeSyncronizationContext(
3503 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
3504 {
3505 PAGED_CODE();
3506
3507 InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
3508 PurgeSyncronizationContext->PurgeInProgress = FALSE;
3509 }
3510
3511 NTSTATUS
3512 RxInitializeSrvCallParameters(
3513 IN PRX_CONTEXT RxContext,
3514 IN OUT PSRV_CALL SrvCall)
3515 {
3516 PAGED_CODE();
3517
3518 SrvCall->pPrincipalName = NULL;
3519
3520 /* We only have stuff to initialize for file opening from DFS */
3521 if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
3522 {
3523 return STATUS_SUCCESS;
3524 }
3525
3526 ASSERT(RxContext->Create.EaBuffer != NULL);
3527
3528 UNIMPLEMENTED;
3529 return STATUS_NOT_IMPLEMENTED;
3530 }
3531
3532 NTSTATUS
3533 RxInitializeVNetRootParameters(
3534 PRX_CONTEXT RxContext,
3535 OUT LUID *LogonId,
3536 OUT PULONG SessionId,
3537 OUT PUNICODE_STRING *UserNamePtr,
3538 OUT PUNICODE_STRING *UserDomainNamePtr,
3539 OUT PUNICODE_STRING *PasswordPtr,
3540 OUT PULONG Flags)
3541 {
3542 NTSTATUS Status;
3543 PACCESS_TOKEN Token;
3544
3545 PAGED_CODE();
3546
3547 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
3548 LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
3549
3550 *UserNamePtr = NULL;
3551 *UserDomainNamePtr = NULL;
3552 *PasswordPtr = NULL;
3553 /* By default, that's not CSC instance */
3554 *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
3555
3556 Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
3557 if (SeTokenIsRestricted(Token))
3558 {
3559 return STATUS_ACCESS_DENIED;
3560 }
3561
3562 /* Get LogonId */
3563 Status = SeQueryAuthenticationIdToken(Token, LogonId);
3564 if (!NT_SUCCESS(Status))
3565 {
3566 return Status;
3567 }
3568
3569 /* And SessionId */
3570 Status = SeQuerySessionIdToken(Token, SessionId);
3571 if (!NT_SUCCESS(Status))
3572 {
3573 return Status;
3574 }
3575
3576 if (RxContext->Create.UserName.Buffer != NULL)
3577 {
3578 UNIMPLEMENTED;
3579 Status = STATUS_NOT_IMPLEMENTED;
3580 goto Leave;
3581 }
3582
3583 /* Deal with connection credentials */
3584 if (RxContext->Create.UserDomainName.Buffer != NULL)
3585 {
3586 UNIMPLEMENTED;
3587 Status = STATUS_NOT_IMPLEMENTED;
3588 goto Leave;
3589 }
3590
3591 if (RxContext->Create.Password.Buffer != NULL)
3592 {
3593 UNIMPLEMENTED;
3594 Status = STATUS_NOT_IMPLEMENTED;
3595 goto Leave;
3596 }
3597
3598 Leave:
3599 if (NT_SUCCESS(Status))
3600 {
3601 /* If that's a CSC instance, mark it as such */
3602 if (RxIsThisACscAgentOpen(RxContext))
3603 {
3604 *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
3605 }
3606 return Status;
3607 }
3608
3609 return Status;
3610 }
3611
3612 /*
3613 * @implemented
3614 */
3615 VOID
3616 RxInitializeWorkQueue(
3617 PRX_WORK_QUEUE WorkQueue,
3618 WORK_QUEUE_TYPE WorkQueueType,
3619 ULONG MaximumNumberOfWorkerThreads,
3620 ULONG MinimumNumberOfWorkerThreads)
3621 {
3622 PAGED_CODE();
3623
3624 WorkQueue->Type = WorkQueueType;
3625 WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
3626 WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
3627
3628 WorkQueue->State = RxWorkQueueActive;
3629 WorkQueue->SpinUpRequestPending = FALSE;
3630 WorkQueue->pRundownContext = NULL;
3631 WorkQueue->NumberOfWorkItemsDispatched = 0;
3632 WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
3633 WorkQueue->CumulativeQueueLength = 0;
3634 WorkQueue->NumberOfSpinUpRequests = 0;
3635 WorkQueue->NumberOfActiveWorkerThreads = 0;
3636 WorkQueue->NumberOfIdleWorkerThreads = 0;
3637 WorkQueue->NumberOfFailedSpinUpRequests = 0;
3638 WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
3639 WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
3640 WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
3641 WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
3642 WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
3643 WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
3644 WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
3645 WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
3646 WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
3647 WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
3648 WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
3649 WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
3650 WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
3651
3652 KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
3653 KeInitializeSpinLock(&WorkQueue->SpinLock);
3654 }
3655
3656 /*
3657 * @implemented
3658 */
3659 NTSTATUS
3660 RxInitializeWorkQueueDispatcher(
3661 PRX_WORK_QUEUE_DISPATCHER Dispatcher)
3662 {
3663 NTSTATUS Status;
3664 ULONG MaximumNumberOfWorkerThreads;
3665
3666 PAGED_CODE();
3667
3668 /* Number of threads will depend on system capacity */
3669 if (MmQuerySystemSize() != MmLargeSystem)
3670 {
3671 MaximumNumberOfWorkerThreads = 5;
3672 }
3673 else
3674 {
3675 MaximumNumberOfWorkerThreads = 10;
3676 }
3677
3678 /* Initialize the work queues */
3679 RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
3680 MaximumNumberOfWorkerThreads, 1);
3681 RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
3682 RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
3683
3684 /* And start the worker threads */
3685 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
3686 RxBootstrapWorkerThreadDispatcher,
3687 &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
3688 if (!NT_SUCCESS(Status))
3689 {
3690 return Status;
3691 }
3692
3693 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
3694 RxBootstrapWorkerThreadDispatcher,
3695 &Dispatcher->WorkQueue[CriticalWorkQueue]);
3696 if (!NT_SUCCESS(Status))
3697 {
3698 return Status;
3699 }
3700
3701 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
3702 RxBootstrapWorkerThreadDispatcher,
3703 &Dispatcher->WorkQueue[DelayedWorkQueue]);
3704 return Status;
3705 }
3706
3707 VOID
3708 RxInitiateSrvOpenKeyAssociation (
3709 IN OUT PSRV_OPEN SrvOpen
3710 )
3711 {
3712 UNIMPLEMENTED;
3713 }
3714
3715 /*
3716 * @implemented
3717 */
3718 NTSTATUS
3719 RxInsertWorkQueueItem(
3720 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
3721 WORK_QUEUE_TYPE WorkQueueType,
3722 PRX_WORK_DISPATCH_ITEM DispatchItem)
3723 {
3724 KIRQL OldIrql;
3725 NTSTATUS Status;
3726 BOOLEAN SpinUpThreads;
3727 PRX_WORK_QUEUE WorkQueue;
3728
3729 /* No dispatcher, nothing to insert */
3730 if (RxDispatcher.State != RxDispatcherActive)
3731 {
3732 return STATUS_UNSUCCESSFUL;
3733 }
3734
3735 /* Get the work queue */
3736 WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
3737
3738 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
3739 /* Only insert if the work queue is in decent state */
3740 if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
3741 {
3742 Status = STATUS_UNSUCCESSFUL;
3743 }
3744 else
3745 {
3746 SpinUpThreads = FALSE;
3747 DispatchItem->WorkQueueItem.pDeviceObject = pMRxDeviceObject;
3748 InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
3749 WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
3750 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
3751
3752 /* If required (and possible!), spin up a new worker thread */
3753 if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
3754 WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
3755 !WorkQueue->SpinUpRequestPending)
3756 {
3757 WorkQueue->SpinUpRequestPending = TRUE;
3758 SpinUpThreads = TRUE;
3759 }
3760
3761 Status = STATUS_SUCCESS;
3762 }
3763 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
3764
3765 /* If we failed, return and still not insert item */
3766 if (!NT_SUCCESS(Status))
3767 {
3768 return Status;
3769 }
3770
3771 /* All fine, insert the item */
3772 KeInsertQueue(&WorkQueue->Queue, &DispatchItem->WorkQueueItem.List);
3773
3774 /* And start a new worker thread if needed */
3775 if (SpinUpThreads)
3776 {
3777 RxSpinUpWorkerThreads(WorkQueue);
3778 }
3779
3780 return Status;
3781 }
3782
3783 BOOLEAN
3784 RxIsThisACscAgentOpen(
3785 IN PRX_CONTEXT RxContext)
3786 {
3787 BOOLEAN CscAgent;
3788
3789 CscAgent = FALSE;
3790
3791 /* Client Side Caching is DFS stuff - we don't support it */
3792 if (RxContext->Create.EaLength != 0)
3793 {
3794 UNIMPLEMENTED;
3795 }
3796
3797 if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
3798 ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
3799 {
3800 CscAgent = TRUE;
3801 }
3802
3803 return CscAgent;
3804 }
3805
3806 VOID
3807 RxLockUserBuffer(
3808 IN PRX_CONTEXT RxContext,
3809 IN LOCK_OPERATION Operation,
3810 IN ULONG BufferLength)
3811 {
3812 PIRP Irp;
3813 PMDL Mdl = NULL;
3814
3815 PAGED_CODE();
3816
3817 _SEH2_TRY
3818 {
3819 Irp = RxContext->CurrentIrp;
3820 /* If we already have a MDL, make sure it's locked */
3821 if (Irp->MdlAddress != NULL)
3822 {
3823 ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
3824 }
3825 else
3826 {
3827 /* That likely means the driver asks for buffered IOs - we don't support it! */
3828 ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
3829
3830 /* If we have a real length */
3831 if (BufferLength > 0)
3832 {
3833 /* Allocate a MDL and lock it */
3834 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
3835 if (Mdl == NULL)
3836 {
3837 RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
3838 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3839 }
3840
3841 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
3842 }
3843 }
3844 }
3845 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3846 {
3847 NTSTATUS Status;
3848
3849 Status = _SEH2_GetExceptionCode();
3850
3851 /* Free the possible MDL we have allocated */
3852 IoFreeMdl(Mdl);
3853 Irp->MdlAddress = NULL;
3854
3855 RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
3856
3857 /* Fix status */
3858 if (!FsRtlIsNtstatusExpected(Status))
3859 {
3860 Status = STATUS_INVALID_USER_BUFFER;
3861 }
3862
3863 RxContext->IoStatusBlock.Status = Status;
3864 ExRaiseStatus(Status);
3865 }
3866 _SEH2_END;
3867 }
3868
3869 NTSTATUS
3870 RxLowIoCompletionTail(
3871 IN PRX_CONTEXT RxContext)
3872 {
3873 NTSTATUS Status;
3874 USHORT Operation;
3875
3876 PAGED_CODE();
3877
3878 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
3879
3880 /* Only continue if we're at APC_LEVEL or lower */
3881 if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
3882 !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
3883 {
3884 return STATUS_MORE_PROCESSING_REQUIRED;
3885 }
3886
3887 /* Call the completion routine */
3888 DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
3889 Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
3890 if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
3891 {
3892 return Status;
3893 }
3894
3895 /* If it was a RW operation, for a paging file ... */
3896 Operation = RxContext->LowIoContext.Operation;
3897 if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
3898 {
3899 if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
3900 {
3901 UNIMPLEMENTED;
3902 Status = STATUS_NOT_IMPLEMENTED;
3903 }
3904 }
3905 else
3906 {
3907 /* Sanity check: we had known operation */
3908 ASSERT(Operation < LOWIO_OP_MAXIMUM);
3909 }
3910
3911 /* If not sync operation, complete now. Otherwise, caller has already completed */
3912 if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
3913 {
3914 RxCompleteRequest(RxContext, Status);
3915 }
3916
3917 DPRINT("Status: %x\n", Status);
3918 return Status;
3919 }
3920
3921 /*
3922 * @implemented
3923 */
3924 NTSTATUS
3925 NTAPI
3926 RxLowIoPopulateFsctlInfo(
3927 IN PRX_CONTEXT RxContext)
3928 {
3929 PMDL Mdl;
3930 PIRP Irp;
3931 UCHAR Method;
3932 PIO_STACK_LOCATION Stack;
3933
3934 PAGED_CODE();
3935
3936 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
3937
3938 Irp = RxContext->CurrentIrp;
3939 Stack = RxContext->CurrentIrpSp;
3940
3941 /* Copy stack parameters */
3942 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
3943 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
3944 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
3945 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
3946 Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
3947
3948 /* Same buffer in case of buffered */
3949 if (Method == METHOD_BUFFERED)
3950 {
3951 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
3952 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
3953
3954 return STATUS_SUCCESS;
3955 }
3956
3957 /* Two buffers for neither */
3958 if (Method == METHOD_NEITHER)
3959 {
3960 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
3961 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
3962
3963 return STATUS_SUCCESS;
3964 }
3965
3966 /* Only IN/OUT remain */
3967 ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
3968
3969 /* Use system buffer for input */
3970 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
3971 /* And MDL for output */
3972 Mdl = Irp->MdlAddress;
3973 if (Mdl != NULL)
3974 {
3975 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
3976 if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
3977 {
3978 return STATUS_INSUFFICIENT_RESOURCES;
3979 }
3980 }
3981 else
3982 {
3983 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
3984 }
3985
3986 return STATUS_SUCCESS;
3987 }
3988
3989 NTSTATUS
3990 NTAPI
3991 RxLowIoSubmit(
3992 IN PRX_CONTEXT RxContext,
3993 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
3994 {
3995 NTSTATUS Status;
3996 USHORT Operation;
3997 BOOLEAN Synchronous;
3998 PLOWIO_CONTEXT LowIoContext;
3999
4000 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
4001
4002 PAGED_CODE();
4003
4004 LowIoContext = &RxContext->LowIoContext;
4005 Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4006
4007 LowIoContext->CompletionRoutine = CompletionRoutine;
4008
4009 Status = STATUS_SUCCESS;
4010 Operation = LowIoContext->Operation;
4011 switch (Operation)
4012 {
4013 case LOWIO_OP_READ:
4014 case LOWIO_OP_WRITE:
4015 /* Check that the parameters were properly set by caller
4016 * See comment in RxInitializeLowIoContext()
4017 */
4018 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
4019 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
4020
4021 /* Lock the buffer */
4022 RxLockUserBuffer(RxContext,
4023 (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
4024 LowIoContext->ParamsFor.ReadWrite.ByteCount);
4025 if (RxNewMapUserBuffer(RxContext) == NULL)
4026 {
4027 return STATUS_INSUFFICIENT_RESOURCES;
4028 }
4029 LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
4030
4031 /* If that's a paging IO, initialize serial operation */
4032 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
4033 {
4034 PFCB Fcb;
4035
4036 Fcb = (PFCB)RxContext->pFcb;
4037
4038 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
4039 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
4040 if (Operation == LOWIO_OP_READ)
4041 {
4042 InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
4043 }
4044 else
4045 {
4046 InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
4047 }
4048
4049 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
4050 }
4051
4052 break;
4053
4054 case LOWIO_OP_FSCTL:
4055 case LOWIO_OP_IOCTL:
4056 /* Set FSCTL/IOCTL parameters */
4057 Status = RxLowIoPopulateFsctlInfo(RxContext);
4058 /* Check whether we're consistent: a length means a buffer */
4059 if (NT_SUCCESS(Status))
4060 {
4061 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
4062 LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
4063 (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
4064 LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
4065 {
4066 Status = STATUS_INVALID_PARAMETER;
4067 }
4068 }
4069 break;
4070
4071 /* Nothing to do */
4072 case LOWIO_OP_SHAREDLOCK:
4073 case LOWIO_OP_EXCLUSIVELOCK:
4074 case LOWIO_OP_UNLOCK:
4075 case LOWIO_OP_UNLOCK_MULTIPLE:
4076 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
4077 case LOWIO_OP_CLEAROUT:
4078 break;
4079
4080 default:
4081 ASSERT(FALSE);
4082 Status = STATUS_INVALID_PARAMETER;
4083 break;
4084 }
4085
4086 /* No need to perform extra init in case of posting */
4087 RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
4088
4089 /* Preflight checks were OK, time to submit */
4090 if (NT_SUCCESS(Status))
4091 {
4092 PMINIRDR_DISPATCH Dispatch;
4093
4094 if (!Synchronous)
4095 {
4096 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
4097 /* If not synchronous, we're likely to return before the operation is finished */
4098 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
4099 {
4100 IoMarkIrpPending(RxContext->CurrentIrp);
4101 }
4102 }
4103
4104 Dispatch = RxContext->RxDeviceObject->Dispatch;
4105 if (Dispatch != NULL)
4106 {
4107 /* We'll try to execute until the mini-rdr doesn't return pending */
4108 do
4109 {
4110 RxContext->IoStatusBlock.Information = 0;
4111
4112 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
4113 if (Status == STATUS_PENDING)
4114 {
4115 /* Unless it's not synchronous, caller will be happy with pending op */
4116 if (!Synchronous)
4117 {
4118 return Status;
4119 }
4120
4121 RxWaitSync(RxContext);
4122 Status = RxContext->IoStatusBlock.Status;
4123 }
4124 else
4125 {
4126 if (!Synchronous)
4127 {
4128 /* We had marked the IRP pending, whereas the operation finished, drop that */
4129 if (Status != STATUS_RETRY)
4130 {
4131 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
4132 {
4133 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
4134 }
4135
4136 InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
4137 }
4138 }
4139 }
4140 } while (Status == STATUS_PENDING);
4141 }
4142 else
4143 {
4144 Status = STATUS_INVALID_PARAMETER;
4145 }
4146 }
4147
4148 /* Call completion and return */
4149 RxContext->IoStatusBlock.Status = Status;
4150 LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
4151 return RxLowIoCompletionTail(RxContext);
4152 }
4153
4154 /*
4155 * @implemented
4156 */
4157 PVOID
4158 RxMapSystemBuffer(
4159 IN PRX_CONTEXT RxContext)
4160 {
4161 PIRP Irp;
4162
4163 PAGED_CODE();
4164
4165 Irp = RxContext->CurrentIrp;
4166 /* We should have a MDL (buffered IOs are not supported!) */
4167 if (Irp->MdlAddress != NULL)
4168 {
4169 ASSERT(FALSE);
4170 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
4171 }
4172
4173 /* Just return system buffer */
4174 return Irp->AssociatedIrp.SystemBuffer;
4175 }
4176
4177 VOID
4178 RxMarkFobxOnCleanup(
4179 PFOBX pFobx,
4180 PBOOLEAN NeedPurge)
4181 {
4182 UNIMPLEMENTED;
4183 }
4184
4185 VOID
4186 RxMarkFobxOnClose(
4187 PFOBX Fobx)
4188 {
4189 UNIMPLEMENTED;
4190 }
4191
4192 /*
4193 * @implemented
4194 */
4195 PVOID
4196 RxNewMapUserBuffer(
4197 PRX_CONTEXT RxContext)
4198 {
4199 PIRP Irp;
4200
4201 PAGED_CODE();
4202
4203 Irp = RxContext->CurrentIrp;
4204 if (Irp->MdlAddress != NULL)
4205 {
4206 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
4207 }
4208
4209 return Irp->UserBuffer;
4210 }
4211
4212 BOOLEAN
4213 NTAPI
4214 RxNoOpAcquire(
4215 IN PVOID Fcb,
4216 IN BOOLEAN Wait)
4217 {
4218 UNIMPLEMENTED;
4219 return FALSE;
4220 }
4221
4222 VOID
4223 NTAPI
4224 RxNoOpRelease(
4225 IN PVOID Fcb)
4226 {
4227 UNIMPLEMENTED;
4228 }
4229
4230 VOID
4231 RxOrphanThisFcb(
4232 PFCB Fcb)
4233 {
4234 UNIMPLEMENTED;
4235 }
4236
4237 /*
4238 * @implemented
4239 */
4240 BOOLEAN
4241 RxpAcquirePrefixTableLockShared(
4242 PRX_PREFIX_TABLE pTable,
4243 BOOLEAN Wait,
4244 BOOLEAN ProcessBufferingStateChangeRequests)
4245 {
4246 PAGED_CODE();
4247
4248 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
4249 pTable->TableLock.ActiveEntries);
4250
4251 return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
4252 }
4253
4254 /*
4255 * @implemented
4256 */
4257 BOOLEAN
4258 RxpAcquirePrefixTableLockExclusive(
4259 PRX_PREFIX_TABLE pTable,
4260 BOOLEAN Wait,
4261 BOOLEAN ProcessBufferingStateChangeRequests)
4262 {
4263 PAGED_CODE();
4264
4265 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
4266 pTable->TableLock.ActiveEntries);
4267
4268 return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
4269 }
4270
4271 /*
4272 * @implemented
4273 */
4274 BOOLEAN
4275 RxpDereferenceAndFinalizeNetFcb(
4276 OUT PFCB ThisFcb,
4277 IN PRX_CONTEXT RxContext,
4278 IN BOOLEAN RecursiveFinalize,
4279 IN BOOLEAN ForceFinalize)
4280 {
4281 NTSTATUS Status;
4282 ULONG References;
4283 PNET_ROOT NetRoot;
4284 BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
4285
4286 PAGED_CODE();
4287
4288 ASSERT(!ForceFinalize);
4289 ASSERT(NodeTypeIsFcb(ThisFcb));
4290 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
4291
4292 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
4293 References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
4294 if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
4295 {
4296 return FALSE;
4297 }
4298
4299 Freed = FALSE;
4300 Status = STATUS_SUCCESS;
4301 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
4302 ResourceAcquired = FALSE;
4303 NetRootReferenced = FALSE;
4304 /* If FCB isn't orphaned, it still have context attached */
4305 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
4306 {
4307 /* Don't let NetRoot go away before we're done */
4308 RxReferenceNetRoot(NetRoot);
4309 NetRootReferenced = TRUE;
4310
4311 /* Try to acquire the table lock exclusively */
4312 if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
4313 {
4314 RxReferenceNetFcb(ThisFcb);
4315
4316 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
4317 {
4318 if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
4319 {
4320 RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
4321 }
4322
4323 RxReleaseFcb(RxContext, ThisFcb);
4324
4325 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
4326
4327 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
4328 }
4329
4330 References = RxDereferenceNetFcb(ThisFcb);
4331
4332 ResourceAcquired = TRUE;
4333 }
4334 }
4335
4336 /* If locking was OK (or not needed!), attempt finalization */
4337 if (NT_SUCCESS(Status))
4338 {
4339 Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
4340 }
4341
4342 /* Release table lock if acquired */
4343 if (ResourceAcquired)
4344 {
4345 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4346 }
4347
4348 /* We don't need the NetRoot anylonger */
4349 if (NetRootReferenced)
4350 {
4351 RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
4352 }
4353
4354 return Freed;
4355 }
4356
4357 LONG
4358 RxpDereferenceNetFcb(
4359 PFCB Fcb)
4360 {
4361 UNIMPLEMENTED;
4362 return 0;
4363 }
4364
4365 /*
4366 * @implemented
4367 */
4368 PRX_PREFIX_ENTRY
4369 RxPrefixTableInsertName(
4370 IN OUT PRX_PREFIX_TABLE ThisTable,
4371 IN OUT PRX_PREFIX_ENTRY ThisEntry,
4372 IN PVOID Container,
4373 IN PULONG ContainerRefCount,
4374 IN USHORT CaseInsensitiveLength,
4375 IN PRX_CONNECTION_ID ConnectionId
4376 )
4377 {
4378 PAGED_CODE();
4379
4380 DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
4381
4382 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
4383 ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
4384
4385 /* Copy parameters and compute hash */
4386 ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
4387 ThisEntry->ContainingRecord = Container;
4388 ThisEntry->ContainerRefCount = ContainerRefCount;
4389 InterlockedIncrement((volatile long *)ContainerRefCount);
4390 ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
4391 DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
4392
4393 /* If no path length: this is entry for null path */
4394 if (ThisEntry->Prefix.Length == 0)
4395 {
4396 ThisTable->TableEntryForNull = ThisEntry;
4397 }
4398 /* Otherwise, insert in the appropriate bucket */
4399 else
4400 {
4401 InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
4402 }
4403
4404 /* If we had a connection ID, keep track of it */
4405 if (ConnectionId != NULL)
4406 {
4407 ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
4408 }
4409 else
4410 {
4411 ThisEntry->ConnectionId.Luid.LowPart = 0;
4412 ThisEntry->ConnectionId.Luid.HighPart = 0;
4413 }
4414
4415 InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
4416 /* Reflect the changes */
4417 ++ThisTable->Version;
4418
4419 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
4420
4421 return ThisEntry;
4422 }
4423
4424 /*
4425 * @implemented
4426 */
4427 PVOID
4428 RxPrefixTableLookupName(
4429 IN PRX_PREFIX_TABLE ThisTable,
4430 IN PUNICODE_STRING CanonicalName,
4431 OUT PUNICODE_STRING RemainingName,
4432 IN PRX_CONNECTION_ID ConnectionId)
4433 {
4434 PVOID Container;
4435
4436 PAGED_CODE();
4437
4438 ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
4439 ASSERT(CanonicalName->Length > 0);
4440
4441 /* Call the internal helper */
4442 Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
4443 if (Container == NULL)
4444 {
4445 return NULL;
4446 }
4447
4448 /* Reference our container before returning it */
4449 if (RdbssReferenceTracingValue != 0)
4450 {
4451 NODE_TYPE_CODE Type;
4452
4453 Type = NodeType(Container);
4454 switch (Type)
4455 {
4456 case RDBSS_NTC_SRVCALL:
4457 RxReferenceSrvCall(Container);
4458 break;
4459
4460 case RDBSS_NTC_NETROOT:
4461 RxReferenceNetRoot(Container);
4462 break;
4463
4464 case RDBSS_NTC_V_NETROOT:
4465 RxReferenceVNetRoot(Container);
4466 break;
4467
4468 default:
4469 ASSERT(FALSE);
4470 break;
4471 }
4472 }
4473 else
4474 {
4475 RxReference(Container);
4476 }
4477
4478 return Container;
4479 }
4480
4481 LONG
4482 RxpReferenceNetFcb(
4483 PFCB Fcb)
4484 {
4485 UNIMPLEMENTED;
4486 return 0;
4487 }
4488
4489 /*
4490 * @implemented
4491 */
4492 VOID
4493 RxpReleasePrefixTableLock(
4494 PRX_PREFIX_TABLE pTable,
4495 BOOLEAN ProcessBufferingStateChangeRequests)
4496 {
4497 PAGED_CODE();
4498
4499 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
4500 pTable->TableLock.ActiveEntries);
4501
4502 ExReleaseResourceLite(&pTable->TableLock);
4503 }
4504
4505 /*
4506 * @implemented
4507 */
4508 VOID
4509 NTAPI
4510 RxPrepareContextForReuse(
4511 IN OUT PRX_CONTEXT RxContext)
4512 {
4513 PAGED_CODE();
4514
4515 /* When we reach that point, make sure mandatory parts are null-ed */
4516 if (RxContext->MajorFunction == IRP_MJ_CREATE)
4517 {
4518 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
4519 RxContext->Create.RdrFlags = 0;
4520 }
4521 else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
4522 {
4523 ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
4524 ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
4525 }
4526
4527 RxContext->ReferenceCount = 0;
4528 }
4529
4530 VOID
4531 RxProcessFcbChangeBufferingStateRequest(
4532 PFCB Fcb)
4533 {
4534 UNIMPLEMENTED;
4535 }
4536
4537 BOOLEAN
4538 RxpTrackDereference(
4539 _In_ ULONG TraceType,
4540 _In_ PCSTR FileName,
4541 _In_ ULONG Line,
4542 _In_ PVOID Instance)
4543 {
4544 UNIMPLEMENTED;
4545 return FALSE;
4546 }
4547
4548 VOID
4549 RxpTrackReference(
4550 _In_ ULONG TraceType,
4551 _In_ PCSTR FileName,
4552 _In_ ULONG Line,
4553 _In_ PVOID Instance)
4554 {
4555 UNIMPLEMENTED;
4556 }
4557
4558 VOID
4559 RxpUndoScavengerFinalizationMarking(
4560 PVOID Instance)
4561 {
4562 UNIMPLEMENTED;
4563 }
4564
4565 NTSTATUS
4566 RxPurgeFcbInSystemCache(
4567 IN PFCB Fcb,
4568 IN PLARGE_INTEGER FileOffset OPTIONAL,
4569 IN ULONG Length,
4570 IN BOOLEAN UninitializeCacheMaps,
4571 IN BOOLEAN FlushFile)
4572 {
4573 UNIMPLEMENTED;
4574 return STATUS_NOT_IMPLEMENTED;
4575 }
4576
4577 /*
4578 * @implemented
4579 */
4580 VOID
4581 RxpWorkerThreadDispatcher(
4582 IN PRX_WORK_QUEUE WorkQueue,
4583 IN PLARGE_INTEGER WaitInterval)
4584 {
4585 NTSTATUS Status;
4586 PVOID Parameter;
4587 PETHREAD CurrentThread;
4588 BOOLEAN KillThread, Dereference;
4589 PRX_WORK_QUEUE_ITEM WorkQueueItem;
4590 PWORKER_THREAD_ROUTINE WorkerRoutine;
4591
4592 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
4593
4594 /* Reference ourselves */
4595 CurrentThread = PsGetCurrentThread();
4596 Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, PsThreadType, KernelMode);
4597 ASSERT(NT_SUCCESS(Status));
4598
4599 /* Infinite loop for worker */
4600 KillThread = FALSE;
4601 Dereference = FALSE;
4602 do
4603 {
4604 KIRQL OldIrql;
4605 PLIST_ENTRY ListEntry;
4606
4607 /* Remove an entry from the work queue */
4608 ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
4609 if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
4610 {
4611 PRDBSS_DEVICE_OBJECT DeviceObject;
4612
4613 WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
4614
4615 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
4616 InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
4617 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4618
4619 /* Get the parameters, and null-them in the struct */
4620 WorkerRoutine = WorkQueueItem->WorkerRoutine;
4621 Parameter = WorkQueueItem->Parameter;
4622 DeviceObject = WorkQueueItem->pDeviceObject;
4623
4624 WorkQueueItem->List.Flink = NULL;
4625 WorkQueueItem->WorkerRoutine = NULL;
4626 WorkQueueItem->Parameter = NULL;
4627 WorkQueueItem->pDeviceObject = NULL;
4628
4629 /* Call the routine */
4630 DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
4631 WorkerRoutine(Parameter);
4632
4633 /* Are we going down now? */
4634 if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
4635 {
4636 PKEVENT TearDownEvent;
4637
4638 TearDownEvent = InterlockedExchangePointer((volatile PVOID)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
4639 if (TearDownEvent != NULL)
4640 {
4641 KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
4642 }
4643 }
4644
4645 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
4646 }
4647
4648 /* Shall we shutdown... */
4649 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4650 switch (WorkQueue->State)
4651 {
4652 /* Our queue is active, kill it if we have no more items to dispatch
4653 * and more threads than the required minimum
4654 */
4655 case RxWorkQueueActive:
4656 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
4657 {
4658 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
4659 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
4660 {
4661 KillThread = TRUE;
4662 Dereference = TRUE;
4663 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4664 }
4665
4666 if (KillThread)
4667 {
4668 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4669 }
4670 }
4671 break;
4672
4673 /* The queue is inactive: kill it we have more threads than the required minimum */
4674 case RxWorkQueueInactive:
4675 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
4676 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
4677 {
4678 KillThread = TRUE;
4679 Dereference = TRUE;
4680 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4681 }
4682
4683 if (KillThread)
4684 {
4685 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4686 }
4687 break;
4688
4689 /* Rundown in progress..., kill it for sure! */
4690 case RxWorkQueueRundownInProgress:
4691 {
4692 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
4693
4694 ASSERT(WorkQueue->pRundownContext != NULL);
4695
4696 RundownContext = WorkQueue->pRundownContext;
4697 RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
4698
4699 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
4700 KillThread = TRUE;
4701 Dereference = FALSE;
4702
4703 if (WorkQueue->NumberOfActiveWorkerThreads == 0)
4704 {
4705 KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
4706 }
4707
4708 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
4709 }
4710 break;
4711
4712 default:
4713 break;
4714 }
4715 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4716 } while (!KillThread);
4717
4718 DPRINT("Killed worker thread\n");
4719
4720 /* Do we have to dereference ourselves? */
4721 if (Dereference)
4722 {
4723 ObDereferenceObject(CurrentThread);
4724 }
4725
4726 /* Dump last executed routine */
4727 if (DumpDispatchRoutine)
4728 {
4729 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
4730 }
4731
4732 PsTerminateSystemThread(STATUS_SUCCESS);
4733 }
4734
4735 VOID
4736 RxReference(
4737 IN OUT PVOID Instance)
4738 {
4739 NODE_TYPE_CODE NodeType;
4740 PNODE_TYPE_AND_SIZE Node;
4741
4742 PAGED_CODE();
4743
4744 RxAcquireScavengerMutex();
4745
4746 /* We can only reference a few structs */
4747 NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
4748 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
4749 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
4750 (NodeType == RDBSS_NTC_FOBX));
4751
4752 Node = (PNODE_TYPE_AND_SIZE)Instance;
4753 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
4754
4755 /* And that's not implemented! (yay, we leak :-D) */
4756 switch (NodeType)
4757 {
4758 case RDBSS_NTC_SRVCALL:
4759 case RDBSS_NTC_NETROOT:
4760 case RDBSS_NTC_V_NETROOT:
4761 case RDBSS_NTC_SRVOPEN:
4762 case RDBSS_NTC_FOBX:
4763 UNIMPLEMENTED;
4764 break;
4765 default:
4766 ASSERT(FALSE);
4767 break;
4768 }
4769
4770 RxpUndoScavengerFinalizationMarking(Instance);
4771 RxReleaseScavengerMutex();
4772 }
4773
4774 VOID
4775 NTAPI
4776 RxResumeBlockedOperations_Serially(
4777 IN OUT PRX_CONTEXT RxContext,
4778 IN OUT PLIST_ENTRY BlockingIoQ)
4779 {
4780 PAGED_CODE();
4781
4782 RxAcquireSerializationMutex();
4783
4784 /* This can only happen on pipes */
4785 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
4786 {
4787 RxReleaseSerializationMutex();
4788 return;
4789 }
4790
4791 UNIMPLEMENTED;
4792
4793 RxReleaseSerializationMutex();
4794 }
4795
4796 BOOLEAN
4797 RxScavengeRelatedFobxs(
4798 PFCB Fcb)
4799 {
4800 UNIMPLEMENTED;
4801 return FALSE;
4802 }
4803
4804 BOOLEAN
4805 RxScavengeVNetRoots(
4806 PRDBSS_DEVICE_OBJECT RxDeviceObject)
4807 {
4808 UNIMPLEMENTED;
4809 return FALSE;
4810 }
4811
4812 /*
4813 * @implemented
4814 */
4815 VOID
4816 NTAPI
4817 RxSpinUpRequestsDispatcher(
4818 PVOID Dispatcher)
4819 {
4820 NTSTATUS Status;
4821 PRX_DISPATCHER RxDispatcher;
4822
4823 Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, PsThreadType, KernelMode);
4824 if (!NT_SUCCESS(Status))
4825 {
4826 PsTerminateSystemThread(STATUS_SUCCESS);
4827 }
4828
4829 RxDispatcher = Dispatcher;
4830
4831 do
4832 {
4833 KIRQL OldIrql;
4834 PLIST_ENTRY ListEntry;
4835
4836 Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
4837 KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
4838 ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
4839
4840 KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
4841 if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
4842 {
4843 ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
4844 }
4845 else
4846 {
4847 ListEntry = &RxDispatcher->SpinUpRequests;
4848 }
4849 KeResetEvent(&RxDispatcher->SpinUpRequestsEvent);
4850 KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
4851
4852 while (ListEntry != &RxDispatcher->SpinUpRequests)
4853 {
4854 PWORK_QUEUE_ITEM WorkItem;
4855 PRX_WORK_QUEUE WorkQueue;
4856
4857 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
4858 WorkQueue = WorkItem->Parameter;
4859
4860 InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
4861
4862 DPRINT1("WORKQ:SR %lx %lx\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
4863 WorkItem->WorkerRoutine(WorkItem->Parameter);
4864 }
4865 } while (RxDispatcher->State == RxDispatcherActive);
4866
4867 KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
4868 PsTerminateSystemThread(STATUS_SUCCESS);
4869 }
4870
4871 /*
4872 * @implemented
4873 */
4874 NTSTATUS
4875 RxSpinUpWorkerThread(
4876 PRX_WORK_QUEUE WorkQueue,
4877 PRX_WORKERTHREAD_ROUTINE Routine,
4878 PVOID Parameter)
4879 {
4880 KIRQL OldIrql;
4881 NTSTATUS Status;
4882 HANDLE ThreadHandle;
4883
4884 PAGED_CODE();
4885
4886 /* If work queue is inactive, that cannot work */
4887 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4888 if (WorkQueue->State != RxWorkQueueActive)
4889 {
4890 Status = STATUS_UNSUCCESSFUL;
4891 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
4892 }
4893 else
4894 {
4895 ++WorkQueue->NumberOfActiveWorkerThreads;
4896 Status = STATUS_SUCCESS;
4897 }
4898 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4899
4900 /* Quit on failure */
4901 if (!NT_SUCCESS(Status))
4902 {
4903 return Status;
4904 }
4905
4906 /* Spin up the worker thread */
4907 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
4908 if (NT_SUCCESS(Status))
4909 {
4910 ZwClose(ThreadHandle);
4911 return Status;
4912 }
4913 /* Read well: we reached that point because it failed! */
4914 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
4915
4916 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4917 --WorkQueue->NumberOfActiveWorkerThreads;
4918 ++WorkQueue->NumberOfFailedSpinUpRequests;
4919
4920 /* Rundown, no more active threads, set the event! */
4921 if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
4922 WorkQueue->State == RxWorkQueueRundownInProgress)
4923 {
4924 KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
4925 }
4926
4927 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
4928
4929 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4930
4931 return Status;
4932 }
4933
4934 VOID
4935 RxSpinUpWorkerThreads(
4936 PRX_WORK_QUEUE WorkQueue)
4937 {
4938 UNIMPLEMENTED;
4939 }
4940
4941 VOID
4942 RxSynchronizeWithScavenger(
4943 IN PRX_CONTEXT RxContext)
4944 {
4945 UNIMPLEMENTED;
4946 }
4947
4948 /*
4949 * @implemented
4950 */
4951 ULONG
4952 RxTableComputeHashValue(
4953 IN PUNICODE_STRING Name)
4954 {
4955 ULONG Hash;
4956 SHORT Loops[8];
4957 USHORT MaxChar, i;
4958
4959 PAGED_CODE();
4960
4961 MaxChar = Name->Length / sizeof(WCHAR);
4962
4963 Loops[0] = 1;
4964 Loops[1] = MaxChar - 1;
4965 Loops[2] = MaxChar - 2;
4966 Loops[3] = MaxChar - 3;
4967 Loops[4] = MaxChar - 4;
4968 Loops[5] = MaxChar / 4;
4969 Loops[6] = 2 * MaxChar / 4;
4970 Loops[7] = 3 * MaxChar / 4;
4971
4972 Hash = 0;
4973 for (i = 0; i < 8; ++i)
4974 {
4975 SHORT Idx;
4976
4977 Idx = Loops[i];
4978 if (Idx >= 0 && Idx < MaxChar)
4979 {
4980 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
4981 }
4982 }
4983
4984 return Hash;
4985 }
4986
4987 /*
4988 * @implemented
4989 */
4990 ULONG
4991 RxTableComputePathHashValue(
4992 IN PUNICODE_STRING Name)
4993 {
4994 ULONG Hash;
4995 SHORT Loops[8];
4996 USHORT MaxChar, i;
4997
4998 PAGED_CODE();
4999
5000 MaxChar = Name->Length / sizeof(WCHAR);
5001
5002 Loops[0] = 1;
5003 Loops[1] = MaxChar - 1;
5004 Loops[2] = MaxChar - 2;
5005 Loops[3] = MaxChar - 3;
5006 Loops[4] = MaxChar - 4;
5007 Loops[5] = MaxChar / 4;
5008 Loops[6] = 2 * MaxChar / 4;
5009 Loops[7] = 3 * MaxChar / 4;
5010
5011 Hash = 0;
5012 for (i = 0; i < 8; ++i)
5013 {
5014 SHORT Idx;
5015
5016 Idx = Loops[i];
5017 if (Idx >= 0 && Idx < MaxChar)
5018 {
5019 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
5020 }
5021 }
5022
5023 return Hash;
5024 }
5025
5026 PVOID
5027 RxTableLookupName(
5028 IN PRX_PREFIX_TABLE ThisTable,
5029 IN PUNICODE_STRING Name,
5030 OUT PUNICODE_STRING RemainingName,
5031 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
5032 {
5033 PVOID Container;
5034 USHORT i, MaxChar;
5035 PRX_PREFIX_ENTRY Entry;
5036 RX_CONNECTION_ID NullId;
5037 UNICODE_STRING LookupString;
5038
5039 PAGED_CODE();
5040
5041 /* If caller didn't provide a connection ID, setup one */
5042 if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
5043 {
5044 NullId.Luid.LowPart = 0;
5045 NullId.Luid.HighPart = 0;
5046 RxConnectionId = &NullId;
5047 }
5048
5049 /* Validate name */
5050 ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
5051
5052 Entry = NULL;
5053 Container = NULL;
5054 LookupString.Buffer = Name->Buffer;
5055 MaxChar = Name->Length / sizeof(WCHAR);
5056 /* We'll perform the lookup, path component after another */
5057 for (i = 1; i < MaxChar; ++i)
5058 {
5059 ULONG Hash;
5060 PRX_PREFIX_ENTRY CurEntry;
5061
5062 /* Don't cut in the middle of a path element */
5063 if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
5064 {
5065 continue;
5066 }
5067
5068 /* Perform lookup in the table */
5069 LookupString.Length = i * sizeof(WCHAR);
5070 Hash = RxTableComputeHashValue(&LookupString);
5071 CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
5072 #if DBG
5073 ++ThisTable->Lookups;
5074 #endif
5075 /* Entry not found, move to the next component */
5076 if (CurEntry == NULL)
5077 {
5078 #if DBG
5079 ++ThisTable->FailedLookups;
5080 #endif
5081 continue;
5082 }
5083
5084 Entry = CurEntry;
5085 ASSERT(Entry->ContainingRecord != NULL);
5086 Container = Entry->ContainingRecord;
5087
5088 /* Need to handle NetRoot specific case... */
5089 if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
5090 {
5091 UNIMPLEMENTED;
5092 break;
5093 }
5094 else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
5095 {
5096 break;
5097 }
5098 else
5099 {
5100 ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
5101 }
5102 }
5103
5104 /* Entry was found */
5105 if (Entry != NULL)
5106 {
5107 DPRINT("Found\n");
5108
5109 ASSERT(Name->Length >= Entry->Prefix.Length);
5110
5111 /* Setup remaining name */
5112 RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
5113 RemainingName->Length = Name->Length - Entry->Prefix.Length;
5114 RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
5115 }
5116 else
5117 {
5118 /* Otherwise, that's the whole name */
5119 RemainingName = Name;
5120 }
5121
5122 return Container;
5123 }
5124
5125 /*
5126 * @implemented
5127 */
5128 PRX_PREFIX_ENTRY
5129 RxTableLookupName_ExactLengthMatch(
5130 IN PRX_PREFIX_TABLE ThisTable,
5131 IN PUNICODE_STRING Name,
5132 IN ULONG HashValue,
5133 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
5134 {
5135 PLIST_ENTRY ListEntry, HashBucket;
5136
5137 PAGED_CODE();
5138
5139 ASSERT(RxConnectionId != NULL);
5140
5141 /* Select the right bucket */
5142 HashBucket = HASH_BUCKET(ThisTable, HashValue);
5143 DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
5144 /* If bucket is empty, no match */
5145 if (IsListEmpty(HashBucket))
5146 {
5147 return NULL;
5148 }
5149
5150 /* Browse all the entries in the bucket */
5151 for (ListEntry = HashBucket->Flink;
5152 ListEntry != HashBucket;
5153 ListEntry = ListEntry->Flink)
5154 {
5155 PVOID Container;
5156 PRX_PREFIX_ENTRY Entry;
5157 BOOLEAN CaseInsensitive;
5158 PUNICODE_STRING CmpName, CmpPrefix;
5159 UNICODE_STRING InsensitiveName, InsensitivePrefix;
5160
5161 Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
5162 ++ThisTable->Considers;
5163 ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
5164
5165 Container = Entry->ContainingRecord;
5166 ASSERT(Container != NULL);
5167
5168 /* Not the same hash, not the same length, move on */
5169 if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
5170 {
5171 continue;
5172 }
5173
5174 ++ThisTable->Compares;
5175 /* If we have to perform a case insensitive compare on a portion... */
5176 if (Entry->CaseInsensitiveLength != 0)
5177 {
5178 ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
5179
5180 /* Perform the case insensitive check on the asked length */
5181 InsensitiveName.Buffer = Name->Buffer;
5182 InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
5183 InsensitiveName.Length = Entry->CaseInsensitiveLength;
5184 InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
5185 /* No match, move to the next entry */
5186 if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
5187 {
5188 continue;
5189 }
5190
5191 /* Was the case insensitive covering the whole name? */
5192 if (Name->Length == Entry->CaseInsensitiveLength)
5193 {
5194 /* If connection ID also matches, that a complete match! */
5195 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
5196 {
5197 return Entry;
5198 }
5199 }
5200
5201 /* Otherwise, we have to continue with the sensitive match.... */
5202 InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
5203 InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
5204 InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
5205 InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
5206
5207 CmpName = &InsensitiveName;
5208 CmpPrefix = &InsensitivePrefix;
5209 CaseInsensitive = FALSE;
5210 }
5211 else
5212 {
5213 CmpName = Name;
5214 CmpPrefix = &Entry->Prefix;
5215 CaseInsensitive = ThisTable->CaseInsensitiveMatch;
5216 }
5217
5218 /* Perform the compare, if there's a match, also check for connection ID */
5219 if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
5220 {
5221 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
5222 {
5223 return Entry;
5224 }
5225 }
5226 }
5227
5228 return NULL;
5229 }
5230
5231 VOID
5232 RxTrackerUpdateHistory(
5233 _Inout_opt_ PRX_CONTEXT RxContext,
5234 _Inout_ PMRX_FCB MrxFcb,
5235 _In_ ULONG Operation,
5236 _In_ ULONG LineNumber,
5237 _In_ PCSTR FileName,
5238 _In_ ULONG SerialNumber)
5239 {
5240 UNIMPLEMENTED;
5241 }
5242
5243 VOID
5244 RxTrackPagingIoResource(
5245 _Inout_ PVOID Instance,
5246 _In_ ULONG Type,
5247 _In_ ULONG Line,
5248 _In_ PCSTR File)
5249 {
5250 UNIMPLEMENTED;
5251 }
5252
5253 /*
5254 * @implemented
5255 */
5256 VOID
5257 RxUninitializeVNetRootParameters(
5258 IN PUNICODE_STRING UserName,
5259 IN PUNICODE_STRING UserDomainName,
5260 IN PUNICODE_STRING Password,
5261 OUT PULONG Flags)
5262 {
5263 PAGED_CODE();
5264
5265 /* Only free what could have been allocated */
5266 if (UserName != NULL)
5267 {
5268 ExFreePool(UserName);
5269 }
5270
5271 if (UserDomainName != NULL)
5272 {
5273 ExFreePool(UserDomainName);
5274 }
5275
5276 if (Password != NULL)
5277 {
5278 ExFreePool(Password);
5279 }
5280
5281 /* And remove the possibly set CSC agent flag */
5282 if (Flags != NULL)
5283 {
5284 (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
5285 }
5286 }
5287
5288 /*
5289 * @implemented
5290 */
5291 VOID
5292 RxUpdateCondition(
5293 IN RX_BLOCK_CONDITION NewConditionValue,
5294 OUT PRX_BLOCK_CONDITION Condition,
5295 IN OUT PLIST_ENTRY TransitionWaitList)
5296 {
5297 PRX_CONTEXT Context;
5298 LIST_ENTRY SerializationQueue;
5299
5300 PAGED_CODE();
5301
5302 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
5303
5304 /* Set the new condition */
5305 RxAcquireSerializationMutex();
5306 ASSERT(NewConditionValue != Condition_InTransition);
5307 *Condition = NewConditionValue;
5308 /* And get the serialization queue for treatment */
5309 RxTransferList(&SerializationQueue, TransitionWaitList);
5310 RxReleaseSerializationMutex();
5311
5312 /* Handle the serialization queue */
5313 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
5314 while (Context != NULL)
5315 {
5316 /* If the caller asked for post, post the request */
5317 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
5318 {
5319 Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
5320 RxFsdPostRequest(Context);
5321 }
5322 /* Otherwise, wake up sleeping waiters */
5323 else
5324 {
5325 RxSignalSynchronousWaiter(Context);
5326 }
5327
5328 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
5329 }
5330 }
5331
5332 VOID
5333 RxVerifyOperationIsLegal(
5334 IN PRX_CONTEXT RxContext)
5335 {
5336 UNIMPLEMENTED;
5337 }
5338
5339 /*
5340 * @implemented
5341 */
5342 VOID
5343 RxWaitForStableCondition(
5344 IN PRX_BLOCK_CONDITION Condition,
5345 IN OUT PLIST_ENTRY TransitionWaitList,
5346 IN OUT PRX_CONTEXT RxContext,
5347 OUT NTSTATUS *AsyncStatus OPTIONAL)
5348 {
5349 BOOLEAN Wait;
5350 NTSTATUS LocalStatus;
5351
5352 PAGED_CODE();
5353
5354 /* Make sure to always get status */
5355 if (AsyncStatus == NULL)
5356 {
5357 AsyncStatus = &LocalStatus;
5358 }
5359
5360 /* By default, it's a success */
5361 *AsyncStatus = STATUS_SUCCESS;
5362
5363 Wait = FALSE;
5364 /* If it's not stable, we've to wait */
5365 if (!StableCondition(*Condition))
5366 {
5367 /* Lock the mutex */
5368 RxAcquireSerializationMutex();
5369 /* Still not stable? */
5370 if (!StableCondition(*Condition))
5371 {
5372 /* Insert us in the wait list for processing on stable condition */
5373 RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
5374
5375 /* If we're asked to post on stable, don't wait, and just return pending */
5376 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
5377 {
5378 *AsyncStatus = STATUS_PENDING;
5379 }
5380 else
5381 {
5382 Wait = TRUE;
5383 }
5384 }
5385 RxReleaseSerializationMutex();
5386
5387 /* We don't post on stable, so, just wait... */
5388 if (Wait)
5389 {
5390 RxWaitSync(RxContext);
5391 }
5392 }
5393 }
5394
5395 /*
5396 * @implemented
5397 */
5398 VOID
5399 NTAPI
5400 RxWorkItemDispatcher(
5401 PVOID Context)
5402 {
5403 PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
5404
5405 DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
5406
5407 DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
5408
5409 ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
5410 }
5411
5412 NTSTATUS
5413 __RxAcquireFcb(
5414 _Inout_ PFCB Fcb,
5415 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
5416 _In_ ULONG Mode
5417 #ifdef RDBSS_TRACKER
5418 ,
5419 _In_ ULONG LineNumber,
5420 _In_ PCSTR FileName,
5421 _In_ ULONG SerialNumber
5422 #endif
5423 )
5424 {
5425 NTSTATUS Status;
5426 BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
5427
5428 PAGED_CODE();
5429
5430 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
5431
5432 SpecialContext = FALSE;
5433 ContextIsPresent = FALSE;
5434 /* Check for special context */
5435 if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
5436 {
5437 SpecialContext = TRUE;
5438 }
5439
5440 /* We don't handle buffering state change yet... */
5441 if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
5442 BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
5443 {
5444 UNIMPLEMENTED;
5445 }
5446
5447 /* Nor special contexts */
5448 if (SpecialContext)
5449 {
5450 UNIMPLEMENTED;
5451 }
5452
5453 /* Nor missing contexts... */
5454 if (RxContext == NULL)
5455 {
5456 UNIMPLEMENTED;
5457 }
5458
5459 /* That said: we have a real context! */
5460 ContextIsPresent = TRUE;
5461
5462 /* If we've been cancelled in between, give up */
5463 Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
5464 if (!NT_SUCCESS(Status))
5465 {
5466 return Status;
5467 }
5468
5469 /* Can we wait? */
5470 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
5471
5472 while (TRUE)
5473 {
5474 /* Assume we cannot lock */
5475 Status = STATUS_LOCK_NOT_GRANTED;
5476
5477 /* Lock according to what the caller asked */
5478 switch (Mode)
5479 {
5480 case FCB_MODE_EXCLUSIVE:
5481 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
5482 break;
5483
5484 case FCB_MODE_SHARED:
5485 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
5486 break;
5487
5488 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
5489 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
5490 break;
5491
5492 default:
5493 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
5494 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
5495 break;
5496 }
5497
5498 /* Lock granted! */
5499 if (Acquired)
5500 {
5501 Status = STATUS_SUCCESS;
5502 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
5503
5504 /* Handle paging write - not implemented */
5505 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
5506 {
5507 UNIMPLEMENTED;
5508 }
5509 }
5510
5511 /* And break, that cool! */
5512 if (Acquired)
5513 {
5514 break;
5515 }
5516
5517 /* If it failed, return immediately */
5518 if (!NT_SUCCESS(Status))
5519 {
5520 return Status;
5521 }
5522 }
5523
5524 /* If we don't have to check for valid operation, job done, nothing more to do */
5525 if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
5526 {
5527 if (NT_SUCCESS(Status))
5528 {
5529 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
5530 }
5531
5532 return Status;
5533 }
5534
5535 /* Verify operation */
5536 _SEH2_TRY
5537 {
5538 RxVerifyOperationIsLegal(RxContext);
5539 }
5540 _SEH2_FINALLY
5541 {
5542 /* If it failed, release lock and fail */
5543 if (_SEH2_AbnormalTermination())
5544 {
5545 ExReleaseResourceLite(Fcb->Header.Resource);
5546 Status = STATUS_LOCK_NOT_GRANTED;
5547 }
5548 }
5549 _SEH2_END;
5550
5551 if (NT_SUCCESS(Status))
5552 {
5553 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
5554 }
5555
5556 DPRINT("Status: %x\n", Status);
5557 return Status;
5558 }
5559
5560 /*
5561 * @implemented
5562 */
5563 VOID
5564 __RxItsTheSameContext(
5565 _In_ PRX_CONTEXT RxContext,
5566 _In_ ULONG CapturedRxContextSerialNumber,
5567 _In_ ULONG Line,
5568 _In_ PCSTR File)
5569 {
5570 /* Check we have a context with the same serial number */
5571 if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
5572 RxContext->SerialNumber != CapturedRxContextSerialNumber)
5573 {
5574 /* Just be noisy */
5575 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
5576 }
5577 }
5578
5579 VOID
5580 __RxReleaseFcb(
5581 _Inout_opt_ PRX_CONTEXT RxContext,
5582 _Inout_ PMRX_FCB MrxFcb
5583 #ifdef RDBSS_TRACKER
5584 ,
5585 _In_ ULONG LineNumber,
5586 _In_ PCSTR FileName,
5587 _In_ ULONG SerialNumber
5588 #endif
5589 )
5590 {
5591 BOOLEAN IsExclusive, BufferingPending;
5592
5593 RxAcquireSerializationMutex();
5594
5595 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
5596 IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
5597
5598 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5599 * then just release the FCB
5600 */
5601 if (!BufferingPending || !IsExclusive)
5602 {
5603 RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
5604 LineNumber, FileName, SerialNumber);
5605 ExReleaseResourceLite(MrxFcb->Header.Resource);
5606 }
5607
5608 RxReleaseSerializationMutex();
5609
5610 /* And finally leave */
5611 if (!BufferingPending || !IsExclusive)
5612 {
5613 return;
5614 }
5615
5616 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
5617
5618 /* Otherwise, handle buffering state and release */
5619 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
5620
5621 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
5622 ExReleaseResourceLite(MrxFcb->Header.Resource);
5623 }
5624
5625 VOID
5626 __RxReleaseFcbForThread(
5627 _Inout_opt_ PRX_CONTEXT RxContext,
5628 _Inout_ PMRX_FCB MrxFcb,
5629 _In_ ERESOURCE_THREAD ResourceThreadId
5630 #ifdef RDBSS_TRACKER
5631 ,
5632 _In_ ULONG LineNumber,
5633 _In_ PCSTR FileName,
5634 _In_ ULONG SerialNumber
5635 #endif
5636 )
5637 {
5638 BOOLEAN IsExclusive, BufferingPending;
5639
5640 RxAcquireSerializationMutex();
5641
5642 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
5643 IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
5644
5645 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5646 * then just release the FCB
5647 */
5648 if (!BufferingPending || !IsExclusive)
5649 {
5650 RxTrackerUpdateHistory(RxContext, MrxFcb,
5651 (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
5652 LineNumber, FileName, SerialNumber);
5653 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
5654 }
5655
5656 RxReleaseSerializationMutex();
5657
5658 /* And finally leave */
5659 if (!BufferingPending || !IsExclusive)
5660 {
5661 return;
5662 }
5663
5664 /* Otherwise, handle buffering state and release */
5665 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
5666 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
5667 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
5668 }