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