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