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