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