c2c2b8118c2b5b10c020ce9557cca993f767f3f9
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <dfs.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 VOID
37 RxAssert(
38 PVOID Assert,
39 PVOID File,
40 ULONG Line,
41 PVOID Message);
42
43 VOID
44 NTAPI
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context);
47
48 NTSTATUS
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown);
51
52 VOID
53 NTAPI
54 RxFinishSrvCallConstructionDispatcher(
55 IN PVOID Context);
56
57 NTSTATUS
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60 WORK_QUEUE_TYPE WorkQueueType,
61 PRX_WORK_QUEUE_ITEM WorkQueueItem);
62
63 PVOID
64 RxNewMapUserBuffer(
65 PRX_CONTEXT RxContext);
66
67 VOID
68 NTAPI
69 RxpDestroySrvCall(
70 IN PVOID Context);
71
72 VOID
73 RxpDispatchChangeBufferingStateRequests(
74 PSRV_CALL SrvCall,
75 PSRV_OPEN SrvOpen,
76 PLIST_ENTRY DiscardedRequests);
77
78 VOID
79 NTAPI
80 RxScavengerTimerRoutine(
81 PVOID Context);
82
83 VOID
84 NTAPI
85 RxTimerDispatch(
86 _In_ struct _KDPC *Dpc,
87 _In_opt_ PVOID DeferredContext,
88 _In_opt_ PVOID SystemArgument1,
89 _In_opt_ PVOID SystemArgument2);
90
91 VOID
92 NTAPI
93 RxWorkItemDispatcher(
94 PVOID Context);
95
96 PVOID
97 NTAPI
98 _RxAllocatePoolWithTag(
99 _In_ POOL_TYPE PoolType,
100 _In_ SIZE_T NumberOfBytes,
101 _In_ ULONG Tag);
102
103 VOID
104 NTAPI
105 _RxFreePool(
106 _In_ PVOID Buffer);
107
108 VOID
109 NTAPI
110 _RxFreePoolWithTag(
111 _In_ PVOID Buffer,
112 _In_ ULONG Tag);
113
114 extern ULONG ReadAheadGranularity;
115
116 volatile LONG RxNumberOfActiveFcbs = 0;
117 ULONG SerialNumber = 1;
118 PVOID RxNull = NULL;
119 volatile ULONG RxContextSerialNumberCounter;
120 BOOLEAN RxStopOnLoudCompletion = TRUE;
121 BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
122 LIST_ENTRY RxSrvCalldownList;
123 RX_SPIN_LOCK RxStrucSupSpinLock;
124 #if 0
125 ULONG RdbssReferenceTracingValue = (RDBSS_REF_TRACK_SRVCALL | RDBSS_REF_TRACK_NETROOT |
126 RDBSS_REF_TRACK_VNETROOT | RDBSS_REF_TRACK_NETFOBX |
127 RDBSS_REF_TRACK_NETFCB | RDBSS_REF_TRACK_SRVOPEN |
128 RX_PRINT_REF_TRACKING);
129 #else
130 ULONG RdbssReferenceTracingValue = 0;
131 #endif
132 LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
133 LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
134 RX_DISPATCHER RxDispatcher;
135 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
136 FAST_MUTEX RxLowIoPagingIoSyncMutex;
137 BOOLEAN RxContinueFromAssert = TRUE;
138 ULONG RxExplodePoolTags = 1;
139 LARGE_INTEGER RxTimerInterval;
140 RX_SPIN_LOCK RxTimerLock;
141 LIST_ENTRY RxTimerQueueHead;
142 LIST_ENTRY RxRecurrentWorkItemsList;
143 KDPC RxTimerDpc;
144 KTIMER RxTimer;
145 ULONG RxTimerTickCount;
146 #if DBG
147 BOOLEAN DumpDispatchRoutine = TRUE;
148 #else
149 BOOLEAN DumpDispatchRoutine = FALSE;
150 #endif
151
152 #if RDBSS_ASSERTS
153 #ifdef ASSERT
154 #undef ASSERT
155 #endif
156
157 #define ASSERT(exp) \
158 if (!(exp)) \
159 { \
160 RxAssert(#exp, __FILE__, __LINE__, NULL); \
161 }
162 #endif
163
164 #if RX_POOL_WRAPPER
165 #undef RxAllocatePool
166 #undef RxAllocatePoolWithTag
167 #undef RxFreePool
168
169 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
170 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
171 #define RxFreePool _RxFreePool
172 #define RxFreePoolWithTag _RxFreePoolWithTag
173 #endif
174
175 /* FUNCTIONS ****************************************************************/
176
177 NTSTATUS
178 NTAPI
179 RxAcquireExclusiveFcbResourceInMRx(
180 _Inout_ PMRX_FCB Fcb)
181 {
182 UNIMPLEMENTED;
183 return STATUS_NOT_IMPLEMENTED;
184 }
185
186 /*
187 * @implemented
188 */
189 BOOLEAN
190 NTAPI
191 RxAcquireFcbForLazyWrite(
192 PVOID Context,
193 BOOLEAN Wait)
194 {
195 PFCB Fcb;
196 BOOLEAN Ret;
197
198 PAGED_CODE();
199
200 Fcb = Context;
201 /* The received context is a FCB */
202 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
203 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
204 ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
205
206 /* Acquire the paging resource (shared) */
207 Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
208 if (Ret)
209 {
210 /* Update tracker information */
211 Fcb->PagingIoResourceFile = __FILE__;
212 Fcb->PagingIoResourceLine = __LINE__;
213 /* Lazy writer thread is the current one */
214 Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
215
216 /* There is no top level IRP */
217 ASSERT(RxIsThisTheTopLevelIrp(NULL));
218 /* Now, there will be! */
219 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
220 Fcb->RxDeviceObject, TRUE);
221 /* In case of failure, release the lock and reset everything */
222 if (!Ret)
223 {
224 Fcb->PagingIoResourceFile = NULL;
225 Fcb->PagingIoResourceLine = 0;
226 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
227 Fcb->Specific.Fcb.LazyWriteThread = NULL;
228 }
229 }
230
231 return Ret;
232 }
233
234 /*
235 * @implemented
236 */
237 BOOLEAN
238 NTAPI
239 RxAcquireFcbForReadAhead(
240 PVOID Context,
241 BOOLEAN Wait)
242 {
243 PFCB Fcb;
244 BOOLEAN Ret;
245
246 PAGED_CODE();
247
248 Fcb = Context;
249 /* The received context is a FCB */
250 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
251 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
252
253 Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
254 if (Ret)
255 {
256 /* There is no top level IRP */
257 ASSERT(RxIsThisTheTopLevelIrp(NULL));
258 /* Now, there will be! */
259 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
260 Fcb->RxDeviceObject, TRUE);
261 /* In case of failure, release the lock and reset everything */
262 if (!Ret)
263 {
264 ExReleaseResourceLite(Fcb->Header.Resource);
265 }
266 }
267
268 return Ret;
269 }
270
271 VOID
272 NTAPI
273 RxAcquireFileForNtCreateSection(
274 PFILE_OBJECT FileObject)
275 {
276 UNIMPLEMENTED;
277 }
278
279 NTSTATUS
280 NTAPI
281 RxAcquireForCcFlush(
282 PFILE_OBJECT FileObject,
283 PDEVICE_OBJECT DeviceObject)
284 {
285 UNIMPLEMENTED;
286 return STATUS_NOT_IMPLEMENTED;
287 }
288
289 /*
290 * @implemented
291 */
292 VOID
293 RxAddVirtualNetRootToNetRoot(
294 PNET_ROOT NetRoot,
295 PV_NET_ROOT VNetRoot)
296 {
297 PAGED_CODE();
298
299 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
300
301 /* Insert in the VNetRoot list - make sure lock is held */
302 ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
303
304 VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
305 ++NetRoot->NumberOfVirtualNetRoots;
306 InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
307 }
308
309 /*
310 * @implemented
311 */
312 PVOID
313 RxAllocateFcbObject(
314 PRDBSS_DEVICE_OBJECT RxDeviceObject,
315 NODE_TYPE_CODE NodeType,
316 POOL_TYPE PoolType,
317 ULONG NameSize,
318 PVOID AlreadyAllocatedObject)
319 {
320 PFCB Fcb;
321 PFOBX Fobx;
322 PSRV_OPEN SrvOpen;
323 PVOID Buffer, PAPNBuffer;
324 PNON_PAGED_FCB NonPagedFcb;
325 PMINIRDR_DISPATCH Dispatch;
326 ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
327
328 PAGED_CODE();
329
330 Dispatch = RxDeviceObject->Dispatch;
331
332 NonPagedSize = 0;
333 FobxSize = 0;
334 SrvOpenSize = 0;
335 FcbSize = 0;
336
337 Fcb = NULL;
338 Fobx = NULL;
339 SrvOpen = NULL;
340 NonPagedFcb = NULL;
341 PAPNBuffer = NULL;
342
343 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
344 if (NodeType == RDBSS_NTC_FOBX)
345 {
346 FobxSize = sizeof(FOBX);
347 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
348 {
349 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
350 }
351 }
352 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
353 else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
354 {
355 SrvOpenSize = sizeof(SRV_OPEN);
356 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
357 {
358 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
359 }
360
361 FobxSize = sizeof(FOBX);
362 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
363 {
364 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
365 }
366 }
367 /* Otherwise, we're asked to allocate a FCB */
368 else
369 {
370 /* So, allocate the FCB and its extension if asked */
371 FcbSize = sizeof(FCB);
372 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
373 {
374 FcbSize += QuadAlign(Dispatch->MRxFcbSize);
375 }
376
377 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
378 * Otherwise, it will be allocated later on, specifically
379 */
380 if (PoolType == NonPagedPool)
381 {
382 NonPagedSize = sizeof(NON_PAGED_FCB);
383 }
384
385 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
386 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
387 {
388 SrvOpenSize = sizeof(SRV_OPEN);
389 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
390 {
391 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
392 }
393
394 FobxSize = sizeof(FOBX);
395 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
396 {
397 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
398 }
399 }
400 }
401
402 /* If we already have a buffer, go ahead */
403 if (AlreadyAllocatedObject != NULL)
404 {
405 Buffer = AlreadyAllocatedObject;
406 }
407 /* Otherwise, allocate it */
408 else
409 {
410 Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
411 if (Buffer == NULL)
412 {
413 return NULL;
414 }
415 }
416
417 /* Now, get the pointers - FOBX is easy */
418 if (NodeType == RDBSS_NTC_FOBX)
419 {
420 Fobx = Buffer;
421 }
422 /* SRV_OPEN first, FOBX next */
423 else if (NodeType == RDBSS_NTC_SRVOPEN)
424 {
425 SrvOpen = Buffer;
426 Fobx = Add2Ptr(Buffer, SrvOpenSize);
427 }
428 else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
429 {
430 SrvOpen = Buffer;
431 }
432 else
433 {
434 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
435 Fcb = Buffer;
436 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
437 {
438 SrvOpen = Add2Ptr(Buffer, FcbSize);
439 Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
440 }
441
442 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
443 if (PoolType != NonPagedPool)
444 {
445 NonPagedFcb = RxAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
446 if (NonPagedFcb == NULL)
447 {
448 RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
449 return NULL;
450 }
451
452 PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
453 }
454 /* Otherwise, just point at the right place in what has been allocated previously */
455 else
456 {
457 NonPagedFcb = Add2Ptr(Fobx, FobxSize);
458 PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
459 }
460 }
461
462 /* If we have allocated a SRV_OPEN, initialize it */
463 if (SrvOpen != NULL)
464 {
465 ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
466
467 if (NodeType == RDBSS_NTC_SRVOPEN)
468 {
469 SrvOpen->InternalFobx = Fobx;
470 }
471 else
472 {
473 SrvOpen->InternalFobx = NULL;
474 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
475 }
476
477 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
478 {
479 SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
480 }
481
482 InitializeListHead(&SrvOpen->SrvOpenQLinks);
483 }
484
485 /* If we have allocated a FOBX, initialize it */
486 if (Fobx != NULL)
487 {
488 ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
489
490 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
491 {
492 Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
493 }
494 }
495
496 /* If we have allocated a FCB, initialize it */
497 if (Fcb != NULL)
498 {
499 ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
500
501 Fcb->NonPaged = NonPagedFcb;
502 ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
503 #if DBG
504 Fcb->CopyOfNonPaged = NonPagedFcb;
505 NonPagedFcb->FcbBackPointer = Fcb;
506 #endif
507
508 Fcb->InternalSrvOpen = SrvOpen;
509 Fcb->InternalFobx = Fobx;
510
511 Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
512 Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
513 Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
514
515 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
516 {
517 Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
518 }
519
520 ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
521
522 InterlockedIncrement(&RxNumberOfActiveFcbs);
523 InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
524
525 ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
526 FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
527 }
528
529 DPRINT("Allocated %p\n", Buffer);
530
531 return Buffer;
532 }
533
534 /*
535 * @implemented
536 */
537 PVOID
538 RxAllocateObject(
539 NODE_TYPE_CODE NodeType,
540 PMINIRDR_DISPATCH MRxDispatch,
541 ULONG NameLength)
542 {
543 ULONG Tag, ObjectSize;
544 PVOID Object, *Extension;
545 PRX_PREFIX_ENTRY PrefixEntry;
546 USHORT StructSize, ExtensionSize;
547
548 PAGED_CODE();
549
550 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
551 ExtensionSize = 0;
552 switch (NodeType)
553 {
554 case RDBSS_NTC_SRVCALL:
555 Tag = RX_SRVCALL_POOLTAG;
556 StructSize = sizeof(SRV_CALL);
557 if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
558 {
559 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
560 }
561 break;
562
563 case RDBSS_NTC_NETROOT:
564 Tag = RX_NETROOT_POOLTAG;
565 StructSize = sizeof(NET_ROOT);
566 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
567 {
568 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
569 }
570 break;
571
572 case RDBSS_NTC_V_NETROOT:
573 Tag = RX_V_NETROOT_POOLTAG;
574 StructSize = sizeof(V_NET_ROOT);
575 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
576 {
577 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
578 }
579 break;
580
581 default:
582 ASSERT(FALSE);
583 break;
584 }
585
586 /* Now, allocate the object */
587 ObjectSize = ExtensionSize + StructSize + NameLength;
588 Object = RxAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
589 if (Object == NULL)
590 {
591 return NULL;
592 }
593 /* Initialize it */
594 ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
595
596 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
597 switch (NodeType)
598 {
599 case RDBSS_NTC_SRVCALL:
600 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
601 Extension = &((PSRV_CALL)Object)->Context;
602 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
603 break;
604
605 case RDBSS_NTC_NETROOT:
606 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
607 Extension = &((PNET_ROOT)Object)->Context;
608 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
609 break;
610
611 case RDBSS_NTC_V_NETROOT:
612 PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
613 Extension = &((PV_NET_ROOT)Object)->Context;
614 break;
615
616 default:
617 ASSERT(FALSE);
618 break;
619 }
620
621 /* Set the prefix table unicode string */
622 RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
623 PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
624 PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
625 PrefixEntry->Prefix.Length = NameLength;
626 PrefixEntry->Prefix.MaximumLength = NameLength;
627 PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
628
629 /* Return the extension if we are asked to manage it */
630 if (ExtensionSize != 0)
631 {
632 *Extension = Add2Ptr(Object, StructSize);
633 }
634
635 return Object;
636 }
637
638 /*
639 * @implemented
640 */
641 VOID
642 RxAssert(
643 PVOID Assert,
644 PVOID File,
645 ULONG Line,
646 PVOID Message)
647 {
648 CHAR Response[2];
649 CONTEXT Context;
650
651 /* If we're not asked to continue, just stop the system */
652 if (!RxContinueFromAssert)
653 {
654 KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
655 }
656
657 /* Otherwise, capture context to offer the user to dump it */
658 RtlCaptureContext(&Context);
659
660 /* Loop until the user hits 'i' */
661 while (TRUE)
662 {
663 /* If no file provided, use empty name */
664 if (File == NULL)
665 {
666 File = "";
667 }
668
669 /* If no message provided, use empty one */
670 if (Message == NULL)
671 {
672 Message = "";
673 }
674
675 /* Display the message */
676 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
677 /* And ask the user */
678 DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
679 /* If he asks for ignore, quit
680 * In case of invalid input, ask again
681 */
682 if (Response[0] != 'B' && Response[0] != 'b')
683 {
684 if (Response[0] == 'I' || Response[0] == 'i')
685 {
686 return;
687 }
688
689 continue;
690 }
691
692 /* Break: offer the user to dump the context and break */
693 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
694 DbgBreakPoint();
695
696 /* Continue looping, so that after dump, execution can continue (with ignore) */
697 }
698 }
699
700 /*
701 * @implemented
702 */
703 VOID
704 NTAPI
705 RxBootstrapWorkerThreadDispatcher(
706 IN PVOID WorkQueue)
707 {
708 PRX_WORK_QUEUE RxWorkQueue;
709
710 PAGED_CODE();
711
712 RxWorkQueue = WorkQueue;
713 RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
714 }
715
716 /*
717 * @implemented
718 */
719 NTSTATUS
720 NTAPI
721 RxChangeBufferingState(
722 PSRV_OPEN SrvOpen,
723 PVOID Context,
724 BOOLEAN ComputeNewState)
725 {
726 PFCB Fcb;
727 NTSTATUS Status, MiniStatus;
728 ULONG NewBufferingState, OldBufferingState;
729
730 PAGED_CODE();
731
732 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
733
734 Fcb = (PFCB)SrvOpen->pFcb;
735 ASSERT(NodeTypeIsFcb(Fcb));
736 /* First of all, mark that buffering state is changing */
737 SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
738
739 /* Assume success */
740 Status = STATUS_SUCCESS;
741 _SEH2_TRY
742 {
743 /* If we're asked to compute a new state, ask the mini-rdr for it */
744 if (ComputeNewState)
745 {
746 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
747 ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
748 if (MiniStatus != STATUS_SUCCESS)
749 {
750 NewBufferingState = 0;
751 }
752 }
753 else
754 {
755 /* If not, use SRV_OPEN state */
756 NewBufferingState = SrvOpen->BufferingFlags;
757 }
758
759 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
760 if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
761 {
762 SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
763 }
764
765 /* If there's a lock operation to complete, clear that flag */
766 if (Fcb->OutstandingLockOperationsCount != 0)
767 {
768 ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
769 }
770
771 /* Get the old state */
772 OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
773 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
774
775 /* If we're dropping write cache, then flush the FCB */
776 if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
777 !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
778 {
779 DPRINT("Flushing\n");
780
781 Status = RxFlushFcbInSystemCache(Fcb, TRUE);
782 }
783
784 /* If we're dropping read cache, then purge */
785 if (Fcb->UncleanCount == 0 ||
786 (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
787 !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
788 BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
789 {
790 DPRINT("Purging\n");
791
792 if (!NT_SUCCESS(Status))
793 {
794 DPRINT("Previous flush failed with status: %lx\n", Status);
795 }
796
797 CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE);
798 }
799
800 /* If there's already a change pending in SRV_OPEN */
801 if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
802 {
803 /* If there's a FOBX at least */
804 if (!IsListEmpty(&SrvOpen->FobxList))
805 {
806 PRX_CONTEXT RxContext;
807
808 /* Create a fake context to pass to the mini-rdr */
809 RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
810 if (RxContext != NULL)
811 {
812 PFOBX Fobx;
813
814 RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
815
816 /* Give the first FOBX */
817 Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
818 RxContext->pFobx = (PMRX_FOBX)Fobx;
819 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
820
821 /* If there was a delayed close, perform it */
822 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
823 {
824 DPRINT("Oplock break close for %p\n", SrvOpen);
825
826 RxCloseAssociatedSrvOpen(Fobx, RxContext);
827 }
828 /* Otherwise, inform the mini-rdr about completion */
829 else
830 {
831 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
832 (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
833 (void)MiniStatus;
834 }
835
836 RxDereferenceAndDeleteRxContext(RxContext);
837 }
838 }
839 }
840
841 /* Set the new state */
842 Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
843 }
844 _SEH2_FINALLY
845 {
846 /* Job done, clear the flag */
847 ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
848
849 if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
850 {
851 ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
852 }
853 }
854 _SEH2_END;
855
856 return Status;
857 }
858
859 NTSTATUS
860 RxCheckVNetRootCredentials(
861 PRX_CONTEXT RxContext,
862 PV_NET_ROOT VNetRoot,
863 PLUID LogonId,
864 PUNICODE_STRING UserName,
865 PUNICODE_STRING UserDomain,
866 PUNICODE_STRING Password,
867 ULONG Flags)
868 {
869 PAGED_CODE();
870
871 /* If that's a UNC name, there's nothing to process */
872 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
873 (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
874 Flags != 0))
875 {
876 return STATUS_MORE_PROCESSING_REQUIRED;
877 }
878
879 /* Compare the logon ID in the VNetRoot with the one provided */
880 if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
881 {
882 return STATUS_MORE_PROCESSING_REQUIRED;
883 }
884
885 /* No credential provided? That's OK */
886 if (UserName == NULL && UserDomain == NULL && Password == NULL)
887 {
888 return STATUS_SUCCESS;
889 }
890
891 /* Left to do! */
892 UNIMPLEMENTED;
893 return STATUS_NOT_IMPLEMENTED;
894 }
895
896 NTSTATUS
897 RxCompleteRequest(
898 PRX_CONTEXT Context,
899 NTSTATUS Status)
900 {
901 PIRP Irp;
902
903 PAGED_CODE();
904
905 DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
906
907 ASSERT(Context != NULL);
908 ASSERT(Context->CurrentIrp != NULL);
909 Irp = Context->CurrentIrp;
910
911 /* Debug what the caller asks for */
912 if (Context->LoudCompletionString != NULL)
913 {
914 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
915 /* Does the user asks to stop on failed completion */
916 if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
917 {
918 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
919 }
920 }
921
922 /* Complete for real */
923 Context->CurrentIrp = NULL;
924 RxCompleteRequest_Real(Context, Irp, Status);
925
926 DPRINT("Status: %lx\n", Status);
927 return Status;
928 }
929
930 /*
931 * @implemented
932 */
933 VOID
934 RxCompleteRequest_Real(
935 IN PRX_CONTEXT RxContext,
936 IN PIRP Irp,
937 IN NTSTATUS Status)
938 {
939 CCHAR Boost;
940 KIRQL OldIrql;
941 PIO_STACK_LOCATION Stack;
942
943 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
944
945 /* Nothing to complete, just free context */
946 if (Irp == NULL)
947 {
948 DPRINT("NULL IRP for %p\n", RxContext);
949 if (RxContext != NULL)
950 {
951 RxDereferenceAndDeleteRxContext_Real(RxContext);
952 }
953
954 return;
955 }
956
957 /* Remove cancel routine */
958 IoAcquireCancelSpinLock(&OldIrql);
959 IoSetCancelRoutine(Irp, NULL);
960 IoReleaseCancelSpinLock(OldIrql);
961
962 /* Select the boost, given the success/paging operation */
963 if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
964 {
965 Boost = IO_DISK_INCREMENT;
966 }
967 else
968 {
969 Irp->IoStatus.Information = 0;
970 Boost = IO_NO_INCREMENT;
971 }
972 Irp->IoStatus.Status = Status;
973
974 if (RxContext != NULL)
975 {
976 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
977 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
978 {
979 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
980 RxContext->MinorFunction, RxContext, Irp,
981 Status, Irp->IoStatus.Information, RxContext->SerialNumber);
982 }
983 }
984
985 /* If that's an opening, there might be a canonical name allocated,
986 * if completion isn't pending, release it
987 */
988 Stack = IoGetCurrentIrpStackLocation(Irp);
989 if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
990 RxContext != NULL)
991 {
992 if (BooleanFlagOn(RxContext->Create.Flags, 2))
993 {
994 Stack->FileObject->FileName.Length += sizeof(WCHAR);
995 }
996
997 RxpPrepareCreateContextForReuse(RxContext);
998 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
999 }
1000
1001 /* If it's a write, validate the correct behavior of the operation */
1002 if (Stack->MajorFunction == IRP_MJ_WRITE)
1003 {
1004 if (NT_SUCCESS(Irp->IoStatus.Status))
1005 {
1006 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
1007 }
1008 }
1009
1010 /* If it's pending, make sure IRP is marked as such */
1011 if (RxContext != NULL)
1012 {
1013 if (RxContext->PendingReturned)
1014 {
1015 ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
1016 }
1017 }
1018
1019 /* Complete now */
1020 DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
1021 IoCompleteRequest(Irp, Boost);
1022
1023 /* If there's a context, dereference it */
1024 if (RxContext != NULL)
1025 {
1026 RxDereferenceAndDeleteRxContext_Real(RxContext);
1027 }
1028 }
1029
1030 /*
1031 * @implemented
1032 */
1033 VOID
1034 RxCompleteSrvOpenKeyAssociation(
1035 IN OUT PSRV_OPEN SrvOpen)
1036 {
1037 PSRV_CALL SrvCall;
1038
1039 SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall;
1040 /* Only handle requests if opening was a success */
1041 if (SrvOpen->Condition == Condition_Good)
1042 {
1043 KIRQL OldIrql;
1044 BOOLEAN ProcessChange;
1045 LIST_ENTRY DiscardedRequests;
1046
1047 /* Initialize our discarded requests list */
1048 InitializeListHead(&DiscardedRequests);
1049
1050 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
1051
1052 /* Transfer our requests in the SRV_CALL */
1053 RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList);
1054
1055 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1056 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1057
1058 /* Dispatch requests and get the discarded ones */
1059 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests);
1060
1061 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
1062
1063 /* Is there still anything to process? */
1064 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
1065 if (IsListEmpty(&SrvCall->BufferingManager.HandlerList))
1066 {
1067 ProcessChange = FALSE;
1068 }
1069 else
1070 {
1071 ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE);
1072 if (ProcessChange)
1073 {
1074 SrvCall->BufferingManager.HandlerInactive = TRUE;
1075 }
1076 }
1077 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
1078
1079 /* Yes? Go ahead! */
1080 if (ProcessChange)
1081 {
1082 RxReferenceSrvCall(SrvCall);
1083 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
1084 &SrvCall->BufferingManager.HandlerWorkItem,
1085 RxProcessChangeBufferingStateRequests, SrvCall);
1086 }
1087
1088 /* And discard left requests */
1089 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
1090 }
1091 else
1092 {
1093 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1094 }
1095 }
1096
1097 /*
1098 * @implemented
1099 */
1100 NTSTATUS
1101 RxConstructNetRoot(
1102 IN PRX_CONTEXT RxContext,
1103 IN PSRV_CALL SrvCall,
1104 IN PNET_ROOT NetRoot,
1105 IN PV_NET_ROOT VirtualNetRoot,
1106 OUT PLOCK_HOLDING_STATE LockHoldingState)
1107 {
1108 NTSTATUS Status;
1109 PRX_PREFIX_TABLE PrefixTable;
1110 PMRX_CREATENETROOT_CONTEXT Context;
1111 RX_BLOCK_CONDITION RootCondition, VRootCondition;
1112
1113 PAGED_CODE();
1114
1115 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
1116 VirtualNetRoot, LockHoldingState);
1117
1118 /* Validate the lock is exclusively held */
1119 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
1120 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1121
1122 /* Allocate the context */
1123 Context = RxAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
1124 if (Context == NULL)
1125 {
1126 return STATUS_INSUFFICIENT_RESOURCES;
1127 }
1128
1129 /* We can release lock now */
1130 RxReleasePrefixTableLock(PrefixTable);
1131 *LockHoldingState = LHS_LockNotHeld;
1132
1133 RootCondition = Condition_Bad;
1134 VRootCondition = Condition_Bad;
1135
1136 /* Initialize the context */
1137 RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
1138 KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
1139 Context->RxContext = RxContext;
1140 Context->pVNetRoot = VirtualNetRoot;
1141 Context->Callback = RxCreateNetRootCallBack;
1142
1143 /* And call the mini-rdr */
1144 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
1145 if (Status == STATUS_PENDING)
1146 {
1147 /* Wait for the mini-rdr to be done */
1148 KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
1149 /* Update the structures condition according to mini-rdr return */
1150 if (NT_SUCCESS(Context->NetRootStatus))
1151 {
1152 if (NT_SUCCESS(Context->VirtualNetRootStatus))
1153 {
1154 RootCondition = Condition_Good;
1155 VRootCondition = Condition_Good;
1156 Status = STATUS_SUCCESS;
1157 }
1158 else
1159 {
1160 RootCondition = Condition_Good;
1161 Status = Context->VirtualNetRootStatus;
1162 }
1163 }
1164 else
1165 {
1166 Status = Context->VirtualNetRootStatus;
1167 if (NT_SUCCESS(Status))
1168 {
1169 Status = Context->NetRootStatus;
1170 }
1171 }
1172 }
1173 else
1174 {
1175 /* It has to return STATUS_PENDING! */
1176 ASSERT(FALSE);
1177 }
1178
1179 /* Acquire lock again - for caller lock status will remain unchanged */
1180 ASSERT(*LockHoldingState == LHS_LockNotHeld);
1181 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
1182 *LockHoldingState = LHS_ExclusiveLockHeld;
1183
1184 /* Do the transition to the condition got from mini-rdr */
1185 RxTransitionNetRoot(NetRoot, RootCondition);
1186 RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
1187
1188 /* Context is not longer needed */
1189 RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
1190
1191 DPRINT("Status: %x\n", Status);
1192
1193 return Status;
1194 }
1195
1196 /*
1197 * @implemented
1198 */
1199 NTSTATUS
1200 RxConstructSrvCall(
1201 IN PRX_CONTEXT RxContext,
1202 IN PSRV_CALL SrvCall,
1203 OUT PLOCK_HOLDING_STATE LockHoldingState)
1204 {
1205 NTSTATUS Status;
1206 PRX_PREFIX_TABLE PrefixTable;
1207 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1208 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1209 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
1210
1211 PAGED_CODE();
1212
1213 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
1214
1215 /* Validate the lock is exclusively held */
1216 RxDeviceObject = RxContext->RxDeviceObject;
1217 PrefixTable = RxDeviceObject->pRxNetNameTable;
1218 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1219
1220 /* Allocate the context for mini-rdr */
1221 Calldown = RxAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
1222 if (Calldown == NULL)
1223 {
1224 SrvCall->Context = NULL;
1225 SrvCall->Condition = Condition_Bad;
1226 RxReleasePrefixTableLock(PrefixTable);
1227 *LockHoldingState = LHS_LockNotHeld;
1228 return STATUS_INSUFFICIENT_RESOURCES;
1229 }
1230
1231 /* Initialize it */
1232 RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
1233
1234 SrvCall->Context = NULL;
1235 SrvCall->Condition = Condition_InTransition;
1236
1237 RxReleasePrefixTableLock(PrefixTable);
1238 *LockHoldingState = LHS_LockNotHeld;
1239
1240 CallbackContext = &Calldown->CallbackContexts[0];
1241 DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
1242 DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
1243 CallbackContext->SrvCalldownStructure = Calldown;
1244 CallbackContext->CallbackContextOrdinal = 0;
1245 CallbackContext->RxDeviceObject = RxDeviceObject;
1246
1247 RxReferenceSrvCall(SrvCall);
1248
1249 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1250 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1251 {
1252 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
1253 }
1254 else
1255 {
1256 KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
1257 }
1258
1259 Calldown->NumberToWait = 1;
1260 Calldown->NumberRemaining = 1;
1261 Calldown->RxContext = RxContext;
1262 Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
1263 Calldown->CallBack = RxCreateSrvCallCallBack;
1264 Calldown->BestFinisher = NULL;
1265 CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
1266 InitializeListHead(&Calldown->SrvCalldownList);
1267
1268 /* Call the mini-rdr */
1269 ASSERT(RxDeviceObject->Dispatch != NULL);
1270 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
1271 ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
1272 Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
1273 /* It has to return STATUS_PENDING! */
1274 ASSERT(Status == STATUS_PENDING);
1275
1276 /* No async, start completion */
1277 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1278 {
1279 KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
1280
1281 /* Finish construction - we'll notify mini-rdr it's the winner */
1282 Status = RxFinishSrvCallConstruction(Calldown);
1283 if (!NT_SUCCESS(Status))
1284 {
1285 RxReleasePrefixTableLock(PrefixTable);
1286 *LockHoldingState = LHS_LockNotHeld;
1287 }
1288 else
1289 {
1290 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
1291 *LockHoldingState = LHS_ExclusiveLockHeld;
1292 }
1293 }
1294
1295 DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
1296 return Status;
1297 }
1298
1299 /*
1300 * @implemented
1301 */
1302 NTSTATUS
1303 RxConstructVirtualNetRoot(
1304 IN PRX_CONTEXT RxContext,
1305 IN PUNICODE_STRING CanonicalName,
1306 IN NET_ROOT_TYPE NetRootType,
1307 OUT PV_NET_ROOT *VirtualNetRootPointer,
1308 OUT PLOCK_HOLDING_STATE LockHoldingState,
1309 OUT PRX_CONNECTION_ID RxConnectionId)
1310 {
1311 NTSTATUS Status;
1312 PV_NET_ROOT VNetRoot;
1313 RX_BLOCK_CONDITION Condition;
1314 UNICODE_STRING LocalNetRootName, FilePathName;
1315
1316 PAGED_CODE();
1317
1318 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1319
1320 VNetRoot = NULL;
1321 Condition = Condition_Bad;
1322 /* Before creating the VNetRoot, try to find the appropriate connection */
1323 Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
1324 &LocalNetRootName, &FilePathName,
1325 LockHoldingState, RxConnectionId);
1326 /* Found and active */
1327 if (Status == STATUS_CONNECTION_ACTIVE)
1328 {
1329 /* We need a new VNetRoot */
1330 VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
1331 CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
1332 if (VNetRoot != NULL)
1333 {
1334 RxReferenceVNetRoot(VNetRoot);
1335 }
1336
1337 /* Dereference previous VNetRoot */
1338 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
1339 /* Reset and start construct (new structures will replace old ones) */
1340 RxContext->Create.pSrvCall = NULL;
1341 RxContext->Create.pNetRoot = NULL;
1342 RxContext->Create.pVNetRoot = NULL;
1343
1344 /* Construct new NetRoot */
1345 if (VNetRoot != NULL)
1346 {
1347 Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
1348 (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
1349 if (NT_SUCCESS(Status))
1350 {
1351 Condition = Condition_Good;
1352 }
1353 }
1354 else
1355 {
1356 Status = STATUS_INSUFFICIENT_RESOURCES;
1357 }
1358 }
1359 else
1360 {
1361 /* If it failed creating the connection, leave */
1362 if (Status != STATUS_SUCCESS)
1363 {
1364 if (*LockHoldingState != LHS_LockNotHeld)
1365 {
1366 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1367 *LockHoldingState = LHS_LockNotHeld;
1368 }
1369
1370 *VirtualNetRootPointer = VNetRoot;
1371 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
1372 return Status;
1373 }
1374
1375 *LockHoldingState = LHS_ExclusiveLockHeld;
1376
1377 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
1378 Condition = Condition_Good;
1379 }
1380
1381 /* We have a non stable VNetRoot - transition it */
1382 if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
1383 {
1384 RxTransitionVNetRoot(VNetRoot, Condition);
1385 }
1386
1387 /* If recreation failed */
1388 if (Status != STATUS_SUCCESS)
1389 {
1390 /* Dereference potential VNetRoot */
1391 if (VNetRoot != NULL)
1392 {
1393 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1394 RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1395 VNetRoot = NULL;
1396 }
1397
1398 /* Release lock */
1399 if (*LockHoldingState != LHS_LockNotHeld)
1400 {
1401 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1402 *LockHoldingState = LHS_LockNotHeld;
1403 }
1404
1405 /* Set NULL ptr */
1406 *VirtualNetRootPointer = VNetRoot;
1407 return Status;
1408 }
1409
1410 /* Return the allocated VNetRoot */
1411 *VirtualNetRootPointer = VNetRoot;
1412 return Status;
1413 }
1414
1415 /*
1416 * @implemented
1417 */
1418 PFCB
1419 RxCreateNetFcb(
1420 IN PRX_CONTEXT RxContext,
1421 IN PV_NET_ROOT VNetRoot,
1422 IN PUNICODE_STRING Name)
1423 {
1424 PFCB Fcb;
1425 BOOLEAN FakeFcb;
1426 PNET_ROOT NetRoot;
1427 POOL_TYPE PoolType;
1428 NODE_TYPE_CODE NodeType;
1429 PIO_STACK_LOCATION Stack;
1430 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1431
1432 PAGED_CODE();
1433
1434 /* We need a decent VNetRoot */
1435 ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1436
1437 NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1438 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1439 ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1440
1441 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1442 ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1443
1444 Stack = RxContext->CurrentIrpSp;
1445
1446 /* Do we need to create a fake FCB? Like for renaming */
1447 FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1448 !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
1449 ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1450
1451 PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
1452 NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
1453
1454 /* Allocate the FCB */
1455 Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1456 NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1457 if (Fcb == NULL)
1458 {
1459 return NULL;
1460 }
1461
1462 /* Initialize the FCB */
1463 Fcb->CachedNetRootType = NetRoot->Type;
1464 Fcb->RxDeviceObject = RxDeviceObject;
1465 Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1466 Fcb->VNetRoot = VNetRoot;
1467 Fcb->pNetRoot = VNetRoot->pNetRoot;
1468
1469 InitializeListHead(&Fcb->SrvOpenList);
1470 Fcb->SrvOpenListVersion = 0;
1471
1472 Fcb->FcbTableEntry.Path.Length = Name->Length;
1473 Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
1474 Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1475 RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1476 NetRoot->InnerNamePrefix.Length);
1477 RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1478
1479 /* Copy back parameters from RxContext */
1480 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1481 {
1482 Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
1483 }
1484
1485 InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
1486
1487 if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
1488 {
1489 Fcb->FcbState |= FCB_STATE_PAGING_FILE;
1490 }
1491
1492 if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1493 {
1494 Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
1495 }
1496
1497 Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1498 ExInitializeResourceLite(Fcb->Header.Resource);
1499
1500 Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1501 ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1502
1503 Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
1504 ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
1505
1506 /* Fake FCB doesn't go in prefix table */
1507 if (FakeFcb)
1508 {
1509 Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
1510 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
1511 DPRINT("Fake FCB: %p\n", Fcb);
1512 }
1513 else
1514 {
1515 RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1516 }
1517
1518 RxReferenceVNetRoot(VNetRoot);
1519 InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1520
1521 Fcb->ulFileSizeVersion = 0;
1522
1523 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1524 RxReferenceNetFcb(Fcb);
1525
1526 return Fcb;
1527 }
1528
1529 /*
1530 * @implemented
1531 */
1532 PMRX_FOBX
1533 NTAPI
1534 RxCreateNetFobx(
1535 OUT PRX_CONTEXT RxContext,
1536 IN PMRX_SRV_OPEN MrxSrvOpen)
1537 {
1538 PFCB Fcb;
1539 PFOBX Fobx;
1540 ULONG Flags;
1541 PNET_ROOT NetRoot;
1542 PSRV_OPEN SrvOpen;
1543 POOL_TYPE PoolType;
1544
1545 PAGED_CODE();
1546
1547 SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1548 ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1549 ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1550 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1551
1552 Fcb = SrvOpen->Fcb;
1553 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1554 /* Can we use pre-allocated FOBX? */
1555 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
1556 {
1557 Fobx = Fcb->InternalFobx;
1558 /* Call allocate to initialize the FOBX */
1559 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1560 /* Mark it used now */
1561 Fcb->FcbState |= FCB_STATE_FOBX_USED;
1562 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1563 }
1564 else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1565 {
1566 Fobx = SrvOpen->InternalFobx;
1567 /* Call allocate to initialize the FOBX */
1568 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1569 /* Mark it used now */
1570 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1571 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1572 }
1573 else
1574 {
1575 /* Last case, we cannot, allocate a FOBX */
1576 Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
1577 Flags = 0;
1578 }
1579
1580 /* Allocation failed! */
1581 if (Fobx == NULL)
1582 {
1583 return NULL;
1584 }
1585
1586 /* Set flags */
1587 Fobx->Flags = Flags;
1588
1589 /* Initialize throttling */
1590 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1591 if (NetRoot != NULL)
1592 {
1593 if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1594 {
1595 RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1596 NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1597 NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1598 }
1599 else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1600 {
1601 RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1602 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1603 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1604 }
1605 }
1606
1607 /* Propagate flags fron RxContext */
1608 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1609 {
1610 Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1611 }
1612
1613 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1614 {
1615 Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1616 }
1617
1618 /* Continue init */
1619 Fobx->FobxSerialNumber = 0;
1620 Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1621 Fobx->NodeReferenceCount = 1;
1622 Fobx->RxDeviceObject = Fcb->RxDeviceObject;
1623
1624 RxReferenceSrvOpen(SrvOpen);
1625 InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1626
1627 InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1628 InitializeListHead(&Fobx->ScavengerFinalizationList);
1629 InitializeListHead(&Fobx->ClosePendingList);
1630
1631 Fobx->CloseTime.QuadPart = 0;
1632 Fobx->fOpenCountDecremented = FALSE;
1633
1634 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1635
1636 return (PMRX_FOBX)Fobx;
1637 }
1638
1639 /*
1640 * @implemented
1641 */
1642 PNET_ROOT
1643 RxCreateNetRoot(
1644 IN PSRV_CALL SrvCall,
1645 IN PUNICODE_STRING Name,
1646 IN ULONG NetRootFlags,
1647 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1648 {
1649 PNET_ROOT NetRoot;
1650 USHORT CaseInsensitiveLength;
1651 PRX_PREFIX_TABLE PrefixTable;
1652
1653 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1654
1655 PAGED_CODE();
1656
1657 /* We need a SRV_CALL */
1658 ASSERT(SrvCall != NULL);
1659
1660 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1661 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1662
1663 /* Get name length */
1664 CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1665 if (CaseInsensitiveLength > MAXUSHORT)
1666 {
1667 return NULL;
1668 }
1669
1670 /* Allocate the NetRoot */
1671 NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1672 CaseInsensitiveLength);
1673 if (NetRoot == NULL)
1674 {
1675 return NULL;
1676 }
1677
1678 /* Construct name */
1679 RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1680 Name->Buffer, Name->Length);
1681 if (SrvCall->PrefixEntry.Prefix.Length != 0)
1682 {
1683 RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1684 SrvCall->PrefixEntry.Prefix.Length);
1685 }
1686
1687 if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1688 {
1689 CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1690 }
1691 /* Inisert in prefix table */
1692 RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1693 (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1694 RxConnectionId);
1695
1696 /* Prepare the FCB table */
1697 RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1698
1699 InitializeListHead(&NetRoot->TransitionWaitList);
1700 InitializeListHead(&NetRoot->ScavengerFinalizationList);
1701 InitializeListHead(&NetRoot->VirtualNetRoots);
1702
1703 RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
1704
1705 NetRoot->SerialNumberForEnum = SerialNumber++;
1706 NetRoot->Flags |= NetRootFlags;
1707 NetRoot->DiskParameters.ClusterSize = 1;
1708 NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1709 NetRoot->SrvCall = SrvCall;
1710
1711 RxReferenceSrvCall(SrvCall);
1712
1713 DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1714 return NetRoot;
1715 }
1716
1717 /*
1718 * @implemented
1719 */
1720 VOID
1721 NTAPI
1722 RxCreateNetRootCallBack(
1723 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1724 {
1725 PAGED_CODE();
1726
1727 KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1728 }
1729
1730 /*
1731 * @implemented
1732 */
1733 PRX_CONTEXT
1734 NTAPI
1735 RxCreateRxContext(
1736 IN PIRP Irp,
1737 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1738 IN ULONG InitialContextFlags)
1739 {
1740 KIRQL OldIrql;
1741 PRX_CONTEXT Context;
1742
1743 ASSERT(RxDeviceObject != NULL);
1744
1745 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1746
1747 #if DBG
1748 InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
1749 #endif
1750 InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1751
1752 /* Allocate the context from our lookaside list */
1753 Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1754 if (Context == NULL)
1755 {
1756 return NULL;
1757 }
1758
1759 /* Zero it */
1760 RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1761
1762 /* It was allocated on NP pool, keep track of it! */
1763 SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1764 /* And initialize it */
1765 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1766 ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
1767
1768 /* Add it to our global list */
1769 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1770 InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1771 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1772
1773 DPRINT("Context: %p\n", Context);
1774 return Context;
1775 }
1776
1777 /*
1778 * @implemented
1779 */
1780 PSRV_CALL
1781 RxCreateSrvCall(
1782 IN PRX_CONTEXT RxContext,
1783 IN PUNICODE_STRING Name,
1784 IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1785 IN PRX_CONNECTION_ID RxConnectionId)
1786 {
1787 ULONG NameLength;
1788 PSRV_CALL SrvCall;
1789
1790 PAGED_CODE();
1791
1792 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1793
1794 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1795
1796 /* Get the name length */
1797 NameLength = Name->Length + 2 * sizeof(WCHAR);
1798 if (InnerNamePrefix != NULL)
1799 {
1800 NameLength += InnerNamePrefix->Length;
1801 }
1802
1803 /* Allocate the object */
1804 SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1805 if (SrvCall == NULL)
1806 {
1807 return NULL;
1808 }
1809
1810 /* Initialize it */
1811 SrvCall->SerialNumberForEnum = SerialNumber++;
1812 SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1813 RxInitializeBufferingManager(SrvCall);
1814 InitializeListHead(&SrvCall->TransitionWaitList);
1815 InitializeListHead(&SrvCall->ScavengerFinalizationList);
1816 RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
1817 RxInitializeSrvCallParameters(RxContext, SrvCall);
1818 RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1819 SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1820 SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1821 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1822 SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1823
1824 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1825 return SrvCall;
1826 }
1827
1828 /*
1829 * @implemented
1830 */
1831 VOID
1832 NTAPI
1833 RxCreateSrvCallCallBack(
1834 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
1835 {
1836 KIRQL OldIrql;
1837 PSRV_CALL SrvCall;
1838 PRX_CONTEXT RxContext;
1839 ULONG NumberRemaining;
1840 BOOLEAN StartDispatcher;
1841 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1842
1843 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1844
1845 /* Get our context structures */
1846 Calldown = Context->SrvCalldownStructure;
1847 SrvCall = (PSRV_CALL)Calldown->SrvCall;
1848
1849 /* If it is a success, that's the winner */
1850 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1851 if (Context->Status == STATUS_SUCCESS)
1852 {
1853 Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1854 Calldown->BestFinisher = Context->RxDeviceObject;
1855 }
1856 NumberRemaining = --Calldown->NumberRemaining;
1857 SrvCall->Status = Context->Status;
1858 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1859
1860 /* Still some to ask, keep going */
1861 if (NumberRemaining != 0)
1862 {
1863 return;
1864 }
1865
1866 /* If that's not async, signal we're done */
1867 RxContext = Calldown->RxContext;
1868 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1869 {
1870 KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1871 return;
1872 }
1873 /* If that's a mailslot, finish construction, no more to do */
1874 else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1875 {
1876 RxFinishSrvCallConstruction(Calldown);
1877 return;
1878 }
1879
1880 /* Queue our finish call for delayed completion */
1881 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1882 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1883 InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
1884 StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1885 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1886
1887 /* If we have to start dispatcher, go ahead */
1888 if (StartDispatcher)
1889 {
1890 NTSTATUS Status;
1891
1892 Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
1893 RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
1894 if (!NT_SUCCESS(Status))
1895 {
1896 /* It failed - run it manually.... */
1897 RxFinishSrvCallConstructionDispatcher(NULL);
1898 }
1899 }
1900 }
1901
1902 /*
1903 * @implemented
1904 */
1905 PSRV_OPEN
1906 RxCreateSrvOpen(
1907 IN PV_NET_ROOT VNetRoot,
1908 IN OUT PFCB Fcb)
1909 {
1910 ULONG Flags;
1911 PSRV_OPEN SrvOpen;
1912 POOL_TYPE PoolType;
1913
1914 PAGED_CODE();
1915
1916 ASSERT(NodeTypeIsFcb(Fcb));
1917 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1918
1919 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1920
1921 _SEH2_TRY
1922 {
1923 SrvOpen = Fcb->InternalSrvOpen;
1924 /* Check whethet we have to allocate a new SRV_OPEN */
1925 if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
1926 BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
1927 !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1928 {
1929 /* Proceed */
1930 SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1931 RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
1932 Flags = 0;
1933 }
1934 else
1935 {
1936 /* Otherwise, just use internal one and initialize it */
1937 RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1938 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
1939 Fcb->InternalSrvOpen);
1940 Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
1941 Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
1942 }
1943
1944 /* If SrvOpen was properly allocated, initialize it */
1945 if (SrvOpen != NULL)
1946 {
1947 SrvOpen->Flags = Flags;
1948 SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
1949 SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
1950 SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
1951 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
1952 SrvOpen->NodeReferenceCount = 1;
1953
1954 RxReferenceVNetRoot(VNetRoot);
1955 RxReferenceNetFcb(Fcb);
1956
1957 InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
1958 ++Fcb->SrvOpenListVersion;
1959
1960 InitializeListHead(&SrvOpen->ScavengerFinalizationList);
1961 InitializeListHead(&SrvOpen->TransitionWaitList);
1962 InitializeListHead(&SrvOpen->FobxList);
1963 InitializeListHead(&SrvOpen->SrvOpenKeyList);
1964 }
1965 }
1966 _SEH2_FINALLY
1967 {
1968 if (_SEH2_AbnormalTermination())
1969 {
1970 if (SrvOpen != NULL)
1971 {
1972 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
1973 SrvOpen = NULL;
1974 }
1975 }
1976 else
1977 {
1978 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
1979 }
1980 }
1981 _SEH2_END;
1982
1983 return SrvOpen;
1984 }
1985
1986 /*
1987 * @implemented
1988 */
1989 PV_NET_ROOT
1990 RxCreateVNetRoot(
1991 IN PRX_CONTEXT RxContext,
1992 IN PNET_ROOT NetRoot,
1993 IN PUNICODE_STRING CanonicalName,
1994 IN PUNICODE_STRING LocalNetRootName,
1995 IN PUNICODE_STRING FilePath,
1996 IN PRX_CONNECTION_ID RxConnectionId)
1997 {
1998 NTSTATUS Status;
1999 PV_NET_ROOT VNetRoot;
2000 USHORT CaseInsensitiveLength;
2001
2002 PAGED_CODE();
2003
2004 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
2005 LocalNetRootName, FilePath, RxConnectionId);
2006
2007 /* Lock must be held exclusively */
2008 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
2009
2010 /* Check for overflow */
2011 if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
2012 {
2013 return NULL;
2014 }
2015
2016 /* Get name length and allocate VNetRoot */
2017 CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2018 VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
2019 CaseInsensitiveLength);
2020 if (VNetRoot == NULL)
2021 {
2022 return NULL;
2023 }
2024
2025 /* Initialize its connection parameters */
2026 Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
2027 &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
2028 &VNetRoot->pPassword, &VNetRoot->Flags);
2029 if (!NT_SUCCESS(Status))
2030 {
2031 RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
2032 VNetRoot->pPassword, &VNetRoot->Flags);
2033 RxFreeObject(VNetRoot);
2034
2035 return NULL;
2036 }
2037
2038 /* Set name */
2039 RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2040
2041 VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2042 VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
2043 VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2044 VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2045
2046 InitializeListHead(&VNetRoot->TransitionWaitList);
2047 InitializeListHead(&VNetRoot->ScavengerFinalizationList);
2048
2049 if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
2050 {
2051 USHORT i;
2052
2053 if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
2054 {
2055 CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
2056 }
2057 else
2058 {
2059 CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
2060 }
2061
2062 for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
2063 {
2064 if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
2065 {
2066 break;
2067 }
2068 }
2069
2070 CaseInsensitiveLength += (i * sizeof(WCHAR));
2071 }
2072
2073 /* Insert in prefix table */
2074 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
2075 VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
2076 RxConnectionId);
2077
2078 RxReferenceNetRoot(NetRoot);
2079 RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
2080
2081 /* Finish init */
2082 VNetRoot->SerialNumberForEnum = SerialNumber++;
2083 VNetRoot->UpperFinalizationDone = FALSE;
2084 VNetRoot->ConnectionFinalizationDone = FALSE;
2085 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2086
2087 DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
2088 DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
2089
2090 return VNetRoot;
2091 }
2092
2093 /*
2094 * @implemented
2095 */
2096 VOID
2097 RxDereference(
2098 IN OUT PVOID Instance,
2099 IN LOCK_HOLDING_STATE LockHoldingState)
2100 {
2101 LONG RefCount;
2102 NODE_TYPE_CODE NodeType;
2103 PNODE_TYPE_AND_SIZE Node;
2104
2105 PAGED_CODE();
2106
2107 RxAcquireScavengerMutex();
2108
2109 /* Check we have a node we can handle */
2110 NodeType = NodeType(Instance);
2111 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
2112 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
2113 (NodeType == RDBSS_NTC_FOBX));
2114
2115 Node = (PNODE_TYPE_AND_SIZE)Instance;
2116 RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
2117 ASSERT(RefCount >= 0);
2118
2119 /* Trace refcount */
2120 switch (NodeType)
2121 {
2122 case RDBSS_NTC_SRVCALL:
2123 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
2124 break;
2125
2126 case RDBSS_NTC_NETROOT:
2127 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
2128 break;
2129
2130 case RDBSS_NTC_V_NETROOT:
2131 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
2132 break;
2133
2134 case RDBSS_NTC_SRVOPEN:
2135 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
2136 break;
2137
2138 case RDBSS_NTC_FOBX:
2139 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
2140 break;
2141
2142 default:
2143 ASSERT(FALSE);
2144 break;
2145 }
2146
2147 /* No need to free - still in use */
2148 if (RefCount > 1)
2149 {
2150 RxReleaseScavengerMutex();
2151 return;
2152 }
2153
2154 /* We have to be locked exclusively */
2155 if (LockHoldingState != LHS_ExclusiveLockHeld)
2156 {
2157 if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
2158 (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT))
2159 {
2160 RxpMarkInstanceForScavengedFinalization(Instance);
2161 }
2162
2163 RxReleaseScavengerMutex();
2164 return;
2165 }
2166 else
2167 {
2168 if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK))
2169 {
2170 RxpUndoScavengerFinalizationMarking(Instance);
2171 }
2172 }
2173
2174 RxReleaseScavengerMutex();
2175
2176 /* Now, deallocate the memory */
2177 switch (NodeType)
2178 {
2179 case RDBSS_NTC_SRVCALL:
2180 {
2181 PSRV_CALL SrvCall;
2182
2183 SrvCall = (PSRV_CALL)Instance;
2184
2185 ASSERT(SrvCall->RxDeviceObject != NULL);
2186 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
2187 RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
2188 break;
2189 }
2190
2191 case RDBSS_NTC_NETROOT:
2192 {
2193 PNET_ROOT NetRoot;
2194
2195 NetRoot = (PNET_ROOT)Instance;
2196
2197 ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL);
2198 ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2199 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2200 break;
2201 }
2202
2203 case RDBSS_NTC_V_NETROOT:
2204 {
2205 PV_NET_ROOT VNetRoot;
2206
2207 VNetRoot = (PV_NET_ROOT)Instance;
2208
2209 ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL);
2210 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2211 RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE);
2212 break;
2213 }
2214
2215 case RDBSS_NTC_SRVOPEN:
2216 {
2217 PSRV_OPEN SrvOpen;
2218
2219 SrvOpen = (PSRV_OPEN)Instance;
2220
2221 ASSERT(RxIsFcbAcquired(SrvOpen->Fcb));
2222 if (SrvOpen->OpenCount == 0)
2223 {
2224 RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE);
2225 }
2226 break;
2227 }
2228
2229 case RDBSS_NTC_FOBX:
2230 {
2231 PFOBX Fobx;
2232
2233 Fobx = (PFOBX)Instance;
2234
2235 ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb));
2236 RxFinalizeNetFobx(Fobx, TRUE, FALSE);
2237 break;
2238 }
2239 }
2240 }
2241
2242 /*
2243 * @implemented
2244 */
2245 VOID
2246 NTAPI
2247 RxDereferenceAndDeleteRxContext_Real(
2248 IN PRX_CONTEXT RxContext)
2249 {
2250 KIRQL OldIrql;
2251 ULONG RefCount;
2252 BOOLEAN Allocated;
2253 PRX_CONTEXT StopContext = NULL;
2254
2255 /* Make sure we really have a context */
2256 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
2257 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
2258 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
2259 /* If refcount is 0, start releasing stuff that needs spinlock held */
2260 if (RefCount == 0)
2261 {
2262 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2263
2264 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
2265
2266 /* If that's stop context from DO, remove it */
2267 RxDeviceObject = RxContext->RxDeviceObject;
2268 if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
2269 {
2270 RxDeviceObject->StartStopContext.pStopContext = NULL;
2271 }
2272 else
2273 {
2274 /* Remove it from the list */
2275 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
2276 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
2277 RemoveEntryList(&RxContext->ContextListEntry);
2278
2279 /* If that was the last active context, save the stop context */
2280 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
2281 {
2282 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
2283 {
2284 StopContext = RxDeviceObject->StartStopContext.pStopContext;
2285 }
2286 }
2287 }
2288 }
2289 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
2290
2291 /* Now, deal with what can be done without spinlock held */
2292 if (RefCount == 0)
2293 {
2294 /* Refcount shouldn't have changed */
2295 ASSERT(RxContext->ReferenceCount == 0);
2296 /* Reset everything that can be */
2297 RxPrepareContextForReuse(RxContext);
2298
2299 #ifdef RDBSS_TRACKER
2300 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
2301 #endif
2302 /* If that was the last active, set the event */
2303 if (StopContext != NULL)
2304 {
2305 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
2306 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
2307 }
2308
2309 #if DBG
2310 /* Is ShadowCrit still owned? Shouldn't happen! */
2311 if (RxContext->ShadowCritOwner != 0)
2312 {
2313 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
2314 ASSERT(FALSE);
2315 }
2316 #endif
2317
2318 /* If it was allocated, free it */
2319 if (Allocated)
2320 {
2321 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
2322 }
2323 }
2324 }
2325
2326 VOID
2327 NTAPI
2328 RxDispatchChangeBufferingStateRequests(
2329 PVOID Context)
2330 {
2331 UNIMPLEMENTED;
2332 }
2333
2334 /*
2335 * @implemented
2336 */
2337 NTSTATUS
2338 NTAPI
2339 RxDispatchToWorkerThread(
2340 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
2341 IN WORK_QUEUE_TYPE WorkQueueType,
2342 IN PRX_WORKERTHREAD_ROUTINE Routine,
2343 IN PVOID pContext)
2344 {
2345 NTSTATUS Status;
2346 PRX_WORK_DISPATCH_ITEM DispatchItem;
2347
2348 /* Allocate a bit of context */
2349 DispatchItem = RxAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
2350 if (DispatchItem == NULL)
2351 {
2352 return STATUS_INSUFFICIENT_RESOURCES;
2353 }
2354
2355 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2356 DispatchItem->DispatchRoutine = Routine;
2357 DispatchItem->DispatchRoutineParameter = pContext;
2358 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
2359 DispatchItem->WorkQueueItem.Parameter = DispatchItem;
2360
2361 /* Insert item */
2362 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem);
2363 if (!NT_SUCCESS(Status))
2364 {
2365 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
2366 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
2367 }
2368
2369 DPRINT("Dispatching: %p, %p\n", Routine, pContext);
2370
2371 return Status;
2372 }
2373
2374 /*
2375 * @implemented
2376 */
2377 VOID
2378 RxExclusivePrefixTableLockToShared(
2379 PRX_PREFIX_TABLE Table)
2380 {
2381 PAGED_CODE();
2382
2383 ExConvertExclusiveToSharedLite(&Table->TableLock);
2384 }
2385
2386 /*
2387 * @implemented
2388 */
2389 VOID
2390 RxExtractServerName(
2391 IN PUNICODE_STRING FilePathName,
2392 OUT PUNICODE_STRING SrvCallName,
2393 OUT PUNICODE_STRING RestOfName)
2394 {
2395 USHORT i, Length;
2396
2397 PAGED_CODE();
2398
2399 ASSERT(SrvCallName != NULL);
2400
2401 /* SrvCall name will start from the begin up to the first separator */
2402 SrvCallName->Buffer = FilePathName->Buffer;
2403 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
2404 {
2405 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2406 {
2407 break;
2408 }
2409 }
2410
2411 /* Compute length */
2412 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
2413 SrvCallName->MaximumLength = Length;
2414 SrvCallName->Length = Length;
2415
2416 /* Return the rest if asked */
2417 if (RestOfName != NULL)
2418 {
2419 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
2420 RestOfName->Buffer = &FilePathName->Buffer[i];
2421 RestOfName->MaximumLength = Length;
2422 RestOfName->Length = Length;
2423 }
2424 }
2425
2426 /*
2427 * @implemented
2428 */
2429 NTSTATUS
2430 RxFcbTableInsertFcb(
2431 IN OUT PRX_FCB_TABLE FcbTable,
2432 IN OUT PFCB Fcb)
2433 {
2434 PAGED_CODE();
2435
2436 /* We deal with the table, make sure it's locked */
2437 ASSERT(RxIsFcbTableLockExclusive(FcbTable));
2438
2439 /* Compute the hash */
2440 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
2441
2442 RxReferenceNetFcb(Fcb);
2443
2444 /* If no length, it will be our null entry */
2445 if (Fcb->FcbTableEntry.Path.Length == 0)
2446 {
2447 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
2448 }
2449 /* Otherwise, insert in the appropriate bucket */
2450 else
2451 {
2452 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2453 &Fcb->FcbTableEntry.HashLinks);
2454 }
2455
2456 /* Propagate the change by incrementing the version number */
2457 InterlockedIncrement((volatile long *)&FcbTable->Version);
2458
2459 return STATUS_SUCCESS;
2460 }
2461
2462 /*
2463 * @implemented
2464 */
2465 PFCB
2466 RxFcbTableLookupFcb(
2467 IN PRX_FCB_TABLE FcbTable,
2468 IN PUNICODE_STRING Path)
2469 {
2470 PFCB Fcb;
2471 PRX_FCB_TABLE_ENTRY TableEntry;
2472
2473 PAGED_CODE();
2474
2475 /* No path - easy, that's null entry */
2476 if (Path == NULL)
2477 {
2478 TableEntry = FcbTable->TableEntryForNull;
2479 }
2480 else
2481 {
2482 ULONG Hash;
2483 PLIST_ENTRY HashBucket, ListEntry;
2484
2485 /* Otherwise, compute the hash value and find the associated bucket */
2486 Hash = RxTableComputePathHashValue(Path);
2487 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2488 /* If the bucket is empty, it means there's no entry yet */
2489 if (IsListEmpty(HashBucket))
2490 {
2491 TableEntry = NULL;
2492 }
2493 else
2494 {
2495 /* Otherwise, browse all the entry */
2496 for (ListEntry = HashBucket->Flink;
2497 ListEntry != HashBucket;
2498 ListEntry = ListEntry->Flink)
2499 {
2500 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2501 InterlockedIncrement(&FcbTable->Compares);
2502
2503 /* If entry hash and string are equal, thatt's the one! */
2504 if (TableEntry->HashValue == Hash &&
2505 TableEntry->Path.Length == Path->Length &&
2506 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2507 {
2508 break;
2509 }
2510 }
2511
2512 /* We reached the end? Not found */
2513 if (ListEntry == HashBucket)
2514 {
2515 TableEntry = NULL;
2516 }
2517 }
2518 }
2519
2520 InterlockedIncrement(&FcbTable->Lookups);
2521
2522 /* If table entry isn't null, return the FCB */
2523 if (TableEntry != NULL)
2524 {
2525 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2526 RxReferenceNetFcb(Fcb);
2527 }
2528 else
2529 {
2530 Fcb = NULL;
2531 InterlockedIncrement(&FcbTable->FailedLookups);
2532 }
2533
2534 return Fcb;
2535 }
2536
2537 /*
2538 * @implemented
2539 */
2540 NTSTATUS
2541 RxFcbTableRemoveFcb(
2542 IN OUT PRX_FCB_TABLE FcbTable,
2543 IN OUT PFCB Fcb)
2544 {
2545 PAGED_CODE();
2546
2547 ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2548
2549 /* If no path, then remove entry for null */
2550 if (Fcb->FcbTableEntry.Path.Length == 0)
2551 {
2552 FcbTable->TableEntryForNull = NULL;
2553 }
2554 /* Otherwise, remove from the bucket */
2555 else
2556 {
2557 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2558 }
2559
2560 /* Reset its list entry */
2561 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2562
2563 /* Propagate the change by incrementing the version number */
2564 InterlockedIncrement((volatile long *)&FcbTable->Version);
2565
2566 return STATUS_SUCCESS;
2567 }
2568
2569 /*
2570 * @implemented
2571 */
2572 NTSTATUS
2573 NTAPI
2574 RxFinalizeConnection(
2575 IN OUT PNET_ROOT NetRoot,
2576 IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2577 IN LOGICAL ForceFilesClosed)
2578 {
2579 NTSTATUS Status;
2580 PRX_PREFIX_TABLE PrefixTable;
2581 ULONG UncleanAny, UncleanDir;
2582 LONG FilesOpen, AdditionalRef;
2583 BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
2584
2585 PAGED_CODE();
2586
2587 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
2588
2589 /* Get a BOOLEAN out of LOGICAL
2590 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2591 */
2592 ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
2593
2594 /* First, delete any notification change */
2595 Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
2596 /* If it failed, continue if forced */
2597 if (Status != STATUS_SUCCESS && !ForceFilesClosed)
2598 {
2599 return Status;
2600 }
2601 /* Reset status, in case notification deletion failed */
2602 Status = STATUS_SUCCESS;
2603
2604 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2605
2606 PrefixLocked = FALSE;
2607 FcbTableLocked = FALSE;
2608 FilesOpen = 0;
2609 AdditionalRef = 0;
2610 UncleanAny = 0;
2611 UncleanDir = 0;
2612 _SEH2_TRY
2613 {
2614 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2615 PrefixLocked = TRUE;
2616
2617 RxReferenceNetRoot(NetRoot);
2618
2619 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2620 FcbTableLocked = TRUE;
2621
2622 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2623 if (!VNetRoot->ConnectionFinalizationDone)
2624 {
2625 USHORT Bucket;
2626 PRX_FCB_TABLE FcbTable;
2627
2628 DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
2629
2630 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2631 FcbTable = &NetRoot->FcbTable;
2632 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2633 {
2634 PLIST_ENTRY BucketList, Entry;
2635
2636 BucketList = &FcbTable->HashBuckets[Bucket];
2637 Entry = BucketList->Flink;
2638 while (Entry != BucketList)
2639 {
2640 PFCB Fcb;
2641
2642 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
2643 Entry = Entry->Flink;
2644
2645 /* FCB for this connection, go ahead */
2646 if (Fcb->VNetRoot == VNetRoot)
2647 {
2648 /* It's still open, and no force? Fail and keep track */
2649 if (Fcb->UncleanCount > 0 && !ForceClose)
2650 {
2651 Status = STATUS_CONNECTION_IN_USE;
2652 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2653 {
2654 ++UncleanDir;
2655 }
2656 else
2657 {
2658 ++UncleanAny;
2659 }
2660 }
2661 else
2662 {
2663 /* Else, force purge */
2664 ASSERT(NodeTypeIsFcb(Fcb));
2665
2666 Status = RxAcquireExclusiveFcb(NULL, Fcb);
2667 ASSERT(Status == STATUS_SUCCESS);
2668
2669 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2670
2671 RxScavengeRelatedFobxs(Fcb);
2672 RxPurgeFcb(Fcb);
2673
2674 /* We don't need to release FCB lock, FCB finalize will take care of it */
2675 }
2676 }
2677 }
2678 }
2679
2680 /* No files left, our V_NET_ROOT is finalized */
2681 if (VNetRoot->NumberOfFobxs == 0)
2682 {
2683 VNetRoot->ConnectionFinalizationDone = TRUE;
2684 }
2685 }
2686
2687 /* Keep Number of open files and track of the extra reference */
2688 FilesOpen = VNetRoot->NumberOfFobxs;
2689 AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
2690 /* If force close, caller doesn't want to keep connection alive
2691 * and wants it totally close, so drop the V_NET_ROOT too
2692 */
2693 if (ForceClose)
2694 {
2695 RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
2696 }
2697 }
2698 _SEH2_FINALLY
2699 {
2700 /* Release what was acquired */
2701 if (FcbTableLocked)
2702 {
2703 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2704 }
2705
2706 /* If close is forced, only fix status if there are open files */
2707 if (ForceClose)
2708 {
2709 if (Status != STATUS_SUCCESS && UncleanAny != 0)
2710 {
2711 Status = STATUS_FILES_OPEN;
2712 }
2713 }
2714 /* Else, fix status and fail closing if there are open files */
2715 else
2716 {
2717 if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
2718 {
2719 Status = STATUS_FILES_OPEN;
2720 }
2721 }
2722
2723 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
2724
2725 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2726 * only if it was still referenced!
2727 */
2728 if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
2729 {
2730 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2731 RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
2732 }
2733
2734 if (PrefixLocked)
2735 {
2736 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2737 RxReleasePrefixTableLock(PrefixTable);
2738 }
2739 }
2740 _SEH2_END;
2741
2742 return Status;
2743 }
2744
2745 /*
2746 * @implemented
2747 */
2748 VOID
2749 RxFinalizeFcbTable(
2750 IN OUT PRX_FCB_TABLE FcbTable)
2751 {
2752 USHORT Bucket;
2753
2754 PAGED_CODE();
2755
2756 /* Just delete the lock */
2757 ExDeleteResourceLite(&FcbTable->TableLock);
2758
2759 /* And make sure (checked) that the table is really empty... */
2760 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2761 {
2762 ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
2763 }
2764 }
2765
2766 /*
2767 * @implemented
2768 */
2769 BOOLEAN
2770 RxFinalizeNetFcb(
2771 OUT PFCB ThisFcb,
2772 IN BOOLEAN RecursiveFinalize,
2773 IN BOOLEAN ForceFinalize,
2774 IN LONG ReferenceCount)
2775 {
2776 PAGED_CODE();
2777
2778 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2779 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2780
2781 /* Make sure we have an exclusively acquired FCB */
2782 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2783 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2784
2785 /* We shouldn't force finalization... */
2786 ASSERT(!ForceFinalize);
2787
2788 /* If recurisve, finalize all the associated SRV_OPEN */
2789 if (RecursiveFinalize)
2790 {
2791 PLIST_ENTRY ListEntry;
2792
2793 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2794 ListEntry != &ThisFcb->SrvOpenList;
2795 ListEntry = ListEntry->Flink)
2796 {
2797 PSRV_OPEN SrvOpen;
2798
2799 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2800 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2801 }
2802 }
2803 /* If FCB is still in use, that's over */
2804 else
2805 {
2806 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2807 {
2808 ASSERT(ReferenceCount > 0);
2809
2810 return FALSE;
2811 }
2812 }
2813
2814 ASSERT(ReferenceCount >= 1);
2815
2816 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2817 if (ReferenceCount != 1 && !ForceFinalize)
2818 {
2819 return FALSE;
2820 }
2821
2822 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2823
2824 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
2825
2826 /* If finalization was not already initiated, go ahead */
2827 if (!ThisFcb->UpperFinalizationDone)
2828 {
2829 /* Free any FCB_LOCK */
2830 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2831 {
2832 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2833
2834 while (ThisFcb->BufferedLocks.List != NULL)
2835 {
2836 PFCB_LOCK Entry;
2837
2838 Entry = ThisFcb->BufferedLocks.List;
2839 ThisFcb->BufferedLocks.List = Entry->Next;
2840
2841 RxFreePool(Entry);
2842 }
2843 }
2844
2845 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2846 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2847 {
2848 PNET_ROOT NetRoot;
2849
2850 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2851
2852 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2853 /* So, remove it */
2854 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2855 {
2856 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2857 }
2858 }
2859
2860 ThisFcb->UpperFinalizationDone = TRUE;
2861 }
2862
2863 ASSERT(ReferenceCount >= 1);
2864
2865 /* Even if forced, don't allow broken free */
2866 if (ReferenceCount != 1)
2867 {
2868 return FALSE;
2869 }
2870
2871 /* Now, release everything */
2872 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2873 {
2874 RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2875 }
2876
2877 if (ThisFcb->MRxDispatch != NULL)
2878 {
2879 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2880 }
2881
2882 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2883 ExDeleteResourceLite(ThisFcb->Header.Resource);
2884 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2885
2886 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2887 RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
2888
2889 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2890 ASSERT(!ThisFcb->fMiniInited);
2891
2892 /* And free the object */
2893 RxFreeFcbObject(ThisFcb);
2894
2895 return TRUE;
2896 }
2897
2898 /*
2899 * @implemented
2900 */
2901 BOOLEAN
2902 RxFinalizeNetFobx(
2903 _Out_ PFOBX ThisFobx,
2904 _In_ BOOLEAN RecursiveFinalize,
2905 _In_ BOOLEAN ForceFinalize)
2906 {
2907 PFCB Fcb;
2908 PSRV_OPEN SrvOpen;
2909
2910 PAGED_CODE();
2911
2912 ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
2913
2914 /* Only finalize if forced or if there's no ref left */
2915 if (ThisFobx->NodeReferenceCount != 0 &&
2916 !ForceFinalize)
2917 {
2918 return FALSE;
2919 }
2920
2921 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
2922
2923 SrvOpen = ThisFobx->SrvOpen;
2924 Fcb = SrvOpen->Fcb;
2925 /* If it wasn't finalized yet, do it */
2926 if (!ThisFobx->UpperFinalizationDone)
2927 {
2928 ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
2929 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
2930
2931 /* Remove it from the SRV_OPEN */
2932 RemoveEntryList(&ThisFobx->FobxQLinks);
2933
2934 /* If we were used to browse a directory, free the query buffer */
2935 if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
2936 {
2937 RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
2938 }
2939
2940 /* Notify the mini-rdr */
2941 if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
2942 {
2943 Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
2944 }
2945
2946 /* If the SRV_OPEN wasn't closed yet, do it */
2947 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
2948 {
2949 NTSTATUS Status;
2950
2951 Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
2952 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
2953 }
2954
2955 /* Finalization done */
2956 ThisFobx->UpperFinalizationDone = TRUE;
2957 }
2958
2959 /* If we're still referenced, don't go any further! */
2960 if (ThisFobx->NodeReferenceCount != 0)
2961 {
2962 return FALSE;
2963 }
2964
2965 /* At that point, everything should be closed */
2966 ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
2967
2968 /* Was the FOBX allocated with another object?
2969 * If so, mark the buffer free in said object
2970 */
2971 if (ThisFobx == Fcb->InternalFobx)
2972 {
2973 ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED);
2974 }
2975 else if (ThisFobx == SrvOpen->InternalFobx)
2976 {
2977 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
2978 }
2979
2980 ThisFobx->pSrvOpen = NULL;
2981
2982 /* A FOBX less */
2983 InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
2984
2985 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
2986
2987 /* If it wasn't allocated with another object, free the FOBX */
2988 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
2989 {
2990 RxFreeFcbObject(ThisFobx);
2991 }
2992
2993 return TRUE;
2994 }
2995
2996 /*
2997 * @implemented
2998 */
2999 BOOLEAN
3000 RxFinalizeNetRoot(
3001 OUT PNET_ROOT ThisNetRoot,
3002 IN BOOLEAN RecursiveFinalize,
3003 IN BOOLEAN ForceFinalize)
3004 {
3005 PSRV_CALL SrvCall;
3006 PRX_FCB_TABLE FcbTable;
3007 PRX_PREFIX_TABLE PrefixTable;
3008
3009 PAGED_CODE();
3010
3011 ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
3012
3013 PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3014 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3015
3016 /* If sme finalization is already ongoing, leave */
3017 if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
3018 {
3019 return FALSE;
3020 }
3021
3022 /* Mark we're finalizing */
3023 SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
3024
3025 FcbTable = &ThisNetRoot->FcbTable;
3026 /* Did caller asked us to finalize any associated FCB? */
3027 if (RecursiveFinalize)
3028 {
3029 USHORT Bucket;
3030
3031 /* Browse all the FCBs in our FCB table */
3032 RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
3033 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
3034 {
3035 PLIST_ENTRY HashBucket, ListEntry;
3036
3037 HashBucket = &FcbTable->HashBuckets[Bucket];
3038 ListEntry = HashBucket->Flink;
3039 while (ListEntry != HashBucket)
3040 {
3041 PFCB Fcb;
3042
3043 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
3044 ASSERT(NodeTypeIsFcb(Fcb));
3045
3046 ListEntry = ListEntry->Flink;
3047
3048 /* If the FCB isn't orphaned, then, it's time to purge it */
3049 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3050 {
3051 NTSTATUS Status;
3052
3053 Status = RxAcquireExclusiveFcb(NULL, Fcb);
3054 ASSERT(Status == STATUS_SUCCESS);
3055 RxPurgeFcb(Fcb);
3056 }
3057 }
3058 }
3059 RxReleaseFcbTableLock(FcbTable);
3060 }
3061
3062 /* Only finalize if forced or if there's a single ref left */
3063 if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
3064 {
3065 return FALSE;
3066 }
3067
3068 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
3069
3070 /* If we're still referenced, don't go any further! */
3071 if (ThisNetRoot->NodeReferenceCount != 1)
3072 {
3073 return FALSE;
3074 }
3075
3076 /* Finalize the FCB table (and make sure it's empty!) */
3077 RxFinalizeFcbTable(FcbTable);
3078
3079 /* If name wasn't remove already, do it now */
3080 if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
3081 {
3082 RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
3083 }
3084
3085 /* Delete the object */
3086 SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
3087 RxFreeObject(ThisNetRoot);
3088
3089 /* And dereference the associated SRV_CALL */
3090 if (SrvCall != NULL)
3091 {
3092 RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
3093 }
3094
3095 return TRUE;
3096 }
3097
3098 /*
3099 * @implemented
3100 */
3101 BOOLEAN
3102 RxFinalizeSrvCall(
3103 OUT PSRV_CALL ThisSrvCall,
3104 IN BOOLEAN RecursiveFinalize,
3105 IN BOOLEAN ForceFinalize)
3106 {
3107 PRX_PREFIX_TABLE PrefixTable;
3108
3109 PAGED_CODE();
3110
3111 ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
3112
3113 PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
3114 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3115
3116 /* Only finalize if forced or if there's a single ref left */
3117 if (ThisSrvCall->NodeReferenceCount != 1 &&
3118 !ForceFinalize)
3119 {
3120 return FALSE;
3121 }
3122
3123 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
3124
3125 /* If it wasn't finalized yet, do it */
3126 if (!ThisSrvCall->UpperFinalizationDone)
3127 {
3128 BOOLEAN WillFree;
3129
3130 /* Remove ourselves from prefix table */
3131 RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
3132
3133 /* Remember our third arg, in case we get queued for later execution */
3134 if (ForceFinalize)
3135 {
3136 SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
3137 }
3138
3139 /* And done */
3140 ThisSrvCall->UpperFinalizationDone = TRUE;
3141
3142 /* Would defered execution free the object? */
3143 WillFree = (ThisSrvCall->NodeReferenceCount == 1);
3144
3145 /* If we have a device object */
3146 if (ThisSrvCall->RxDeviceObject != NULL)
3147 {
3148 NTSTATUS Status;
3149
3150 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3151 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3152 {
3153 /* Extra ref, as usual */
3154 InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
3155 /* And dispatch */
3156 RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
3157
3158 /* Return to the caller, in advance, whether we're freeing the object or not */
3159 return WillFree;
3160 }
3161
3162 /* If in the right thread already, call the mini-rdr */
3163 MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
3164 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
3165 (void)Status;
3166 }
3167 }
3168
3169 /* If we're still referenced, don't go any further! */
3170 if (ThisSrvCall->NodeReferenceCount != 1)
3171 {
3172 return FALSE;
3173 }
3174
3175 /* Don't leak */
3176 if (ThisSrvCall->pDomainName != NULL)
3177 {
3178 RxFreePool(ThisSrvCall->pDomainName);
3179 }
3180
3181 /* And free! */
3182 RxTearDownBufferingManager(ThisSrvCall);
3183 RxFreeObject(ThisSrvCall);
3184
3185 return TRUE;
3186 }
3187
3188 /*
3189 * @implemented
3190 */
3191 BOOLEAN
3192 RxFinalizeSrvOpen(
3193 OUT PSRV_OPEN ThisSrvOpen,
3194 IN BOOLEAN RecursiveFinalize,
3195 IN BOOLEAN ForceFinalize)
3196 {
3197 PFCB Fcb;
3198
3199 PAGED_CODE();
3200
3201 /* We have to have a SRV_OPEN */
3202 ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
3203
3204 /* If that's a recursive finalization, finalize any related FOBX */
3205 if (RecursiveFinalize)
3206 {
3207 PLIST_ENTRY ListEntry;
3208
3209 ListEntry = ThisSrvOpen->FobxList.Flink;
3210 while (ListEntry != &ThisSrvOpen->FobxList)
3211 {
3212 PFOBX Fobx;
3213
3214 Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
3215 ListEntry = ListEntry->Flink;
3216 RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
3217 }
3218 }
3219
3220 /* If we have still references, don't finalize unless forced */
3221 if (ThisSrvOpen->NodeReferenceCount != 0 &&
3222 !ForceFinalize)
3223 {
3224 return FALSE;
3225 }
3226
3227 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
3228
3229 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3230 Fcb = (PFCB)ThisSrvOpen->pFcb;
3231 if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
3232 BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
3233 {
3234 PV_NET_ROOT VNetRoot;
3235
3236 /* Associated FCB can't be fake one */
3237 ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
3238 ASSERT(RxIsFcbAcquiredExclusive (Fcb));
3239
3240 /* Purge any pending operation */
3241 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
3242
3243 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3244 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3245 {
3246 NTSTATUS Status;
3247
3248 MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
3249 (void)Status;
3250 }
3251
3252 /* Remove ourselves from the FCB */
3253 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3254 InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
3255 ++Fcb->SrvOpenListVersion;
3256
3257 /* If we have a V_NET_ROOT, dereference it */
3258 VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
3259 if (VNetRoot != NULL)
3260 {
3261 InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
3262 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3263 ThisSrvOpen->pVNetRoot = NULL;
3264 }
3265
3266 /* Finalization done */
3267 ThisSrvOpen->UpperFinalizationDone = TRUE;
3268 }
3269
3270 /* Don't free memory if still referenced */
3271 if (ThisSrvOpen->NodeReferenceCount != 0)
3272 {
3273 return FALSE;
3274 }
3275
3276 /* No key association left */
3277 ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
3278
3279 /* If we're still in some FCB, remove us */
3280 if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
3281 {
3282 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3283 }
3284
3285 /* If enclosed allocation, mark the memory zone free */
3286 if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
3287 {
3288 ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
3289 }
3290 /* Otherwise, free the memory */
3291 else
3292 {
3293 RxFreeFcbObject(ThisSrvOpen);
3294 }
3295
3296 RxDereferenceNetFcb(Fcb);
3297
3298 return TRUE;
3299 }
3300
3301 /*
3302 * @implemented
3303 */
3304 BOOLEAN
3305 RxFinalizeVNetRoot(
3306 OUT PV_NET_ROOT ThisVNetRoot,
3307 IN BOOLEAN RecursiveFinalize,
3308 IN BOOLEAN ForceFinalize)
3309 {
3310 PNET_ROOT NetRoot;
3311 PRX_PREFIX_TABLE PrefixTable;
3312
3313 PAGED_CODE();
3314
3315 ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
3316
3317 PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3318 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3319
3320 /* Only finalize if forced or if there's a single ref left */
3321 if (ThisVNetRoot->NodeReferenceCount != 1 &&
3322 !ForceFinalize)
3323 {
3324 return FALSE;
3325 }
3326
3327 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
3328
3329 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
3330 /* If it wasn't finalized yet, do it */
3331 if (!ThisVNetRoot->UpperFinalizationDone)
3332 {
3333 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
3334
3335 /* Reference the NetRoot so that it doesn't disappear */
3336 RxReferenceNetRoot(NetRoot);
3337 RxOrphanSrvOpens(ThisVNetRoot);
3338 /* Remove us from the available VNetRoot for NetRoot */
3339 RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
3340 /* Remove extra ref */
3341 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3342
3343 /* Remove ourselves from prefix table */
3344 RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
3345
3346 /* Finalization done */
3347 ThisVNetRoot->UpperFinalizationDone = TRUE;
3348 }
3349
3350 /* If we're still referenced, don't go any further! */
3351 if (ThisVNetRoot->NodeReferenceCount != 1)
3352 {
3353 return FALSE;
3354 }
3355
3356 /* If there's an associated device, notify mini-rdr */
3357 if (NetRoot->pSrvCall->RxDeviceObject != NULL)
3358 {
3359 NTSTATUS Status;
3360
3361 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
3362 MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
3363 (void)Status;
3364 }
3365
3366 /* Free parameters */
3367 RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
3368 ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
3369 /* Dereference our NetRoot, we won't reference it anymore */
3370 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3371
3372 /* And free the object! */
3373 RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
3374
3375 return TRUE;
3376 }
3377
3378 NTSTATUS
3379 RxFindOrConstructVirtualNetRoot(
3380 IN PRX_CONTEXT RxContext,
3381 IN PUNICODE_STRING CanonicalName,
3382 IN NET_ROOT_TYPE NetRootType,
3383 IN PUNICODE_STRING RemainingName)
3384 {
3385 ULONG Flags;
3386 NTSTATUS Status;
3387 PVOID Container;
3388 BOOLEAN Construct;
3389 PV_NET_ROOT VNetRoot;
3390 RX_CONNECTION_ID ConnectionID;
3391 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3392 LOCK_HOLDING_STATE LockHoldingState;
3393
3394 PAGED_CODE();
3395
3396 RxDeviceObject = RxContext->RxDeviceObject;
3397 ASSERT(RxDeviceObject->Dispatch != NULL);
3398 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
3399
3400 /* Ask the mini-rdr for connection ID */
3401 ConnectionID.SessionID = 0;
3402 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
3403 {
3404 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
3405 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
3406 {
3407 /* mini-rdr is expected not to fail - unless it's not implemented */
3408 DPRINT1("Failed to initialize connection ID\n");
3409 ASSERT(FALSE);
3410 }
3411 }
3412
3413 RxContext->Create.NetNamePrefixEntry = NULL;
3414
3415 Status = STATUS_MORE_PROCESSING_REQUIRED;
3416 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
3417 LockHoldingState = LHS_SharedLockHeld;
3418 Construct = TRUE;
3419 Flags = 0;
3420
3421 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3422 while (TRUE)
3423 {
3424 PNET_ROOT NetRoot;
3425 PV_NET_ROOT SavedVNetRoot;
3426
3427 /* Look in prefix table */
3428 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
3429 if (Container != NULL)
3430 {
3431 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3432 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
3433 {
3434 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3435 RxDereferenceSrvCall(Container, LockHoldingState);
3436 }
3437 else
3438 {
3439 VNetRoot = Container;
3440 NetRoot = VNetRoot->NetRoot;
3441
3442 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3443 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
3444 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3445 {
3446 Status = STATUS_BAD_NETWORK_PATH;
3447 SavedVNetRoot = NULL;
3448 }
3449 else
3450 {
3451 LUID LogonId;
3452 ULONG SessionId;
3453 PUNICODE_STRING UserName, UserDomain, Password;
3454
3455 /* We can reuse if we use same credentials */
3456 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
3457 &SessionId, &UserName,
3458 &UserDomain, &Password,
3459 &Flags);
3460 if (NT_SUCCESS(Status))
3461 {
3462 SavedVNetRoot = VNetRoot;
3463 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
3464 &LogonId, UserName,
3465 UserDomain, Password,
3466 Flags);
3467 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
3468 {
3469 PLIST_ENTRY ListEntry;
3470
3471 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
3472 ListEntry != &NetRoot->VirtualNetRoots;
3473 ListEntry = ListEntry->Flink)
3474 {
3475 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
3476 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
3477 &LogonId, UserName,
3478 UserDomain, Password,
3479 Flags);
3480 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3481 {
3482 break;
3483 }
3484 }
3485
3486 if (ListEntry == &NetRoot->VirtualNetRoots)
3487 {
3488 SavedVNetRoot = NULL;
3489 }
3490 }
3491
3492 if (!NT_SUCCESS(Status))
3493 {
3494 SavedVNetRoot = NULL;
3495 }
3496
3497 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
3498 }
3499 }
3500
3501 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3502 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
3503 {
3504 if (SavedVNetRoot == NULL)
3505 {
3506 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3507 }
3508 }
3509 /* Reference VNetRoot we'll keep, and dereference current */
3510 else if (SavedVNetRoot != VNetRoot)
3511 {
3512 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3513 if (SavedVNetRoot != NULL)
3514 {
3515 RxReferenceVNetRoot(SavedVNetRoot);
3516 }
3517 }
3518 }
3519
3520 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3521 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3522 {
3523 Construct = FALSE;
3524 break;
3525 }
3526 }
3527
3528 /* If we're locked exclusive, we won't loop again, it was the second pass */
3529 if (LockHoldingState != LHS_SharedLockHeld)
3530 {
3531 break;
3532 }
3533
3534 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3535 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
3536 {
3537 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3538 LockHoldingState = LHS_ExclusiveLockHeld;
3539 break;
3540 }
3541
3542 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3543 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
3544 LockHoldingState = LHS_ExclusiveLockHeld;
3545 }
3546
3547 /* We didn't fail, and didn't find any VNetRoot, construct one */
3548 if (Construct)
3549 {
3550 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
3551
3552 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
3553 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
3554
3555 if (Status == STATUS_SUCCESS)
3556 {
3557 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
3558 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
3559 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
3560
3561 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
3562 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
3563 RemainingName->MaximumLength = RemainingName->Length;
3564
3565 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
3566 {
3567 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
3568 }
3569 VNetRoot->Flags |= Flags;
3570 }
3571 }
3572
3573 /* Release the prefix table - caller expects it to be released */
3574 if (LockHoldingState != LHS_LockNotHeld)
3575 {
3576 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3577 }
3578
3579 /* If we failed creating, quit */
3580 if (Status != STATUS_SUCCESS)
3581 {
3582 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
3583 return Status;
3584 }
3585
3586 /* Otherwise, wait until the VNetRoot is stable */
3587 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
3588 RxWaitForStableVNetRoot(VNetRoot, RxContext);
3589 /* It's all good, update the RX_CONTEXT with all our structs */
3590 if (VNetRoot->Condition == Condition_Good)
3591 {
3592 PNET_ROOT NetRoot;
3593
3594 NetRoot = VNetRoot->NetRoot;
3595 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3596 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3597 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
3598 }
3599 else
3600 {
3601 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3602 RxContext->Create.pVNetRoot = NULL;
3603 Status = STATUS_BAD_NETWORK_PATH;
3604 }
3605
3606 return Status;
3607 }
3608
3609 /*
3610 * @implemented
3611 */
3612 NTSTATUS
3613 RxFindOrCreateConnections(
3614 _In_ PRX_CONTEXT RxContext,
3615 _In_ PUNICODE_STRING CanonicalName,
3616 _In_ NET_ROOT_TYPE NetRootType,
3617 _Out_ PUNICODE_STRING LocalNetRootName,
3618 _Out_ PUNICODE_STRING FilePathName,
3619 _Inout_ PLOCK_HOLDING_STATE LockState,
3620 _In_ PRX_CONNECTION_ID RxConnectionId)
3621 {
3622 PVOID Container;
3623 PSRV_CALL SrvCall;
3624 PNET_ROOT NetRoot;
3625 PV_NET_ROOT VNetRoot;
3626 NTSTATUS Status = STATUS_UNSUCCESSFUL;
3627 PRX_PREFIX_TABLE PrefixTable;
3628 UNICODE_STRING RemainingName, NetRootName;
3629
3630 PAGED_CODE();
3631
3632 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3633 RxContext, CanonicalName, NetRootType, LocalNetRootName,
3634 FilePathName, LockState, RxConnectionId);
3635
3636 *FilePathName = *CanonicalName;
3637 LocalNetRootName->Length = 0;
3638 LocalNetRootName->MaximumLength = 0;
3639 LocalNetRootName->Buffer = CanonicalName->Buffer;
3640
3641 /* UNC path, split it */
3642 if (FilePathName->Buffer[1] == ';')
3643 {
3644 BOOLEAN Slash;
3645 USHORT i, Length;
3646
3647 Slash = FALSE;
3648 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
3649 {
3650 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
3651 {
3652 Slash = TRUE;
3653 break;
3654 }
3655 }
3656
3657 if (!Slash)
3658 {
3659 return STATUS_OBJECT_NAME_INVALID;
3660 }
3661
3662 FilePathName->Buffer = &FilePathName->Buffer[i];
3663 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
3664 LocalNetRootName->Length = Length;
3665 LocalNetRootName->MaximumLength = Length;
3666 FilePathName->Length -= Length;
3667
3668 DPRINT("CanonicalName: %wZ\n", CanonicalName);
3669 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
3670 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
3671 }
3672
3673 Container = NULL;
3674 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
3675
3676 _SEH2_TRY
3677 {
3678 RetryLookup:
3679 ASSERT(*LockState != LHS_LockNotHeld);
3680
3681 /* If previous lookup left something, dereference it */
3682 if (Container != NULL)
3683 {
3684 switch (NodeType(Container))
3685 {
3686 case RDBSS_NTC_SRVCALL:
3687 RxDereferenceSrvCall(Container, *LockState);
3688 break;
3689
3690 case RDBSS_NTC_NETROOT:
3691 RxDereferenceNetRoot(Container, *LockState);
3692 break;
3693
3694 case RDBSS_NTC_V_NETROOT:
3695 RxDereferenceVNetRoot(Container, *LockState);
3696 break;
3697
3698 default:
3699 /* Should never happen */
3700 ASSERT(FALSE);
3701 break;
3702 }
3703 }
3704
3705 /* Look for our NetRoot in prefix table */
3706 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
3707 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
3708
3709 while (TRUE)
3710 {
3711 UNICODE_STRING SrvCallName;
3712
3713 SrvCall = NULL;
3714 NetRoot = NULL;
3715 VNetRoot = NULL;
3716
3717 /* Assume we didn't succeed */
3718 RxContext->Create.pVNetRoot = NULL;
3719 RxContext->Create.pNetRoot = NULL;
3720 RxContext->Create.pSrvCall = NULL;
3721 RxContext->Create.Type = NetRootType;
3722
3723 /* If we found something */
3724 if (Container != NULL)
3725 {
3726 /* A VNetRoot */
3727 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
3728 {
3729 VNetRoot = Container;
3730 /* Use its NetRoot */
3731 NetRoot = VNetRoot->NetRoot;
3732
3733 /* If it's not stable, wait for it to be stable */
3734 if (NetRoot->Condition == Condition_InTransition)
3735 {
3736 RxReleasePrefixTableLock(PrefixTable);
3737 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
3738 RxWaitForStableNetRoot(NetRoot, RxContext);
3739 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3740 *LockState = LHS_ExclusiveLockHeld;
3741
3742 /* Now that's it's ok, retry lookup to find what we want */
3743 if (NetRoot->Condition == Condition_Good)
3744 {
3745 goto RetryLookup;
3746 }
3747 }
3748
3749 /* Is the associated netroot good? */
3750 if (NetRoot->Condition == Condition_Good)
3751 {
3752 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
3753
3754 /* If it is, and SrvCall as well, then, we have our active connection */
3755 if (SrvCall->Condition == Condition_Good &&
3756 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
3757 {
3758 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3759 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3760 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3761
3762 Status = STATUS_CONNECTION_ACTIVE;
3763 _SEH2_LEAVE;
3764 }
3765 }
3766
3767 /* If VNetRoot was well constructed, it means the connection is active */
3768 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
3769 {
3770 Status = STATUS_CONNECTION_ACTIVE;
3771 }
3772 else
3773 {
3774 Status = VNetRoot->ConstructionStatus;
3775 }
3776
3777 RxDereferenceVNetRoot(VNetRoot, *LockState);
3778 _SEH2_LEAVE;
3779 }
3780 /* Can only be a SrvCall */
3781 else
3782 {
3783 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3784 SrvCall = Container;
3785
3786 /* Wait for the SRV_CALL to be stable */
3787 if (SrvCall->Condition == Condition_InTransition)
3788 {
3789 RxReleasePrefixTableLock(PrefixTable);
3790 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
3791 RxWaitForStableSrvCall(SrvCall, RxContext);
3792 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3793 *LockState = LHS_ExclusiveLockHeld;
3794
3795 /* It went good, loop again to find what we look for */
3796 if (SrvCall->Condition == Condition_Good)
3797 {
3798 goto RetryLookup;
3799 }
3800 }
3801
3802 /* If it's not good... */
3803 if (SrvCall->Condition != Condition_Good)
3804 {
3805 /* But SRV_CALL was well constructed, assume a connection was active */
3806 if (SrvCall->Status == STATUS_SUCCESS)
3807 {
3808 Status = STATUS_CONNECTION_ACTIVE;
3809 }
3810 else
3811 {
3812 Status = SrvCall->Status;
3813 }
3814
3815 RxDereferenceSrvCall(SrvCall, *LockState);
3816 _SEH2_LEAVE;
3817 }
3818 }
3819 }
3820
3821 /* If we found a SRV_CALL not matching our DO, quit */
3822 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
3823 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3824 {
3825 RxDereferenceSrvCall(SrvCall, *LockState);
3826 Status = STATUS_BAD_NETWORK_NAME;
3827 _SEH2_LEAVE;
3828 }
3829
3830 /* Now, we want exclusive lock */
3831 if (*LockState == LHS_SharedLockHeld)
3832 {
3833 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
3834 {
3835 RxReleasePrefixTableLock(PrefixTable);
3836 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3837 *LockState = LHS_ExclusiveLockHeld;
3838 goto RetryLookup;
3839 }
3840
3841 RxReleasePrefixTableLock(PrefixTable);
3842 *LockState = LHS_ExclusiveLockHeld;
3843 }
3844
3845 ASSERT(*LockState == LHS_ExclusiveLockHeld);
3846
3847 /* If we reach that point, we found something, no need to create something */
3848 if (Container != NULL)
3849 {
3850 break;
3851 }
3852
3853 /* Get the name for the SRV_CALL */
3854 RxExtractServerName(FilePathName, &SrvCallName, NULL);
3855 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
3856 /* And create the SRV_CALL */
3857 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
3858 if (SrvCall == NULL)
3859 {
3860 Status = STATUS_INSUFFICIENT_RESOURCES;
3861 _SEH2_LEAVE;
3862 }
3863
3864 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3865 RxReferenceSrvCall(SrvCall);
3866 RxContext->Create.pVNetRoot = NULL;
3867 RxContext->Create.pNetRoot = NULL;
3868 RxContext->Create.pSrvCall = NULL;
3869 RxContext->Create.Type = NetRootType;
3870 Container = SrvCall;
3871
3872 /* Construct SRV_CALL, ie, use mini-rdr */
3873 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);