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