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