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