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