xref: /reactos/sdk/lib/drivers/rdbsslib/rdbss.c (revision d56c9a89)
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/rdbsslib/rdbss.c
23  * PURPOSE:          RDBSS library
24  * PROGRAMMER:       Pierre Schweitzer (pierre@reactos.org)
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <limits.h>
32 #include <dfs.h>
33 #include <copysup.h>
34 
35 #define NDEBUG
36 #include <debug.h>
37 
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
39 
40 typedef
41 NTSTATUS
42 (NTAPI *PRX_FSD_DISPATCH) (
43     PRX_CONTEXT Context);
44 
45 typedef struct _RX_FSD_DISPATCH_VECTOR
46 {
47     PRX_FSD_DISPATCH CommonRoutine;
48 } RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
49 
50 VOID
51 NTAPI
52 RxAcquireFileForNtCreateSection(
53     PFILE_OBJECT FileObject);
54 
55 NTSTATUS
56 NTAPI
57 RxAcquireForCcFlush(
58     PFILE_OBJECT FileObject,
59     PDEVICE_OBJECT DeviceObject);
60 
61 VOID
62 RxAddToTopLevelIrpAllocatedContextsList(
63     PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64 
65 VOID
66 RxAssert(
67     PVOID Assert,
68     PVOID File,
69     ULONG Line,
70     PVOID Message);
71 
72 NTSTATUS
73 NTAPI
74 RxCommonCleanup(
75     PRX_CONTEXT Context);
76 
77 NTSTATUS
78 NTAPI
79 RxCommonClose(
80     PRX_CONTEXT Context);
81 
82 NTSTATUS
83 NTAPI
84 RxCommonCreate(
85     PRX_CONTEXT Context);
86 
87 NTSTATUS
88 NTAPI
89 RxCommonDevFCBCleanup(
90     PRX_CONTEXT Context);
91 
92 NTSTATUS
93 NTAPI
94 RxCommonDevFCBClose(
95     PRX_CONTEXT Context);
96 
97 NTSTATUS
98 NTAPI
99 RxCommonDevFCBFsCtl(
100     PRX_CONTEXT Context);
101 
102 NTSTATUS
103 NTAPI
104 RxCommonDevFCBIoCtl(
105     PRX_CONTEXT Context);
106 
107 NTSTATUS
108 NTAPI
109 RxCommonDevFCBQueryVolInfo(
110     PRX_CONTEXT Context);
111 
112 NTSTATUS
113 NTAPI
114 RxCommonDeviceControl(
115     PRX_CONTEXT Context);
116 
117 NTSTATUS
118 NTAPI
119 RxCommonDirectoryControl(
120     PRX_CONTEXT Context);
121 
122 NTSTATUS
123 NTAPI
124 RxCommonDispatchProblem(
125     PRX_CONTEXT Context);
126 
127 NTSTATUS
128 NTAPI
129 RxCommonFileSystemControl(
130     PRX_CONTEXT Context);
131 
132 NTSTATUS
133 NTAPI
134 RxCommonFlushBuffers(
135     PRX_CONTEXT Context);
136 
137 NTSTATUS
138 NTAPI
139 RxCommonLockControl(
140     PRX_CONTEXT Context);
141 
142 NTSTATUS
143 NTAPI
144 RxCommonQueryEa(
145     PRX_CONTEXT Context);
146 
147 NTSTATUS
148 NTAPI
149 RxCommonQueryInformation(
150     PRX_CONTEXT Context);
151 
152 NTSTATUS
153 NTAPI
154 RxCommonQueryQuotaInformation(
155     PRX_CONTEXT Context);
156 
157 NTSTATUS
158 NTAPI
159 RxCommonQuerySecurity(
160     PRX_CONTEXT Context);
161 
162 NTSTATUS
163 NTAPI
164 RxCommonQueryVolumeInformation(
165     PRX_CONTEXT Context);
166 
167 NTSTATUS
168 NTAPI
169 RxCommonRead(
170     PRX_CONTEXT Context);
171 
172 NTSTATUS
173 NTAPI
174 RxCommonSetEa(
175     PRX_CONTEXT Context);
176 
177 NTSTATUS
178 NTAPI
179 RxCommonSetInformation(
180     PRX_CONTEXT Context);
181 
182 NTSTATUS
183 NTAPI
184 RxCommonSetQuotaInformation(
185     PRX_CONTEXT Context);
186 
187 NTSTATUS
188 NTAPI
189 RxCommonSetSecurity(
190     PRX_CONTEXT Context);
191 
192 NTSTATUS
193 NTAPI
194 RxCommonSetVolumeInformation(
195     PRX_CONTEXT Context);
196 
197 NTSTATUS
198 NTAPI
199 RxCommonUnimplemented(
200     PRX_CONTEXT Context);
201 
202 NTSTATUS
203 NTAPI
204 RxCommonWrite(
205     PRX_CONTEXT Context);
206 
207 VOID
208 RxCopyCreateParameters(
209     IN PRX_CONTEXT RxContext);
210 
211 NTSTATUS
212 RxCreateFromNetRoot(
213     PRX_CONTEXT Context,
214     PUNICODE_STRING NetRootName);
215 
216 NTSTATUS
217 RxCreateTreeConnect(
218     IN PRX_CONTEXT RxContext);
219 
220 BOOLEAN
221 NTAPI
222 RxFastIoCheckIfPossible(
223     PFILE_OBJECT FileObject,
224     PLARGE_INTEGER FileOffset,
225     ULONG Length, BOOLEAN Wait,
226     ULONG LockKey, BOOLEAN CheckForReadOperation,
227     PIO_STATUS_BLOCK IoStatus,
228     PDEVICE_OBJECT DeviceObject);
229 
230 BOOLEAN
231 NTAPI
232 RxFastIoDeviceControl(
233     PFILE_OBJECT FileObject,
234     BOOLEAN Wait,
235     PVOID InputBuffer OPTIONAL,
236     ULONG InputBufferLength,
237     PVOID OutputBuffer OPTIONAL,
238     ULONG OutputBufferLength,
239     ULONG IoControlCode,
240     PIO_STATUS_BLOCK IoStatus,
241     PDEVICE_OBJECT DeviceObject);
242 
243 BOOLEAN
244 NTAPI
245 RxFastIoRead(
246     PFILE_OBJECT FileObject,
247     PLARGE_INTEGER FileOffset,
248     ULONG Length,
249     BOOLEAN Wait,
250     ULONG LockKey,
251     PVOID Buffer,
252     PIO_STATUS_BLOCK IoStatus,
253     PDEVICE_OBJECT DeviceObject);
254 
255 BOOLEAN
256 NTAPI
257 RxFastIoWrite(
258     PFILE_OBJECT FileObject,
259     PLARGE_INTEGER FileOffset,
260     ULONG Length,
261     BOOLEAN Wait,
262     ULONG LockKey,
263     PVOID Buffer,
264     PIO_STATUS_BLOCK IoStatus,
265     PDEVICE_OBJECT DeviceObject);
266 
267 NTSTATUS
268 RxFindOrCreateFcb(
269     PRX_CONTEXT RxContext,
270     PUNICODE_STRING NetRootName);
271 
272 NTSTATUS
273 RxFirstCanonicalize(
274     PRX_CONTEXT RxContext,
275     PUNICODE_STRING FileName,
276     PUNICODE_STRING CanonicalName,
277     PNET_ROOT_TYPE NetRootType);
278 
279 VOID
280 RxFreeCanonicalNameBuffer(
281     PRX_CONTEXT Context);
282 
283 VOID
284 NTAPI
285 RxFspDispatch(
286     IN PVOID Context);
287 
288 VOID
289 NTAPI
290 RxGetRegistryParameters(
291     IN PUNICODE_STRING RegistryPath);
292 
293 NTSTATUS
294 NTAPI
295 RxGetStringRegistryParameter(
296     IN HANDLE KeyHandle,
297     IN PCWSTR KeyName,
298     OUT PUNICODE_STRING OutString,
299     IN PUCHAR Buffer,
300     IN ULONG BufferLength,
301     IN BOOLEAN LogFailure);
302 
303 VOID
304 NTAPI
305 RxInitializeDebugSupport(
306     VOID);
307 
308 VOID
309 NTAPI
310 RxInitializeDispatchVectors(
311     PDRIVER_OBJECT DriverObject);
312 
313 NTSTATUS
314 NTAPI
315 RxInitializeRegistrationStructures(
316     VOID);
317 
318 VOID
319 NTAPI
320 RxInitializeTopLevelIrpPackage(
321     VOID);
322 
323 VOID
324 NTAPI
325 RxInitUnwind(
326     PDRIVER_OBJECT DriverObject,
327     USHORT State);
328 
329 BOOLEAN
330 RxIsThisAnRdbssTopLevelContext(
331     PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332 
333 NTSTATUS
334 NTAPI
335 RxLowIoIoCtlShellCompletion(
336     PRX_CONTEXT RxContext);
337 
338 NTSTATUS
339 RxLowIoReadShell(
340     PRX_CONTEXT RxContext);
341 
342 NTSTATUS
343 NTAPI
344 RxLowIoReadShellCompletion(
345     PRX_CONTEXT RxContext);
346 
347 NTSTATUS
348 RxLowIoWriteShell(
349     IN PRX_CONTEXT RxContext);
350 
351 NTSTATUS
352 NTAPI
353 RxLowIoWriteShellCompletion(
354     PRX_CONTEXT RxContext);
355 
356 PVOID
357 RxNewMapUserBuffer(
358     PRX_CONTEXT RxContext);
359 
360 NTSTATUS
361 RxNotifyChangeDirectory(
362     PRX_CONTEXT RxContext);
363 
364 NTSTATUS
365 RxpQueryInfoMiniRdr(
366     PRX_CONTEXT RxContext,
367     FILE_INFORMATION_CLASS FileInfoClass,
368     PVOID Buffer);
369 
370 VOID
371 RxPurgeNetFcb(
372     PFCB Fcb,
373     PRX_CONTEXT LocalContext);
374 
375 NTSTATUS
376 RxQueryAlternateNameInfo(
377     PRX_CONTEXT RxContext,
378     PFILE_NAME_INFORMATION AltNameInfo);
379 
380 NTSTATUS
381 RxQueryBasicInfo(
382     PRX_CONTEXT RxContext,
383     PFILE_BASIC_INFORMATION BasicInfo);
384 
385 NTSTATUS
386 RxQueryCompressedInfo(
387     PRX_CONTEXT RxContext,
388     PFILE_COMPRESSION_INFORMATION CompressionInfo);
389 
390 NTSTATUS
391 RxQueryDirectory(
392     PRX_CONTEXT RxContext);
393 
394 NTSTATUS
395 RxQueryEaInfo(
396     PRX_CONTEXT RxContext,
397     PFILE_EA_INFORMATION EaInfo);
398 
399 NTSTATUS
400 RxQueryInternalInfo(
401     PRX_CONTEXT RxContext,
402     PFILE_INTERNAL_INFORMATION InternalInfo);
403 
404 NTSTATUS
405 RxQueryNameInfo(
406     PRX_CONTEXT RxContext,
407     PFILE_NAME_INFORMATION NameInfo);
408 
409 NTSTATUS
410 RxQueryPipeInfo(
411     PRX_CONTEXT RxContext,
412     PFILE_PIPE_INFORMATION PipeInfo);
413 
414 NTSTATUS
415 RxQueryPositionInfo(
416     PRX_CONTEXT RxContext,
417     PFILE_POSITION_INFORMATION PositionInfo);
418 
419 NTSTATUS
420 RxQueryStandardInfo(
421     PRX_CONTEXT RxContext,
422     PFILE_STANDARD_INFORMATION StandardInfo);
423 
424 VOID
425 NTAPI
426 RxReadRegistryParameters(
427     VOID);
428 
429 VOID
430 NTAPI
431 RxReleaseFileForNtCreateSection(
432     PFILE_OBJECT FileObject);
433 
434 NTSTATUS
435 NTAPI
436 RxReleaseForCcFlush(
437     PFILE_OBJECT FileObject,
438     PDEVICE_OBJECT DeviceObject);
439 
440 PRX_CONTEXT
441 RxRemoveOverflowEntry(
442     PRDBSS_DEVICE_OBJECT DeviceObject,
443     WORK_QUEUE_TYPE Queue);
444 
445 NTSTATUS
446 RxSearchForCollapsibleOpen(
447     PRX_CONTEXT RxContext,
448     ACCESS_MASK DesiredAccess,
449     ULONG ShareAccess);
450 
451 NTSTATUS
452 RxSetAllocationInfo(
453     PRX_CONTEXT RxContext);
454 
455 NTSTATUS
456 RxSetBasicInfo(
457     PRX_CONTEXT RxContext);
458 
459 NTSTATUS
460 RxSetDispositionInfo(
461     PRX_CONTEXT RxContext);
462 
463 NTSTATUS
464 RxSetEndOfFileInfo(
465     PRX_CONTEXT RxContext);
466 
467 NTSTATUS
468 RxSetPipeInfo(
469     PRX_CONTEXT RxContext);
470 
471 NTSTATUS
472 RxSetPositionInfo(
473     PRX_CONTEXT RxContext);
474 
475 NTSTATUS
476 RxSetRenameInfo(
477     PRX_CONTEXT RxContext);
478 
479 NTSTATUS
480 RxSetSimpleInfo(
481     PRX_CONTEXT RxContext);
482 
483 VOID
484 RxSetupNetFileObject(
485     PRX_CONTEXT RxContext);
486 
487 NTSTATUS
488 RxSystemControl(
489     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
490     IN PIRP Irp);
491 
492 VOID
493 RxUninitializeCacheMap(
494     PRX_CONTEXT RxContext,
495     PFILE_OBJECT FileObject,
496     PLARGE_INTEGER TruncateSize);
497 
498 VOID
499 RxUnstart(
500     PRX_CONTEXT Context,
501     PRDBSS_DEVICE_OBJECT DeviceObject);
502 
503 NTSTATUS
504 RxXXXControlFileCallthru(
505     PRX_CONTEXT Context);
506 
507 PVOID
508 NTAPI
509 _RxAllocatePoolWithTag(
510     _In_ POOL_TYPE PoolType,
511     _In_ SIZE_T NumberOfBytes,
512     _In_ ULONG Tag);
513 
514 VOID
515 NTAPI
516 _RxFreePool(
517     _In_ PVOID Buffer);
518 
519 VOID
520 NTAPI
521 _RxFreePoolWithTag(
522     _In_ PVOID Buffer,
523     _In_ ULONG Tag);
524 
525 WCHAR RxStarForTemplate = '*';
526 WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
528 BOOLEAN DisableFlushOnCleanup = FALSE;
529 ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;
530 LIST_ENTRY RxActiveContexts;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList;
532 FAST_MUTEX RxContextPerFileSerializationMutex;
533 RDBSS_DATA RxData;
534 FCB RxDeviceFCB;
535 BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
537 {
538     { RxCommonDispatchProblem },
539     { RxCommonDispatchProblem },
540     { RxCommonDevFCBClose },
541     { RxCommonDispatchProblem },
542     { RxCommonDispatchProblem },
543     { RxCommonDispatchProblem },
544     { RxCommonDispatchProblem },
545     { RxCommonDispatchProblem },
546     { RxCommonDispatchProblem },
547     { RxCommonDispatchProblem },
548     { RxCommonDevFCBQueryVolInfo },
549     { RxCommonDispatchProblem },
550     { RxCommonDispatchProblem },
551     { RxCommonDevFCBFsCtl },
552     { RxCommonDevFCBIoCtl },
553     { RxCommonDevFCBIoCtl },
554     { RxCommonDispatchProblem },
555     { RxCommonDispatchProblem },
556     { RxCommonDevFCBCleanup },
557     { RxCommonDispatchProblem },
558     { RxCommonDispatchProblem },
559     { RxCommonDispatchProblem },
560     { RxCommonUnimplemented },
561     { RxCommonUnimplemented },
562     { RxCommonUnimplemented },
563     { RxCommonUnimplemented },
564     { RxCommonUnimplemented },
565     { RxCommonUnimplemented },
566 };
567 RDBSS_EXPORTS RxExports;
568 FAST_IO_DISPATCH RxFastIoDispatch;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
571 {
572     { RxCommonCreate },
573     { RxCommonUnimplemented },
574     { RxCommonClose },
575     { RxCommonRead },
576     { RxCommonWrite },
577     { RxCommonQueryInformation },
578     { RxCommonSetInformation },
579     { RxCommonQueryEa },
580     { RxCommonSetEa },
581     { RxCommonFlushBuffers },
582     { RxCommonQueryVolumeInformation },
583     { RxCommonSetVolumeInformation },
584     { RxCommonDirectoryControl },
585     { RxCommonFileSystemControl },
586     { RxCommonDeviceControl },
587     { RxCommonDeviceControl },
588     { RxCommonUnimplemented },
589     { RxCommonLockControl },
590     { RxCommonCleanup },
591     { RxCommonUnimplemented },
592     { RxCommonQuerySecurity },
593     { RxCommonSetSecurity },
594     { RxCommonUnimplemented },
595     { RxCommonUnimplemented },
596     { RxCommonUnimplemented },
597     { RxCommonQueryQuotaInformation },
598     { RxCommonSetQuotaInformation },
599     { RxCommonUnimplemented },
600 };
601 ULONG RxFsdEntryCount;
602 LIST_ENTRY RxIrpsList;
603 KSPIN_LOCK RxIrpsListSpinLock;
604 KMUTEX RxScavengerMutex;
605 KMUTEX RxSerializationMutex;
606 UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
607 KSPIN_LOCK TopLevelIrpSpinLock;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList;
609 BOOLEAN RxForceQFIPassThrough = FALSE;
610 BOOLEAN RxNoAsync = FALSE;
611 
612 DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
613 
614 #if RDBSS_ASSERTS
615 #ifdef ASSERT
616 #undef ASSERT
617 #endif
618 
619 #define ASSERT(exp)                               \
620     if (!(exp))                                   \
621     {                                             \
622         RxAssert(#exp, __FILE__, __LINE__, NULL); \
623     }
624 #endif
625 
626 #if RX_POOL_WRAPPER
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
629 #undef RxFreePool
630 
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
635 #endif
636 
637 /* FUNCTIONS ****************************************************************/
638 
639 /*
640  * @implemented
641  */
642 VOID
643 CheckForLoudOperations(
644     PRX_CONTEXT RxContext)
645 {
646     PAGED_CODE();
647 
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
649 
650     /* Are loud operations enabled? */
651     if (RxLoudLowIoOpsEnabled)
652     {
653         PFCB Fcb;
654 
655         /* If so, the operation will be loud only if filename ends with all.scr */
656         Fcb = (PFCB)RxContext->pFcb;
657         if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
658                              L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
659         {
660             SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
661         }
662     }
663 #undef ALLSCR_LENGTH
664 }
665 
666 /*
667  * @implemented
668  */
669 VOID
670 __RxInitializeTopLevelIrpContext(
671     IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
672     IN PIRP Irp,
673     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
674     IN ULONG Flags)
675 {
676     DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
677 
678     RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
679     TopLevelContext->Irp = Irp;
680     TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
681     TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
682     TopLevelContext->RxDeviceObject = RxDeviceObject;
683     TopLevelContext->Previous = IoGetTopLevelIrp();
684     TopLevelContext->Thread = PsGetCurrentThread();
685 
686     /* We cannot add to list something that'd come from stack */
687     if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
688     {
689         RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext);
690     }
691 }
692 
693 /*
694  * @implemented
695  */
696 VOID
697 __RxWriteReleaseResources(
698     PRX_CONTEXT RxContext,
699     BOOLEAN ResourceOwnerSet,
700     ULONG LineNumber,
701     PCSTR FileName,
702     ULONG SerialNumber)
703 {
704     PFCB Fcb;
705 
706     PAGED_CODE();
707 
708     ASSERT(RxContext != NULL);
709 
710     Fcb = (PFCB)RxContext->pFcb;
711     ASSERT(Fcb != NULL);
712 
713     /* If FCB resource was acquired, release it */
714     if (RxContext->FcbResourceAcquired)
715     {
716         /* Taking care of owner */
717         if (ResourceOwnerSet)
718         {
719             RxReleaseFcbForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
720         }
721         else
722         {
723             RxReleaseFcb(RxContext, Fcb);
724         }
725 
726         RxContext->FcbResourceAcquired = FALSE;
727     }
728 
729     /* If FCB paging resource was acquired, release it */
730     if (RxContext->FcbPagingIoResourceAcquired)
731     {
732         /* Taking care of owner */
733         if (ResourceOwnerSet)
734         {
735             RxReleasePagingIoResourceForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
736         }
737         else
738         {
739             RxReleasePagingIoResource(RxContext, Fcb);
740         }
741 
742         /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
743     }
744 }
745 
746 /*
747  * @implemented
748  */
749 VOID
750 RxAddToTopLevelIrpAllocatedContextsList(
751     PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
752 {
753     KIRQL OldIrql;
754 
755     DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
756 
757     ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
758     ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
759 
760     KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
761     InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
762     KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
763 }
764 
765 /*
766  * @implemented
767  */
768 VOID
769 NTAPI
770 RxAddToWorkque(
771     IN PRX_CONTEXT RxContext,
772     IN PIRP Irp)
773 {
774     ULONG Queued;
775     KIRQL OldIrql;
776     WORK_QUEUE_TYPE Queue;
777     PIO_STACK_LOCATION Stack;
778 
779     Stack = RxContext->CurrentIrpSp;
780     RxContext->PostRequest = FALSE;
781 
782     /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783     if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
784         Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
785     {
786         Queue = DelayedWorkQueue;
787         SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
788     }
789     else
790     {
791         Queue = CriticalWorkQueue;
792         SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
793     }
794 
795     /* Check for overflow */
796     if (Stack->FileObject != NULL)
797     {
798         KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
799 
800         Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
801         /* In case of an overflow, add the new queued call to the overflow list */
802         if (Queued > 1)
803         {
804             InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
805             InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
806             ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
807 
808             KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
809             return;
810         }
811 
812         KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
813     }
814 
815     ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
816     ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
817 }
818 
819 /*
820  * @implemented
821  */
822 VOID
823 RxAdjustFileTimesAndSize(
824     PRX_CONTEXT Context)
825 {
826     PFCB Fcb;
827     PFOBX Fobx;
828     NTSTATUS Status;
829     PFILE_OBJECT FileObject;
830     LARGE_INTEGER CurrentTime;
831     FILE_BASIC_INFORMATION FileBasicInfo;
832     FILE_END_OF_FILE_INFORMATION FileEOFInfo;
833     BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
834 
835     PAGED_CODE();
836 
837     FileObject = Context->CurrentIrpSp->FileObject;
838     /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839     if (FileObject->PrivateCacheMap == NULL)
840     {
841         return;
842     }
843 
844     /* Get now */
845     KeQuerySystemTime(&CurrentTime);
846 
847     Fobx = (PFOBX)Context->pFobx;
848     /* Was the file modified? */
849     FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
850     /* We'll set last write if it was modified and user didn't update yet */
851     SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
852     /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853     SetLastAccess = SetLastWrite ||
854                     (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
855                      !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
856     /* We'll set last change if it was modified and user didn't update yet */
857     SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
858 
859     /* Nothing to update? Job done */
860     if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
861     {
862         return;
863     }
864 
865     Fcb = (PFCB)Context->pFcb;
866     /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
867     NeedUpdate = FALSE;
868     RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
869 
870     /* Update lastwrite time if required */
871     if (SetLastWrite)
872     {
873         NeedUpdate = TRUE;
874         Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
875         FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
876     }
877 
878     /* Update lastaccess time if required */
879     if (SetLastAccess)
880     {
881         NeedUpdate = TRUE;
882         Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
883         FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
884     }
885 
886     /* Update lastchange time if required */
887     if (SetLastChange)
888     {
889         NeedUpdate = TRUE;
890         Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
891         FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
892     }
893 
894     /* If one of the date was modified, issue a call to mini-rdr */
895     if (NeedUpdate)
896     {
897         Context->Info.FileInformationClass = FileBasicInformation;
898         Context->Info.Buffer = &FileBasicInfo;
899         Context->Info.Length = sizeof(FileBasicInfo);
900 
901         MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
902         (void)Status;
903     }
904 
905     /* If the file was modified, update its EOF */
906     if (FileModified)
907     {
908         FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
909 
910         Context->Info.FileInformationClass = FileEndOfFileInformation;
911         Context->Info.Buffer = &FileEOFInfo;
912         Context->Info.Length = sizeof(FileEOFInfo);
913 
914         MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
915         (void)Status;
916     }
917 }
918 
919 /*
920  * @implemented
921  */
922 NTSTATUS
923 RxAllocateCanonicalNameBuffer(
924     PRX_CONTEXT RxContext,
925     PUNICODE_STRING CanonicalName,
926     USHORT CanonicalLength)
927 {
928     PAGED_CODE();
929 
930     DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
931 
932     /* Context must be free of any already allocated name */
933     ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
934 
935     /* Validate string length */
936     if (CanonicalLength > USHRT_MAX - 1)
937     {
938         CanonicalName->Buffer = NULL;
939         return STATUS_OBJECT_PATH_INVALID;
940     }
941 
942     CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
943     if (CanonicalName->Buffer == NULL)
944     {
945         return STATUS_INSUFFICIENT_RESOURCES;
946     }
947 
948     CanonicalName->Length = 0;
949     CanonicalName->MaximumLength = CanonicalLength;
950 
951     /* Set the two places - they must always be identical */
952     RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
953     RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
954 
955     return STATUS_SUCCESS;
956 }
957 
958 /*
959  * @implemented
960  */
961 VOID
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
963    PFOBX Fobx)
964 {
965     KIRQL OldIrql;
966     PLIST_ENTRY Entry;
967     PRX_CONTEXT Context;
968     LIST_ENTRY ContextsToCancel;
969 
970     /* Init a list for the contexts to cancel */
971     InitializeListHead(&ContextsToCancel);
972 
973     /* Lock our list lock */
974     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
975 
976     /* Now, browse all the active contexts, to find the associated ones */
977     Entry = RxActiveContexts.Flink;
978     while (Entry != &RxActiveContexts)
979     {
980         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
981         Entry = Entry->Flink;
982 
983         /* Not the IRP we're looking for, ignore */
984         if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
985             Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
986         {
987             continue;
988         }
989 
990         /* Not the FOBX we're looking for, ignore */
991         if ((PFOBX)Context->pFobx != Fobx)
992         {
993             continue;
994         }
995 
996         /* No cancel routine (can't be cancel, then), ignore */
997         if (Context->MRxCancelRoutine == NULL)
998         {
999             continue;
1000         }
1001 
1002         /* Mark our context as cancelled */
1003         SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1004 
1005         /* Move it to our list */
1006         RemoveEntryList(&Context->ContextListEntry);
1007         InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1008 
1009         InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1010     }
1011 
1012     /* Done with the contexts */
1013     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1014 
1015     /* Now, handle all our "extracted" contexts */
1016     while (!IsListEmpty(&ContextsToCancel))
1017     {
1018         Entry = RemoveHeadList(&ContextsToCancel);
1019         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1020 
1021         /* If they had an associated IRP (should be always true) */
1022         if (Context->CurrentIrp != NULL)
1023         {
1024             /* Then, call cancel routine */
1025             ASSERT(Context->MRxCancelRoutine != NULL);
1026             DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1027             Context->MRxCancelRoutine(Context);
1028         }
1029 
1030         /* And delete the context */
1031         RxDereferenceAndDeleteRxContext(Context);
1032     }
1033 }
1034 
1035 /*
1036  * @implemented
1037  */
1038 NTSTATUS
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040    PV_NET_ROOT VNetRoot,
1041    BOOLEAN ForceFilesClosed)
1042 {
1043     KIRQL OldIrql;
1044     NTSTATUS Status;
1045     PLIST_ENTRY Entry;
1046     PRX_CONTEXT Context;
1047     LIST_ENTRY ContextsToCancel;
1048 
1049     /* Init a list for the contexts to cancel */
1050     InitializeListHead(&ContextsToCancel);
1051 
1052     /* Lock our list lock */
1053     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1054 
1055     /* Assume success */
1056     Status = STATUS_SUCCESS;
1057 
1058     /* Now, browse all the active contexts, to find the associated ones */
1059     Entry = RxActiveContexts.Flink;
1060     while (Entry != &RxActiveContexts)
1061     {
1062         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1063         Entry = Entry->Flink;
1064 
1065         /* Not the IRP we're looking for, ignore */
1066         if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
1067             Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
1068         {
1069             continue;
1070         }
1071 
1072         /* Not the VNetRoot we're looking for, ignore */
1073         if (Context->pFcb == NULL ||
1074             (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
1075         {
1076             continue;
1077         }
1078 
1079         /* No cancel routine (can't be cancel, then), ignore */
1080         if (Context->MRxCancelRoutine == NULL)
1081         {
1082             continue;
1083         }
1084 
1085         /* At that point, we found a matching context
1086          * If we're not asked to force close, then fail - it's still open
1087          */
1088         if (!ForceFilesClosed)
1089         {
1090             Status = STATUS_FILES_OPEN;
1091             break;
1092         }
1093 
1094         /* Mark our context as cancelled */
1095         SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1096 
1097         /* Move it to our list */
1098         RemoveEntryList(&Context->ContextListEntry);
1099         InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1100 
1101         InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1102     }
1103 
1104     /* Done with the contexts */
1105     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1106 
1107     if (Status != STATUS_SUCCESS)
1108     {
1109         return Status;
1110     }
1111 
1112     /* Now, handle all our "extracted" contexts */
1113     while (!IsListEmpty(&ContextsToCancel))
1114     {
1115         Entry = RemoveHeadList(&ContextsToCancel);
1116         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1117 
1118         /* If they had an associated IRP (should be always true) */
1119         if (Context->CurrentIrp != NULL)
1120         {
1121             /* Then, call cancel routine */
1122             ASSERT(Context->MRxCancelRoutine != NULL);
1123             DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1124             Context->MRxCancelRoutine(Context);
1125         }
1126 
1127         /* And delete the context */
1128         RxDereferenceAndDeleteRxContext(Context);
1129     }
1130 
1131     return Status;
1132 }
1133 
1134 VOID
1135 NTAPI
1136 RxCancelRoutine(
1137     PDEVICE_OBJECT DeviceObject,
1138     PIRP Irp)
1139 {
1140     UNIMPLEMENTED;
1141 }
1142 
1143 /*
1144  * @implemented
1145  */
1146 NTSTATUS
1147 RxCanonicalizeFileNameByServerSpecs(
1148     PRX_CONTEXT RxContext,
1149     PUNICODE_STRING NetRootName)
1150 {
1151     USHORT NextChar, CurChar;
1152     USHORT MaxChars;
1153 
1154     PAGED_CODE();
1155 
1156     /* Validate file name is not empty */
1157     MaxChars = NetRootName->Length / sizeof(WCHAR);
1158     if (MaxChars == 0)
1159     {
1160         return STATUS_MORE_PROCESSING_REQUIRED;
1161     }
1162 
1163     /* Validate name is correct */
1164     for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
1165     {
1166         USHORT i;
1167 
1168         for (i = NextChar + 1; i < MaxChars; ++i)
1169         {
1170             if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
1171             {
1172                 break;
1173             }
1174         }
1175 
1176         CurChar = i - 1;
1177         if (CurChar == NextChar)
1178         {
1179             if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
1180             {
1181                 continue;
1182             }
1183 
1184             if (CurChar != 0)
1185             {
1186                 if (CurChar >= MaxChars - 1)
1187                 {
1188                     continue;
1189                 }
1190 
1191                 if (NetRootName->Buffer[CurChar + 1] != ':')
1192                 {
1193                     return STATUS_OBJECT_PATH_SYNTAX_BAD;
1194                 }
1195             }
1196             else
1197             {
1198                 if (NetRootName->Buffer[1] != ':')
1199                 {
1200                     return STATUS_OBJECT_PATH_SYNTAX_BAD;
1201                 }
1202             }
1203         }
1204         else
1205         {
1206             if ((CurChar - NextChar) == 1)
1207             {
1208                 if (NetRootName->Buffer[NextChar + 2] != '.')
1209                 {
1210                     continue;
1211                 }
1212 
1213                 if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
1214                 {
1215                     return STATUS_OBJECT_PATH_SYNTAX_BAD;
1216                 }
1217             }
1218             else
1219             {
1220                 if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
1221                     || NetRootName->Buffer[NextChar + 1] != '.')
1222                 {
1223                     continue;
1224                 }
1225 
1226                 if (NetRootName->Buffer[NextChar + 2] == '.')
1227                 {
1228                     return STATUS_OBJECT_PATH_SYNTAX_BAD;
1229                 }
1230             }
1231         }
1232     }
1233 
1234     return STATUS_MORE_PROCESSING_REQUIRED;
1235 }
1236 
1237 NTSTATUS
1238 RxCanonicalizeNameAndObtainNetRoot(
1239     PRX_CONTEXT RxContext,
1240     PUNICODE_STRING FileName,
1241     PUNICODE_STRING NetRootName)
1242 {
1243     NTSTATUS Status;
1244     NET_ROOT_TYPE NetRootType;
1245     UNICODE_STRING CanonicalName;
1246 
1247     PAGED_CODE();
1248 
1249     NetRootType = NET_ROOT_WILD;
1250 
1251     RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1252     RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1253 
1254     /* if not relative opening, just handle the passed name */
1255     if (RxContext->CurrentIrpSp->FileObject->RelatedFileObject == NULL)
1256     {
1257         Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1258         if (!NT_SUCCESS(Status))
1259         {
1260             return Status;
1261         }
1262     }
1263     else
1264     {
1265         PFCB Fcb;
1266 
1267         /* Make sure we have a valid FCB and a FOBX */
1268         Fcb = RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext;
1269         if (Fcb == NULL ||
1270             RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext2 == NULL)
1271         {
1272             return STATUS_INVALID_PARAMETER;
1273         }
1274 
1275         if (!NodeTypeIsFcb(Fcb))
1276         {
1277             return STATUS_INVALID_PARAMETER;
1278         }
1279 
1280         UNIMPLEMENTED;
1281     }
1282 
1283     /* Get/Create the associated VNetRoot for opening */
1284     Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1285     if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1286         BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
1287     {
1288         ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1289 
1290         RxFreeCanonicalNameBuffer(RxContext);
1291         Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1292         if (NT_SUCCESS(Status))
1293         {
1294             Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1295         }
1296     }
1297 
1298     /* Filename cannot contain wildcards */
1299     if (FsRtlDoesNameContainWildCards(NetRootName))
1300     {
1301         Status = STATUS_OBJECT_NAME_INVALID;
1302     }
1303 
1304     /* Make sure file name is correct */
1305     if (NT_SUCCESS(Status))
1306     {
1307         Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1308     }
1309 
1310     /* Give the mini-redirector a chance to prepare the name */
1311     if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
1312     {
1313         if (RxContext->Create.pNetRoot != NULL)
1314         {
1315             NTSTATUS IgnoredStatus;
1316 
1317             MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1318                          MRxPreparseName, (RxContext, NetRootName));
1319             (void)IgnoredStatus;
1320         }
1321     }
1322 
1323     return Status;
1324 }
1325 
1326 VOID
1327 NTAPI
1328 RxCheckFcbStructuresForAlignment(
1329     VOID)
1330 {
1331     UNIMPLEMENTED;
1332 }
1333 
1334 #if DBG
1335 NTSTATUS
1336 RxCheckShareAccess(
1337     _In_ ACCESS_MASK DesiredAccess,
1338     _In_ ULONG DesiredShareAccess,
1339     _Inout_ PFILE_OBJECT FileObject,
1340     _Inout_ PSHARE_ACCESS ShareAccess,
1341     _In_ BOOLEAN Update,
1342     _In_ PSZ where,
1343     _In_ PSZ wherelogtag)
1344 {
1345     PAGED_CODE();
1346 
1347     RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1348     RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1349 
1350     return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
1351 }
1352 #endif
1353 
1354 /*
1355  * @implemented
1356  */
1357 NTSTATUS
1358 RxCheckShareAccessPerSrvOpens(
1359     IN PFCB Fcb,
1360     IN ACCESS_MASK DesiredAccess,
1361     IN ULONG DesiredShareAccess)
1362 {
1363     BOOLEAN ReadAccess;
1364     BOOLEAN WriteAccess;
1365     BOOLEAN DeleteAccess;
1366     PSHARE_ACCESS ShareAccess;
1367 
1368     PAGED_CODE();
1369 
1370     ShareAccess = &Fcb->ShareAccessPerSrvOpens;
1371 
1372     RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1373     RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1374 
1375     /* Check if any access wanted */
1376     ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
1377     WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
1378     DeleteAccess = (DesiredAccess & DELETE) != 0;
1379 
1380     if (ReadAccess || WriteAccess || DeleteAccess)
1381     {
1382         BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1383         BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1384         BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1385 
1386         /* Check whether there's a violation */
1387         if ((ReadAccess &&
1388              (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1389             (WriteAccess &&
1390              (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1391             (DeleteAccess &&
1392              (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1393             ((ShareAccess->Readers != 0) && !SharedRead) ||
1394             ((ShareAccess->Writers != 0) && !SharedWrite) ||
1395             ((ShareAccess->Deleters != 0) && !SharedDelete))
1396         {
1397             return STATUS_SHARING_VIOLATION;
1398         }
1399     }
1400 
1401     return STATUS_SUCCESS;
1402 }
1403 
1404 VOID
1405 RxCleanupPipeQueues(
1406     PRX_CONTEXT Context)
1407 {
1408     UNIMPLEMENTED;
1409 }
1410 
1411 /*
1412  * @implemented
1413  */
1414 NTSTATUS
1415 RxCloseAssociatedSrvOpen(
1416     IN PFOBX Fobx,
1417     IN PRX_CONTEXT RxContext OPTIONAL)
1418 {
1419     PFCB Fcb;
1420     NTSTATUS Status;
1421     PSRV_OPEN SrvOpen;
1422     BOOLEAN CloseSrvOpen;
1423     PRX_CONTEXT LocalContext;
1424 
1425     PAGED_CODE();
1426 
1427     /* Assume SRV_OPEN is already closed */
1428     CloseSrvOpen = FALSE;
1429     /* If we have a FOBX, we'll have to close it */
1430     if (Fobx != NULL)
1431     {
1432         /* If the FOBX isn't closed yet */
1433         if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1434         {
1435             SrvOpen = Fobx->SrvOpen;
1436             Fcb = (PFCB)SrvOpen->pFcb;
1437             /* Check whether we've to close SRV_OPEN first */
1438             if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1439             {
1440                 CloseSrvOpen = TRUE;
1441             }
1442             else
1443             {
1444                 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1445 
1446                 /* Not much to do */
1447                 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1448 
1449                 if (SrvOpen->OpenCount > 0)
1450                 {
1451                     --SrvOpen->OpenCount;
1452                 }
1453             }
1454         }
1455 
1456         /* No need to close SRV_OPEN, so close FOBX */
1457         if (!CloseSrvOpen)
1458         {
1459             RxMarkFobxOnClose(Fobx);
1460 
1461             return STATUS_SUCCESS;
1462         }
1463     }
1464     else
1465     {
1466         /* No FOBX? No RX_CONTEXT, ok, job done! */
1467         if (RxContext == NULL)
1468         {
1469             return STATUS_SUCCESS;
1470         }
1471 
1472         /* Get the FCB from RX_CONTEXT */
1473         Fcb = (PFCB)RxContext->pFcb;
1474         SrvOpen = NULL;
1475     }
1476 
1477     /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1478     if (RxContext == NULL)
1479     {
1480         ASSERT(Fobx != NULL);
1481 
1482         LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
1483         if (LocalContext == NULL)
1484         {
1485             return STATUS_INSUFFICIENT_RESOURCES;
1486         }
1487 
1488         LocalContext->MajorFunction = 2;
1489         LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1490         LocalContext->pFobx = (PMRX_FOBX)Fobx;
1491         LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1492     }
1493     else
1494     {
1495         LocalContext = RxContext;
1496     }
1497 
1498     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1499 
1500     /* Now, close the FOBX */
1501     if (Fobx != NULL)
1502     {
1503         RxMarkFobxOnClose(Fobx);
1504     }
1505     else
1506     {
1507         InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1508     }
1509 
1510     /* If not a "standard" file, SRV_OPEN can be null */
1511     if (SrvOpen == NULL)
1512     {
1513         ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
1514         RxDereferenceNetFcb(Fcb);
1515 
1516         if (LocalContext != RxContext)
1517         {
1518             RxDereferenceAndDeleteRxContext(LocalContext);
1519         }
1520 
1521         return STATUS_SUCCESS;
1522     }
1523 
1524     /* If SRV_OPEN isn't in a good condition, nothing to close */
1525     if (SrvOpen->Condition != Condition_Good)
1526     {
1527         if (LocalContext != RxContext)
1528         {
1529             RxDereferenceAndDeleteRxContext(LocalContext);
1530         }
1531 
1532         return STATUS_SUCCESS;
1533     }
1534 
1535     /* Decrease open count */
1536     if (SrvOpen->OpenCount > 0)
1537     {
1538         --SrvOpen->OpenCount;
1539     }
1540 
1541     /* If we're the only one left, is there a FOBX handled by Scavenger? */
1542     if (SrvOpen->OpenCount == 1)
1543     {
1544         if (!IsListEmpty(&SrvOpen->FobxList))
1545         {
1546             if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1547             {
1548                 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1549             }
1550         }
1551     }
1552 
1553     /* Nothing left, purge FCB */
1554     if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1555     {
1556         RxPurgeNetFcb(Fcb, LocalContext);
1557     }
1558 
1559     /* Already closed? Job done! */
1560     SrvOpen = Fobx->SrvOpen;
1561     if (SrvOpen == NULL ||
1562         (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1563         BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1564     {
1565         SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1566         if (LocalContext != RxContext)
1567         {
1568             RxDereferenceAndDeleteRxContext(LocalContext);
1569         }
1570 
1571         return STATUS_SUCCESS;
1572     }
1573 
1574     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1575 
1576     /* Inform mini-rdr about closing */
1577     MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1578     DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1579            Status, RxContext, Fobx, Fcb, SrvOpen);
1580 
1581     /* And mark as such */
1582     SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1583     SrvOpen->Key = (PVOID)-1;
1584 
1585     /* If we were delayed, we're not! */
1586     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1587     {
1588         InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1589     }
1590 
1591     /* Clear access */
1592     RxRemoveShareAccessPerSrvOpens(SrvOpen);
1593     RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
1594 
1595     /* Dereference */
1596     RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1597 
1598     /* Mark the FOBX closed as well */
1599     SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1600 
1601     if (LocalContext != RxContext)
1602     {
1603         RxDereferenceAndDeleteRxContext(LocalContext);
1604     }
1605 
1606     return Status;
1607 }
1608 
1609 /*
1610  * @implemented
1611  */
1612 NTSTATUS
1613 RxCollapseOrCreateSrvOpen(
1614     PRX_CONTEXT RxContext)
1615 {
1616     PFCB Fcb;
1617     NTSTATUS Status;
1618     ULONG Disposition;
1619     PSRV_OPEN SrvOpen;
1620     USHORT ShareAccess;
1621     PIO_STACK_LOCATION Stack;
1622     ACCESS_MASK DesiredAccess;
1623     RX_BLOCK_CONDITION FcbCondition;
1624 
1625     PAGED_CODE();
1626 
1627     DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1628 
1629     Fcb = (PFCB)RxContext->pFcb;
1630     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1631     ++Fcb->UncleanCount;
1632 
1633     Stack = RxContext->CurrentIrpSp;
1634     DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1635     ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1636 
1637     Disposition = RxContext->Create.NtCreateParameters.Disposition;
1638 
1639     /* Try to find a reusable SRV_OPEN */
1640     Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
1641     if (Status == STATUS_NOT_FOUND)
1642     {
1643         /* If none found, create one */
1644         SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb);
1645         if (SrvOpen == NULL)
1646         {
1647             Status = STATUS_INSUFFICIENT_RESOURCES;
1648         }
1649         else
1650         {
1651             SrvOpen->DesiredAccess = DesiredAccess;
1652             SrvOpen->ShareAccess = ShareAccess;
1653             Status = STATUS_SUCCESS;
1654         }
1655 
1656         RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1657 
1658         if (Status != STATUS_SUCCESS)
1659         {
1660             FcbCondition = Condition_Bad;
1661         }
1662         else
1663         {
1664             RxInitiateSrvOpenKeyAssociation(SrvOpen);
1665 
1666             /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1667             RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1668             /* Inform the mini-rdr we're handling a create */
1669             MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCreate, (RxContext));
1670             ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1671 
1672             DPRINT("MRxCreate returned: %x\n", Status);
1673             if (Status == STATUS_SUCCESS)
1674             {
1675                 /* In case of overwrite, reset file size */
1676                 if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
1677                 {
1678                     RxAcquirePagingIoResource(RxContext, Fcb);
1679                     Fcb->Header.AllocationSize.QuadPart = 0LL;
1680                     Fcb->Header.FileSize.QuadPart = 0LL;
1681                     Fcb->Header.ValidDataLength.QuadPart = 0LL;
1682                     RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1683                     CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1684                     RxReleasePagingIoResource(RxContext, Fcb);
1685                 }
1686                 else
1687                 {
1688                     /* Otherwise, adjust sizes */
1689                     RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1690                     if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1691                     {
1692                         RxAdjustAllocationSizeforCC(Fcb);
1693                     }
1694                     CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1695                 }
1696             }
1697 
1698             /* Set the IoStatus with information returned by mini-rdr */
1699             RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1700 
1701             SrvOpen->OpenStatus = Status;
1702             /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1703             RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
1704 
1705             ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1706 
1707             RxCompleteSrvOpenKeyAssociation(SrvOpen);
1708 
1709             if (Status == STATUS_SUCCESS)
1710             {
1711                 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1712                 {
1713                     ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
1714                 }
1715                 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1716                 FcbCondition = Condition_Good;
1717             }
1718             else
1719             {
1720                 FcbCondition = Condition_Bad;
1721                 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1722                 RxContext->pRelevantSrvOpen = NULL;
1723 
1724                 if (RxContext->pFobx != NULL)
1725                 {
1726                     RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
1727                     RxContext->pFobx = NULL;
1728                 }
1729             }
1730         }
1731 
1732         /* Set FCB state -  good or bad - depending on whether create succeed */
1733         DPRINT("Transitioning FCB %p to condition %lx\n", Fcb, Fcb->Condition);
1734         RxTransitionNetFcb(Fcb, FcbCondition);
1735     }
1736     else if (Status == STATUS_SUCCESS)
1737     {
1738         BOOLEAN IsGood, ExtraOpen;
1739 
1740         /* A reusable SRV_OPEN was found */
1741         RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
1742         ExtraOpen = FALSE;
1743 
1744         SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1745 
1746         IsGood = (SrvOpen->Condition == Condition_Good);
1747         /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1748         if (!StableCondition(SrvOpen->Condition))
1749         {
1750             RxReferenceSrvOpen(SrvOpen);
1751             ++SrvOpen->OpenCount;
1752             ExtraOpen = TRUE;
1753 
1754             RxReleaseFcb(RxContext, Fcb);
1755             RxContext->Create.FcbAcquired = FALSE;
1756 
1757             RxWaitForStableSrvOpen(SrvOpen, RxContext);
1758 
1759             if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, Fcb)))
1760             {
1761                 RxContext->Create.FcbAcquired = TRUE;
1762             }
1763 
1764             IsGood = (SrvOpen->Condition == Condition_Good);
1765         }
1766 
1767         /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1768         if (IsGood)
1769         {
1770             MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1771 
1772             ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1773         }
1774         else
1775         {
1776             Status = SrvOpen->OpenStatus;
1777         }
1778 
1779         if (ExtraOpen)
1780         {
1781             --SrvOpen->OpenCount;
1782             RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1783         }
1784     }
1785 
1786     --Fcb->UncleanCount;
1787 
1788     DPRINT("Status: %x\n", Status);
1789     return Status;
1790 }
1791 
1792 /*
1793  * @implemented
1794  */
1795 NTSTATUS
1796 NTAPI
1797 RxCommonCleanup(
1798     PRX_CONTEXT Context)
1799 {
1800 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1801     PFCB Fcb;
1802     PFOBX Fobx;
1803     ULONG OpenCount;
1804     NTSTATUS Status;
1805     PNET_ROOT NetRoot;
1806     PFILE_OBJECT FileObject;
1807     LARGE_INTEGER TruncateSize;
1808     PLARGE_INTEGER TruncateSizePtr;
1809     BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1810 
1811     PAGED_CODE();
1812 
1813     Fcb = (PFCB)Context->pFcb;
1814     Fobx = (PFOBX)Context->pFobx;
1815     DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1816 
1817     /* File system closing, it's OK */
1818     if (Fobx == NULL)
1819     {
1820         if (Fcb->UncleanCount > 0)
1821         {
1822             InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1823         }
1824 
1825         return STATUS_SUCCESS;
1826     }
1827 
1828     /* Check we have a correct FCB type */
1829     if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
1830         NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
1831         NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1832         NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
1833     {
1834         DPRINT1("Invalid Fcb type for %p\n", Fcb);
1835         RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1836     }
1837 
1838     FileObject = Context->CurrentIrpSp->FileObject;
1839     ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
1840 
1841     RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1842 
1843     Status = RxAcquireExclusiveFcb(Context, Fcb);
1844     if (!NT_SUCCESS(Status))
1845     {
1846         return Status;
1847     }
1848 
1849     FcbAcquired = TRUE;
1850 
1851     Fobx->AssociatedFileObject = NULL;
1852 
1853     /* In case it was already orphaned */
1854     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
1855     {
1856         ASSERT(Fcb->UncleanCount != 0);
1857         InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1858 
1859         if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1860         {
1861             --Fcb->UncachedUncleanCount;
1862         }
1863 
1864         /* Inform mini-rdr */
1865         MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1866 
1867         ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1868         --Fobx->SrvOpen->UncleanFobxCount;
1869 
1870         RxUninitializeCacheMap(Context, FileObject, NULL);
1871 
1872         RxReleaseFcb(Context, Fcb);
1873 
1874         return STATUS_SUCCESS;
1875     }
1876 
1877     /* Report the fact that file could be set as delete on close */
1878     if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1879     {
1880         SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
1881     }
1882 
1883     /* Cancel any pending notification */
1884     RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
1885 
1886     /* Backup open count before we start playing with it */
1887     OpenCount = Fcb->ShareAccess.OpenCount;
1888 
1889     NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1890     FcbTableAcquired = FALSE;
1891     LeftForDelete = FALSE;
1892     OneLeft = (Fcb->UncleanCount == 1);
1893 
1894     _SEH2_TRY
1895     {
1896         /* Unclean count and delete on close? Verify whether we're the one */
1897         if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
1898         {
1899             if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
1900             {
1901                 FcbTableAcquired = TRUE;
1902             }
1903             else
1904             {
1905                 RxReleaseFcb(Context, Fcb);
1906 
1907                 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
1908 
1909                 Status = RxAcquireExclusiveFcb(Context, Fcb);
1910                 if (Status != STATUS_SUCCESS)
1911                 {
1912                     RxReleaseFcbTableLock(&NetRoot->FcbTable);
1913                     return Status;
1914                 }
1915 
1916                 FcbTableAcquired = TRUE;
1917             }
1918 
1919             /* That means we'll perform the delete on close! */
1920             if (Fcb->UncleanCount == 1)
1921             {
1922                 LeftForDelete = TRUE;
1923             }
1924             else
1925             {
1926                 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1927                 FcbTableAcquired = FALSE;
1928             }
1929         }
1930 
1931         IsFile = FALSE;
1932         TruncateSizePtr = NULL;
1933         /* Handle cleanup for pipes and printers */
1934         if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
1935         {
1936             RxCleanupPipeQueues(Context);
1937         }
1938         /* Handle cleanup for files */
1939         else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
1940         {
1941             Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
1942             if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
1943             {
1944                 /* First, unlock */
1945                 FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
1946 
1947                 /* If there are still locks to release, proceed */
1948                 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
1949                 {
1950                     RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
1951                     Context->LowIoContext.ParamsFor.Locks.Flags = 0;
1952                     Status = RxLowIoLockControlShell(Context);
1953                 }
1954 
1955                 /* Fix times and size */
1956                 RxAdjustFileTimesAndSize(Context);
1957 
1958                 /* If we're the only one left... */
1959                 if (OneLeft)
1960                 {
1961                     /* And if we're supposed to delete on close */
1962                     if (LeftForDelete)
1963                     {
1964                         /* Update the sizes */
1965                         RxAcquirePagingIoResource(Context, Fcb);
1966                         Fcb->Header.FileSize.QuadPart = 0;
1967                         Fcb->Header.ValidDataLength.QuadPart = 0;
1968                         RxReleasePagingIoResource(Context, Fcb);
1969                     }
1970                     /* Otherwise, call the mini-rdr to adjust sizes */
1971                     else
1972                     {
1973                         /* File got grown up, fill with zeroes */
1974                         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
1975                             (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
1976                         {
1977                             MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
1978                             Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1979                         }
1980 
1981                         /* File was truncated, let mini-rdr proceed */
1982                         if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
1983                         {
1984                             MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
1985                             ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
1986 
1987                             /* Keep track of file change for Cc uninit */
1988                             TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
1989                             TruncateSizePtr = &TruncateSize;
1990                         }
1991                     }
1992                 }
1993 
1994                 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1995                 if (NeedPurge)
1996                 {
1997                     if (!OneLeft)
1998                     {
1999                         NeedPurge = FALSE;
2000                     }
2001                 }
2002                 /* Otherwise, try to see whether we can purge */
2003                 else
2004                 {
2005                     NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
2006                 }
2007 
2008                 IsFile = TRUE;
2009             }
2010         }
2011 
2012         /* We have to still be there! */
2013         ASSERT(Fcb->UncleanCount != 0);
2014         InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
2015 
2016         if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2017         {
2018             --Fcb->UncachedUncleanCount;
2019         }
2020 
2021         /* Inform mini-rdr about ongoing cleanup */
2022         MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
2023 
2024         ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
2025         --Fobx->SrvOpen->UncleanFobxCount;
2026 
2027         /* Flush cache */
2028         if (DisableFlushOnCleanup)
2029         {
2030             /* Only if we're the last standing */
2031             if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
2032                 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
2033             {
2034                 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
2035                 RxFlushFcbInSystemCache(Fcb, TRUE);
2036             }
2037         }
2038         else
2039         {
2040             /* Always */
2041             if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2042             {
2043                 DPRINT("Flushing %p on cleanup\n", Context);
2044                 RxFlushFcbInSystemCache(Fcb, TRUE);
2045             }
2046         }
2047 
2048         /* If only remaining uncached & unclean, then flush and purge */
2049         if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2050         {
2051             if (Fcb->UncachedUncleanCount != 0)
2052             {
2053                 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
2054                     Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2055                 {
2056                     DPRINT("Flushing FCB in system cache for %p\n", Context);
2057                     RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
2058                 }
2059             }
2060         }
2061 
2062         /* If purge required, and not about to delete, flush */
2063         if (!LeftForDelete && NeedPurge)
2064         {
2065             DPRINT("Flushing FCB in system cache for %p\n", Context);
2066             RxFlushFcbInSystemCache(Fcb, TRUE);
2067         }
2068 
2069         /* If it was a file, drop cache */
2070         if (IsFile)
2071         {
2072             DPRINT("Uninit cache map for file\n");
2073             RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
2074         }
2075 
2076         /* If that's the one left for deletion, or if it needs purge, flush */
2077         if (LeftForDelete || NeedPurge)
2078         {
2079             RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
2080             /* If that's for deletion, also remove from FCB table */
2081             if (LeftForDelete)
2082             {
2083                 RxRemoveNameNetFcb(Fcb);
2084                 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2085                 FcbTableAcquired = FALSE;
2086             }
2087         }
2088 
2089         /* Remove any share access */
2090         if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
2091         {
2092             RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
2093         }
2094 
2095         /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2096         if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
2097             RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
2098         {
2099             NTSTATUS InternalStatus;
2100             PRX_CONTEXT InternalContext;
2101 
2102             /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2103             InternalStatus = STATUS_UNSUCCESSFUL;
2104             InternalContext = RxCreateRxContext(Context->CurrentIrp,
2105                                                 Fcb->RxDeviceObject,
2106                                                 RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
2107             if (InternalContext != NULL)
2108             {
2109                 FILE_END_OF_FILE_INFORMATION FileEOF;
2110 
2111                 InternalStatus = STATUS_SUCCESS;
2112 
2113                 /* Initialize the context for file information set */
2114                 InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
2115                 InternalContext->pFobx = (PMRX_FOBX)Fobx;
2116                 InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
2117 
2118                 /* Get EOF from the FCB */
2119                 FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
2120                 InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
2121                 InternalContext->Info.Buffer = &FileEOF;
2122                 InternalContext->Info.Length = sizeof(FileEOF);
2123 
2124                 /* Call the mini-rdr */
2125                 MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
2126 
2127                 /* We're done */
2128                 RxDereferenceAndDeleteRxContext(InternalContext);
2129             }
2130 
2131             /* We tried, so, clean the FOBX flag */
2132             ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
2133             /* If it failed, then, disable collapsing on the FCB */
2134             if (!NT_SUCCESS(InternalStatus))
2135             {
2136                 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2137             }
2138         }
2139 
2140         /* We're clean! */
2141         SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
2142 
2143         FcbAcquired = FALSE;
2144         RxReleaseFcb(Context, Fcb);
2145     }
2146     _SEH2_FINALLY
2147     {
2148         if (FcbAcquired)
2149         {
2150             RxReleaseFcb(Context, Fcb);
2151         }
2152 
2153         if (FcbTableAcquired)
2154         {
2155             RxReleaseFcbTableLock(&NetRoot->FcbTable);
2156         }
2157     }
2158     _SEH2_END;
2159 
2160     return Status;
2161 #undef BugCheckFileId
2162 }
2163 
2164 NTSTATUS
2165 NTAPI
2166 RxCommonClose(
2167     PRX_CONTEXT Context)
2168 {
2169 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2170     PFCB Fcb;
2171     PFOBX Fobx;
2172     NTSTATUS Status;
2173     PFILE_OBJECT FileObject;
2174     BOOLEAN DereferenceFobx, AcquiredFcb;
2175 
2176     PAGED_CODE();
2177 
2178     Fcb = (PFCB)Context->pFcb;
2179     Fobx = (PFOBX)Context->pFobx;
2180     FileObject = Context->CurrentIrpSp->FileObject;
2181     DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
2182 
2183     Status = RxAcquireExclusiveFcb(Context, Fcb);
2184     if (!NT_SUCCESS(Status))
2185     {
2186         return Status;
2187     }
2188 
2189     AcquiredFcb = TRUE;
2190     _SEH2_TRY
2191     {
2192         BOOLEAN Freed;
2193 
2194         /* Check our FCB type is expected */
2195         if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2196             (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
2197             (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
2198         {
2199             RxBugCheck(NodeType(Fcb), 0, 0);
2200         }
2201 
2202         RxReferenceNetFcb(Fcb);
2203 
2204         DereferenceFobx = FALSE;
2205         /* If we're not closing FS */
2206         if (Fobx != NULL)
2207         {
2208             PSRV_OPEN SrvOpen;
2209             PSRV_CALL SrvCall;
2210 
2211             SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
2212             SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
2213             /* Handle delayed close */
2214             if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2215             {
2216                 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
2217                 {
2218                     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
2219                     {
2220                         DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
2221 
2222                         if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
2223                         {
2224                             if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
2225                             {
2226                                 InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
2227                             }
2228                             else
2229                             {
2230                                 DereferenceFobx = TRUE;
2231                                 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
2232                             }
2233                         }
2234                     }
2235                 }
2236             }
2237 
2238             /* If we reach maximum of delayed close/or if there are no delayed close */
2239             if (!DereferenceFobx)
2240             {
2241                 PNET_ROOT NetRoot;
2242 
2243                 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2244                 if (NetRoot->Type != NET_ROOT_PRINT)
2245                 {
2246                     /* Delete if asked */
2247                     if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
2248                     {
2249                         RxScavengeRelatedFobxs(Fcb);
2250                         RxSynchronizeWithScavenger(Context);
2251 
2252                         RxReleaseFcb(Context, Fcb);
2253 
2254                         RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2255                         RxOrphanThisFcb(Fcb);
2256                         RxReleaseFcbTableLock(&NetRoot->FcbTable);
2257 
2258                         Status = RxAcquireExclusiveFcb(Context, Fcb);
2259                         ASSERT(NT_SUCCESS(Status));
2260                     }
2261                 }
2262             }
2263 
2264             RxMarkFobxOnClose(Fobx);
2265         }
2266 
2267         if (DereferenceFobx)
2268         {
2269             ASSERT(Fobx != NULL);
2270             RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
2271         }
2272         else
2273         {
2274             RxCloseAssociatedSrvOpen(Fobx, Context);
2275             if (Fobx != NULL)
2276             {
2277                 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
2278             }
2279         }
2280 
2281         Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
2282         AcquiredFcb = !Freed;
2283 
2284         FileObject->FsContext = (PVOID)-1;
2285 
2286         if (Freed)
2287         {
2288             RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2289         }
2290         else
2291         {
2292             RxReleaseFcb(Context, Fcb);
2293             AcquiredFcb = FALSE;
2294         }
2295     }
2296     _SEH2_FINALLY
2297     {
2298         if (_SEH2_AbnormalTermination())
2299         {
2300             if (AcquiredFcb)
2301             {
2302                 RxReleaseFcb(Context, Fcb);
2303             }
2304         }
2305         else
2306         {
2307             ASSERT(!AcquiredFcb);
2308         }
2309     }
2310     _SEH2_END;
2311 
2312     DPRINT("Status: %x\n", Status);
2313     return Status;
2314 #undef BugCheckFileId
2315 }
2316 
2317 /*
2318  * @implemented
2319  */
2320 NTSTATUS
2321 NTAPI
2322 RxCommonCreate(
2323     PRX_CONTEXT Context)
2324 {
2325     PIRP Irp;
2326     NTSTATUS Status;
2327     PFILE_OBJECT FileObject;
2328     PIO_STACK_LOCATION Stack;
2329 
2330     PAGED_CODE();
2331 
2332     DPRINT("RxCommonCreate(%p)\n", Context);
2333 
2334     Irp = Context->CurrentIrp;
2335     Stack = Context->CurrentIrpSp;
2336     FileObject = Stack->FileObject;
2337 
2338     /* Check whether that's a device opening */
2339     if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2340     {
2341         FileObject->FsContext = &RxDeviceFCB;
2342         FileObject->FsContext2 = NULL;
2343 
2344         ++RxDeviceFCB.NodeReferenceCount;
2345         ++RxDeviceFCB.OpenCount;
2346 
2347         Irp->IoStatus.Information = FILE_OPENED;
2348         DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2349 
2350         Status = STATUS_SUCCESS;
2351     }
2352     else
2353     {
2354         PFCB RelatedFcb = NULL;
2355 
2356         /* Make sure caller is consistent */
2357         if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
2358             (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
2359 	    {
2360             DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2361 	        return STATUS_INVALID_PARAMETER;
2362         }
2363 
2364         DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2365                  Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2366                  Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2367         DPRINT("FileName: %wZ\n", &FileObject->FileName);
2368 
2369         if (FileObject->RelatedFileObject != NULL)
2370         {
2371             RelatedFcb = FileObject->RelatedFileObject->FsContext;
2372             DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2373         }
2374 
2375         /* Going to rename? */
2376         if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
2377         {
2378             DPRINT("TargetDir!\n");
2379         }
2380 
2381         /* Copy create parameters to the context */
2382         RxCopyCreateParameters(Context);
2383 
2384         /* If the caller wants to establish a connection, go ahead */
2385         if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2386         {
2387             Status = RxCreateTreeConnect(Context);
2388         }
2389         else
2390         {
2391             /* Validate file name */
2392             if (FileObject->FileName.Length > sizeof(WCHAR) &&
2393                 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2394                 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2395             {
2396                 FileObject->FileName.Length -= sizeof(WCHAR);
2397                 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2398                               FileObject->FileName.Length);
2399 
2400                 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2401                     FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2402                     FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2403                 {
2404                     return STATUS_OBJECT_NAME_INVALID;
2405                 }
2406             }
2407 
2408             /* Attempt to open the file */
2409             do
2410             {
2411                 UNICODE_STRING NetRootName;
2412 
2413                 /* Strip last \ if required */
2414                 if (FileObject->FileName.Length != 0 &&
2415                     FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2416                 {
2417                     if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2418                     {
2419                         return STATUS_OBJECT_NAME_INVALID;
2420                     }
2421 
2422                     FileObject->FileName.Length -= sizeof(WCHAR);
2423                     Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
2424                 }
2425 
2426                 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
2427                 {
2428                     FileObject->Flags |= FO_WRITE_THROUGH;
2429                 }
2430 
2431                 /* Get the associated net root to opening */
2432                 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2433                 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2434                 {
2435                     break;
2436                 }
2437 
2438                 /* And attempt to open */
2439                 Status = RxCreateFromNetRoot(Context, &NetRootName);
2440                 if (Status == STATUS_SHARING_VIOLATION)
2441                 {
2442                     ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2443 
2444                     /* If that happens for file creation, fail for real */
2445                     if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
2446                     {
2447                         Status = STATUS_OBJECT_NAME_COLLISION;
2448                     }
2449                     else
2450                     {
2451                         /* Otherwise, if possible, attempt to scavenger current FOBX
2452                          * to check whether a dormant FOBX is the reason for sharing violation
2453                          */
2454                         if (Context->Create.TryForScavengingOnSharingViolation &&
2455                             !Context->Create.ScavengingAlreadyTried)
2456                         {
2457                             /* Only doable with a VNetRoot */
2458                             if (Context->Create.pVNetRoot != NULL)
2459                             {
2460                                 PV_NET_ROOT VNetRoot;
2461                                 NT_CREATE_PARAMETERS SavedParameters;
2462 
2463                                 /* Save create parameters */
2464                                 RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
2465 
2466                                 /* Reference the VNetRoot for the scavenging time */
2467                                 VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
2468                                 RxReferenceVNetRoot(VNetRoot);
2469 
2470                                 /* Prepare the RX_CONTEXT for reuse */
2471                                 RxpPrepareCreateContextForReuse(Context);
2472                                 RxReinitializeContext(Context);
2473 
2474                                 /* Copy what we saved */
2475                                 RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
2476 
2477                                 /* And recopy what can be */
2478                                 RxCopyCreateParameters(Context);
2479 
2480                                 /* And start purging, then scavenging FOBX */
2481                                 RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
2482                                                     DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
2483                                 RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
2484                                                           NULL, TRUE);
2485 
2486                                 /* Ask for a second round */
2487                                 Status = STATUS_MORE_PROCESSING_REQUIRED;
2488 
2489                                 /* Keep track we already scavenged */
2490                                 Context->Create.ScavengingAlreadyTried = TRUE;
2491 
2492                                 /* Reference our SRV_CALL for CBS handling */
2493                                 RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
2494                                 RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
2495 
2496                                 /* Drop our extra reference */
2497                                 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2498                             }
2499                         }
2500                     }
2501                 }
2502                 else if (Status == STATUS_REPARSE)
2503                 {
2504                     Context->CurrentIrp->IoStatus.Information = 0;
2505                 }
2506                 else
2507                 {
2508                     ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2509                 }
2510             }
2511             while (Status == STATUS_MORE_PROCESSING_REQUIRED);
2512         }
2513 
2514         if (Status == STATUS_RETRY)
2515         {
2516             RxpPrepareCreateContextForReuse(Context);
2517         }
2518         ASSERT(Status != STATUS_PENDING);
2519     }
2520 
2521     DPRINT("Status: %lx\n", Status);
2522     return Status;
2523 }
2524 
2525 /*
2526  * @implemented
2527  */
2528 NTSTATUS
2529 NTAPI
2530 RxCommonDevFCBCleanup(
2531     PRX_CONTEXT Context)
2532 {
2533     PMRX_FCB Fcb;
2534     NTSTATUS Status;
2535 
2536     PAGED_CODE();
2537 
2538     DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2539 
2540     Fcb = Context->pFcb;
2541     Status = STATUS_SUCCESS;
2542     ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2543 
2544     /* Our FOBX if set, has to be a VNetRoot */
2545     if (Context->pFobx != NULL)
2546     {
2547         RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2548         if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2549         {
2550             Status = STATUS_INVALID_DEVICE_REQUEST;
2551         }
2552         RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2553     }
2554     else
2555     {
2556         --Fcb->UncleanCount;
2557     }
2558 
2559     return Status;
2560 }
2561 
2562 /*
2563  * @implemented
2564  */
2565 NTSTATUS
2566 NTAPI
2567 RxCommonDevFCBClose(
2568     PRX_CONTEXT Context)
2569 {
2570     PMRX_FCB Fcb;
2571     NTSTATUS Status;
2572     PMRX_V_NET_ROOT NetRoot;
2573 
2574     PAGED_CODE();
2575 
2576     DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2577 
2578     Fcb = Context->pFcb;
2579     NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2580     Status = STATUS_SUCCESS;
2581     ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2582 
2583     /* Our FOBX if set, has to be a VNetRoot */
2584     if (NetRoot != NULL)
2585     {
2586         RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2587         if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2588         {
2589             --NetRoot->NumberOfOpens;
2590             RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2591         }
2592         else
2593         {
2594             Status = STATUS_NOT_IMPLEMENTED;
2595         }
2596         RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2597     }
2598     else
2599     {
2600         --Fcb->OpenCount;
2601     }
2602 
2603     return Status;
2604 }
2605 
2606 NTSTATUS
2607 NTAPI
2608 RxCommonDevFCBFsCtl(
2609     PRX_CONTEXT Context)
2610 {
2611     UNIMPLEMENTED;
2612     return STATUS_NOT_IMPLEMENTED;
2613 }
2614 
2615 /*
2616  * @implemented
2617  */
2618 NTSTATUS
2619 NTAPI
2620 RxCommonDevFCBIoCtl(
2621     PRX_CONTEXT Context)
2622 {
2623     NTSTATUS Status;
2624 
2625     PAGED_CODE();
2626 
2627     DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2628 
2629     if (Context->pFobx != NULL)
2630     {
2631         return STATUS_INVALID_HANDLE;
2632     }
2633 
2634     /* Is that a prefix claim from MUP? */
2635     if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2636     {
2637         return RxPrefixClaim(Context);
2638     }
2639 
2640     /* Otherwise, pass through the mini-rdr */
2641     Status = RxXXXControlFileCallthru(Context);
2642     if (Status != STATUS_PENDING)
2643     {
2644         if (Context->PostRequest)
2645         {
2646             Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2647             Status = RxFsdPostRequest(Context);
2648         }
2649     }
2650 
2651     DPRINT("Status: %lx\n", Status);
2652     return Status;
2653 }
2654 
2655 NTSTATUS
2656 NTAPI
2657 RxCommonDevFCBQueryVolInfo(
2658     PRX_CONTEXT Context)
2659 {
2660     UNIMPLEMENTED;
2661     return STATUS_NOT_IMPLEMENTED;
2662 }
2663 
2664 /*
2665  * @implemented
2666  */
2667 NTSTATUS
2668 NTAPI
2669 RxCommonDeviceControl(
2670     PRX_CONTEXT Context)
2671 {
2672     NTSTATUS Status;
2673 
2674     PAGED_CODE();
2675 
2676     /* Prefix claim is only allowed for device, not files */
2677     if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2678     {
2679         return STATUS_INVALID_DEVICE_REQUEST;
2680     }
2681 
2682     /* Submit to mini-rdr */
2683     RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
2684     Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
2685     if (Status == STATUS_PENDING)
2686     {
2687         RxDereferenceAndDeleteRxContext_Real(Context);
2688     }
2689 
2690     return Status;
2691 }
2692 
2693 /*
2694  * @implemented
2695  */
2696 NTSTATUS
2697 NTAPI
2698 RxCommonDirectoryControl(
2699     PRX_CONTEXT Context)
2700 {
2701     PFCB Fcb;
2702     PFOBX Fobx;
2703     NTSTATUS Status;
2704     PIO_STACK_LOCATION Stack;
2705 
2706     PAGED_CODE();
2707 
2708     Fcb = (PFCB)Context->pFcb;
2709     Fobx = (PFOBX)Context->pFobx;
2710     Stack = Context->CurrentIrpSp;
2711     DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2712 
2713     /* Call the appropriate helper */
2714     if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2715     {
2716         Status = RxQueryDirectory(Context);
2717     }
2718     else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2719     {
2720         Status = RxNotifyChangeDirectory(Context);
2721         if (Status == STATUS_PENDING)
2722         {
2723             RxDereferenceAndDeleteRxContext_Real(Context);
2724         }
2725     }
2726     else
2727     {
2728         Status = STATUS_INVALID_DEVICE_REQUEST;
2729     }
2730 
2731     return Status;
2732 }
2733 
2734 NTSTATUS
2735 NTAPI
2736 RxCommonDispatchProblem(
2737     PRX_CONTEXT Context)
2738 {
2739     UNIMPLEMENTED;
2740     return STATUS_NOT_IMPLEMENTED;
2741 }
2742 
2743 NTSTATUS
2744 NTAPI
2745 RxCommonFileSystemControl(
2746     PRX_CONTEXT Context)
2747 {
2748     PIRP Irp;
2749     ULONG ControlCode;
2750     PIO_STACK_LOCATION Stack;
2751 
2752     PAGED_CODE();
2753 
2754     Irp = Context->CurrentIrp;
2755     Stack = Context->CurrentIrpSp;
2756     ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
2757 
2758     DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
2759 
2760     UNIMPLEMENTED;
2761     return STATUS_NOT_IMPLEMENTED;
2762 }
2763 
2764 NTSTATUS
2765 NTAPI
2766 RxCommonFlushBuffers(
2767     PRX_CONTEXT Context)
2768 {
2769     UNIMPLEMENTED;
2770     return STATUS_NOT_IMPLEMENTED;
2771 }
2772 
2773 NTSTATUS
2774 NTAPI
2775 RxCommonLockControl(
2776     PRX_CONTEXT Context)
2777 {
2778     UNIMPLEMENTED;
2779     return STATUS_NOT_IMPLEMENTED;
2780 }
2781 
2782 NTSTATUS
2783 NTAPI
2784 RxCommonQueryEa(
2785     PRX_CONTEXT Context)
2786 {
2787     UNIMPLEMENTED;
2788     return STATUS_NOT_IMPLEMENTED;
2789 }
2790 
2791 /*
2792  * @implemented
2793  */
2794 NTSTATUS
2795 NTAPI
2796 RxCommonQueryInformation(
2797     PRX_CONTEXT Context)
2798 {
2799 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function)                              \
2800     Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2801     Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2802 
2803     PFCB Fcb;
2804     PIRP Irp;
2805     PFOBX Fobx;
2806     BOOLEAN Locked;
2807     NTSTATUS Status;
2808     PIO_STACK_LOCATION Stack;
2809     FILE_INFORMATION_CLASS FileInfoClass;
2810 
2811     PAGED_CODE();
2812 
2813     Fcb = (PFCB)Context->pFcb;
2814     Fobx = (PFOBX)Context->pFobx;
2815     DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2816 
2817     Irp = Context->CurrentIrp;
2818     Stack = Context->CurrentIrpSp;
2819     DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2820             Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2821 
2822     Context->Info.Length = Stack->Parameters.QueryFile.Length;
2823     FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2824 
2825     Locked  = FALSE;
2826     _SEH2_TRY
2827     {
2828         PVOID Buffer;
2829 
2830         /* Get a writable buffer */
2831         Buffer = RxMapSystemBuffer(Context);
2832         if (Buffer == NULL)
2833         {
2834             Status = STATUS_INSUFFICIENT_RESOURCES;
2835             _SEH2_LEAVE;
2836         }
2837         /* Zero it */
2838         RtlZeroMemory(Buffer, Context->Info.Length);
2839 
2840         /* Validate file type */
2841         if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
2842         {
2843             if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2844             {
2845                 Status = STATUS_INVALID_PARAMETER;
2846                 _SEH2_LEAVE;
2847             }
2848             else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
2849             {
2850                 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
2851                 {
2852                     Status = STATUS_NOT_IMPLEMENTED;
2853                 }
2854                 else
2855                 {
2856                     Status = STATUS_INVALID_PARAMETER;
2857                 }
2858 
2859                 _SEH2_LEAVE;
2860             }
2861         }
2862 
2863         /* Acquire the right lock */
2864         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
2865             FileInfoClass != FileNameInformation)
2866         {
2867             if (FileInfoClass == FileCompressionInformation)
2868             {
2869                 Status = RxAcquireExclusiveFcb(Context, Fcb);
2870             }
2871             else
2872             {
2873                 Status = RxAcquireSharedFcb(Context, Fcb);
2874             }
2875 
2876             if (Status == STATUS_LOCK_NOT_GRANTED)
2877             {
2878                 Status = STATUS_PENDING;
2879                 _SEH2_LEAVE;
2880             }
2881             else if (!NT_SUCCESS(Status))
2882             {
2883                 _SEH2_LEAVE;
2884             }
2885 
2886             Locked = TRUE;
2887         }
2888 
2889         /* Dispatch to the right helper */
2890         switch (FileInfoClass)
2891         {
2892             case FileBasicInformation:
2893                 Status = RxQueryBasicInfo(Context, Buffer);
2894                 break;
2895 
2896             case FileStandardInformation:
2897                 Status = RxQueryStandardInfo(Context, Buffer);
2898                 break;
2899 
2900             case FileInternalInformation:
2901                 Status = RxQueryInternalInfo(Context, Buffer);
2902                 break;
2903 
2904             case FileEaInformation:
2905                 Status = RxQueryEaInfo(Context, Buffer);
2906                 break;
2907 
2908             case FileNameInformation:
2909                 Status = RxQueryNameInfo(Context, Buffer);
2910                 break;
2911 
2912             case FileAllInformation:
2913                 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
2914                 if (!NT_SUCCESS(Status))
2915                 {
2916                     break;
2917                 }
2918 
2919                 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
2920                 if (!NT_SUCCESS(Status))
2921                 {
2922                     break;
2923                 }
2924 
2925                 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2926                                    sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
2927                 if (!NT_SUCCESS(Status))
2928                 {
2929                     break;
2930                 }
2931 
2932                 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2933                                    sizeof(FILE_STANDARD_INFORMATION) +
2934                                    sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
2935                 if (!NT_SUCCESS(Status))
2936                 {
2937                     break;
2938                 }
2939 
2940                 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2941                                    sizeof(FILE_STANDARD_INFORMATION) +
2942                                    sizeof(FILE_INTERNAL_INFORMATION) +
2943                                    sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
2944                 if (!NT_SUCCESS(Status))
2945                 {
2946                     break;
2947                 }
2948 
2949                 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2950                                    sizeof(FILE_STANDARD_INFORMATION) +
2951                                    sizeof(FILE_INTERNAL_INFORMATION) +
2952                                    sizeof(FILE_EA_INFORMATION) +
2953                                    sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
2954                 break;
2955 
2956             case FileAlternateNameInformation:
2957                 Status = RxQueryAlternateNameInfo(Context, Buffer);
2958                 break;
2959 
2960             case FilePipeInformation:
2961             case FilePipeLocalInformation:
2962             case FilePipeRemoteInformation:
2963                 Status = RxQueryPipeInfo(Context, Buffer);
2964                 break;
2965 
2966             case FileCompressionInformation:
2967                 Status = RxQueryCompressedInfo(Context, Buffer);
2968                 break;
2969 
2970             default:
2971                 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
2972                 Status = Context->IoStatusBlock.Status;
2973                 break;
2974         }
2975 
2976         if (Context->Info.Length < 0)
2977         {
2978             Status = STATUS_BUFFER_OVERFLOW;
2979             Context->Info.Length = Stack->Parameters.QueryFile.Length;
2980         }
2981 
2982         Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
2983     }
2984     _SEH2_FINALLY
2985     {
2986         if (Locked)
2987         {
2988             RxReleaseFcb(Context, Fcb);
2989         }
2990     }
2991     _SEH2_END;
2992 
2993     DPRINT("Status: %x\n", Status);
2994     return Status;
2995 
2996 #undef SET_SIZE_AND_QUERY
2997 }
2998 
2999 NTSTATUS
3000 NTAPI
3001 RxCommonQueryQuotaInformation(
3002     PRX_CONTEXT Context)
3003 {
3004     UNIMPLEMENTED;
3005     return STATUS_NOT_IMPLEMENTED;
3006 }
3007 
3008 NTSTATUS
3009 NTAPI
3010 RxCommonQuerySecurity(
3011     PRX_CONTEXT Context)
3012 {
3013     UNIMPLEMENTED;
3014     return STATUS_NOT_IMPLEMENTED;
3015 }
3016 
3017 /*
3018  * @implemented
3019  */
3020 NTSTATUS
3021 NTAPI
3022 RxCommonQueryVolumeInformation(
3023     PRX_CONTEXT Context)
3024 {
3025     PIRP Irp;
3026     PFCB Fcb;
3027     PFOBX Fobx;
3028     NTSTATUS Status;
3029     PIO_STACK_LOCATION Stack;
3030 
3031     PAGED_CODE();
3032 
3033     Fcb = (PFCB)Context->pFcb;
3034     Fobx = (PFOBX)Context->pFobx;
3035 
3036     DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3037 
3038     Irp = Context->CurrentIrp;
3039     Stack = Context->CurrentIrpSp;
3040     DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
3041            Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
3042 
3043     Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
3044     Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
3045     Context->Info.Length = Stack->Parameters.QueryVolume.Length;
3046 
3047     /* Forward to mini-rdr */
3048     MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
3049 
3050     /* Post request if mini-rdr asked to */
3051     if (Context->PostRequest)
3052     {
3053         Status = RxFsdPostRequest(Context);
3054     }
3055     else
3056     {
3057         Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
3058     }
3059 
3060     DPRINT("Status: %x\n", Status);
3061     return Status;
3062 }
3063 
3064 NTSTATUS
3065 NTAPI
3066 RxCommonRead(
3067     PRX_CONTEXT RxContext)
3068 {
3069     PFCB Fcb;
3070     PIRP Irp;
3071     PFOBX Fobx;
3072     NTSTATUS Status;
3073     PNET_ROOT NetRoot;
3074     PVOID SystemBuffer;
3075     PFILE_OBJECT FileObject;
3076     LARGE_INTEGER ByteOffset;
3077     PIO_STACK_LOCATION Stack;
3078     PLOWIO_CONTEXT LowIoContext;
3079     PRDBSS_DEVICE_OBJECT RxDeviceObject;
3080     ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3081     BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
3082 
3083     PAGED_CODE();
3084 
3085     Fcb = (PFCB)RxContext->pFcb;
3086     Fobx = (PFOBX)RxContext->pFobx;
3087     DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3088 
3089     /* Get some parameters */
3090     Irp = RxContext->CurrentIrp;
3091     Stack = RxContext->CurrentIrpSp;
3092     CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3093     PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3094     NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3095     Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3096     InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3097     ReadLength = Stack->Parameters.Read.Length;
3098     ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
3099     DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
3100            (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3101 
3102     RxItsTheSameContext();
3103 
3104     Irp->IoStatus.Information = 0;
3105 
3106     /* Should the read be loud - so far, it's just ignored on ReactOS:
3107      * s/DPRINT/DPRINT1/g will make it loud
3108      */
3109     LowIoContext = &RxContext->LowIoContext;
3110     CheckForLoudOperations(RxContext);
3111     if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3112     {
3113         DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3114                 ByteOffset, ReadLength,
3115                 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3116     }
3117 
3118     RxDeviceObject = RxContext->RxDeviceObject;
3119     /* Update stats */
3120     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3121     {
3122         InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
3123 
3124         if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
3125         {
3126             InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
3127         }
3128         Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
3129 
3130         if (PagingIo)
3131         {
3132             ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
3133         }
3134         else if (NoCache)
3135         {
3136             ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
3137         }
3138         else
3139         {
3140             ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
3141         }
3142     }
3143 
3144     /* A pagefile cannot be a pipe */
3145     IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
3146     if (IsPipe && PagingIo)
3147     {
3148         return STATUS_INVALID_DEVICE_REQUEST;
3149     }
3150 
3151     /* Null-length read is no-op */
3152     if (ReadLength == 0)
3153     {
3154         return STATUS_SUCCESS;
3155     }
3156 
3157     /* Validate FCB type */
3158     if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
3159     {
3160         return STATUS_INVALID_DEVICE_REQUEST;
3161     }
3162 
3163     /* Init the lowio context for possible forward */
3164     RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
3165 
3166     PostRequest = FALSE;
3167     ReadCachingDisabled = FALSE;
3168     OwnerSet = FALSE;
3169     ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3170     FileObject = Stack->FileObject;
3171     NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3172     _SEH2_TRY
3173     {
3174         LONGLONG FileSize;
3175 
3176         /* If no caching, make sure current Cc data have been flushed */
3177         if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
3178         {
3179             Status = RxAcquireExclusiveFcb(RxContext, Fcb);
3180             if (Status == STATUS_LOCK_NOT_GRANTED)
3181             {
3182                 PostRequest = TRUE;
3183                 _SEH2_LEAVE;
3184             }
3185             else if (Status != STATUS_SUCCESS)
3186             {
3187                 _SEH2_LEAVE;
3188             }
3189 
3190             ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
3191             CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
3192             RxReleasePagingIoResource(RxContext, Fcb);
3193 
3194             if (!NT_SUCCESS(Irp->IoStatus.Status))
3195             {
3196                 Status = Irp->IoStatus.Status;
3197                 _SEH2_LEAVE;
3198             }
3199 
3200             RxAcquirePagingIoResource(RxContext, Fcb);
3201             RxReleasePagingIoResource(RxContext, Fcb);
3202         }
3203 
3204         /* Acquire the appropriate lock */
3205         if (PagingIo && !ReadCachingEnabled)
3206         {
3207             ASSERT(!IsPipe);
3208 
3209             if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
3210             {
3211                 PostRequest = TRUE;
3212                 _SEH2_LEAVE;
3213             }
3214 
3215             if (!CanWait)
3216             {
3217                 LowIoContext->Resource = Fcb->Header.PagingIoResource;
3218             }
3219         }
3220         else
3221         {
3222             if (!ReadCachingEnabled)
3223             {
3224                 if (!CanWait && NoCache)
3225                 {
3226                     Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
3227                     if (Status == STATUS_LOCK_NOT_GRANTED)
3228                     {
3229                         DPRINT1("RdAsyLNG %x\n", RxContext);
3230                         PostRequest = TRUE;
3231                         _SEH2_LEAVE;
3232                     }
3233                     if (Status != STATUS_SUCCESS)
3234                     {
3235                         DPRINT1("RdAsyOthr %x\n", RxContext);
3236                         _SEH2_LEAVE;
3237                     }
3238 
3239                     if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3240                     {
3241                         LowIoContext->Resource = Fcb->Header.Resource;
3242                     }
3243                     else
3244                     {
3245                         PostRequest = TRUE;
3246                         _SEH2_LEAVE;
3247                     }
3248                 }
3249                 else
3250                 {
3251                     Status = RxAcquireSharedFcb(RxContext, Fcb);
3252                     if (Status == STATUS_LOCK_NOT_GRANTED)
3253                     {
3254                         PostRequest = TRUE;
3255                         _SEH2_LEAVE;
3256                     }
3257                     else if (Status != STATUS_SUCCESS)
3258                     {
3259                         _SEH2_LEAVE;
3260                     }
3261                 }
3262             }
3263         }
3264 
3265         RxItsTheSameContext();
3266 
3267         ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3268         if (IsPipe)
3269         {
3270             UNIMPLEMENTED;
3271         }
3272 
3273         RxGetFileSizeWithLock(Fcb, &FileSize);
3274 
3275         /* Make sure FLOCK doesn't conflict */
3276         if (!PagingIo)
3277         {
3278             if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
3279             {
3280                 Status = STATUS_FILE_LOCK_CONFLICT;
3281                 _SEH2_LEAVE;
3282             }
3283         }
3284 
3285         /* Validate byteoffset vs length */
3286         if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
3287         {
3288             if (ByteOffset.QuadPart >= FileSize)
3289             {
3290                 Status = STATUS_END_OF_FILE;
3291                 _SEH2_LEAVE;
3292             }
3293 
3294             if (ReadLength > FileSize - ByteOffset.QuadPart)
3295             {
3296                 ReadLength = FileSize - ByteOffset.QuadPart;
3297             }
3298         }
3299 
3300         /* Read with Cc! */
3301         if (!PagingIo && !NoCache && ReadCachingEnabled &&
3302             !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
3303         {
3304             /* File was not cached yet, do it */
3305             if (FileObject->PrivateCacheMap == NULL)
3306             {
3307                 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
3308                 {
3309                     Status = STATUS_FILE_CLOSED;
3310                     _SEH2_LEAVE;
3311                 }
3312 
3313                 RxAdjustAllocationSizeforCC(Fcb);
3314 
3315                 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
3316                                      FALSE, &RxData.CacheManagerCallbacks, Fcb);
3317 
3318                 if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
3319                 {
3320                     CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3321                 }
3322                 else
3323                 {
3324                     CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
3325                     SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3326                 }
3327 
3328                 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3329             }
3330 
3331             /* This should never happen - fix your RDR */
3332             if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3333             {
3334                 ASSERT(FALSE);
3335                 ASSERT(CanWait);
3336 
3337                 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3338                 Status = Irp->IoStatus.Status;
3339                 ASSERT(NT_SUCCESS(Status));
3340             }
3341             else
3342             {
3343                 /* Map buffer */
3344                 SystemBuffer = RxNewMapUserBuffer(RxContext);
3345                 if (SystemBuffer == NULL)
3346                 {
3347                     Status = STATUS_INSUFFICIENT_RESOURCES;
3348                     _SEH2_LEAVE;
3349                 }
3350 
3351                 SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3352 
3353                 RxItsTheSameContext();
3354 
3355                 /* Perform the read */
3356                 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3357                 {
3358                     if (!ReadCachingEnabled)
3359                     {
3360                         ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3361                     }
3362 
3363                     RxItsTheSameContext();
3364 
3365                     PostRequest = TRUE;
3366                     _SEH2_LEAVE;
3367                 }
3368 
3369                 if (!ReadCachingEnabled)
3370                 {
3371                     ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3372                 }
3373 
3374                 Status = Irp->IoStatus.Status;
3375                 ASSERT(NT_SUCCESS(Status));
3376             }
3377         }
3378         else
3379         {
3380             /* Validate the reading */
3381             if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3382                 ByteOffset.QuadPart >= 4096)
3383             {
3384                 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3385                 ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3386             }
3387 
3388             /* If it's consistent, forward to mini-rdr */
3389             if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3390                 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3391             {
3392                 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3393                 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3394 
3395                 RxItsTheSameContext();
3396 
3397                 if (InFsp && ReadCachingDisabled)
3398                 {
3399                     ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3400                                               (PVOID)((ULONG_PTR)RxContext | 3));
3401                     OwnerSet = TRUE;
3402                 }
3403 
3404                 Status = RxLowIoReadShell(RxContext);
3405 
3406                 RxItsTheSameContext();
3407             }
3408             else
3409             {
3410                 if (ByteOffset.QuadPart > FileSize)
3411                 {
3412                     ReadLength = 0;
3413                     Irp->IoStatus.Information = ReadLength;
3414                     _SEH2_LEAVE;
3415                 }
3416 
3417                 if (ByteOffset.QuadPart + ReadLength > FileSize)
3418                 {
3419                     ReadLength = FileSize - ByteOffset.QuadPart;
3420                 }
3421 
3422                 SystemBuffer = RxNewMapUserBuffer(RxContext);
3423                 RtlZeroMemory(SystemBuffer, ReadLength);
3424                 Irp->IoStatus.Information = ReadLength;
3425             }
3426         }
3427     }
3428     _SEH2_FINALLY
3429     {
3430         RxItsTheSameContext();
3431 
3432         /* Post if required */
3433         if (PostRequest)
3434         {
3435             InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3436             Status = RxFsdPostRequest(RxContext);
3437         }
3438         else
3439         {
3440             /* Update FO in case of sync IO */
3441             if (!IsPipe && !PagingIo)
3442             {
3443                 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
3444                 {
3445                     FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
3446                 }
3447             }
3448         }
3449 
3450         /* Set FastIo if read was a success */
3451         if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
3452         {
3453             if (!IsPipe && !PagingIo)
3454             {
3455                 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
3456             }
3457         }
3458 
3459         /* In case we're done (not expected any further processing */
3460         if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
3461         {
3462             /* Release everything that can be */
3463             if (ReadCachingDisabled)
3464             {
3465                 if (PagingIo)
3466                 {
3467                     if (OwnerSet)
3468                     {
3469                         RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3470                     }
3471                     else
3472                     {
3473                         RxReleasePagingIoResource(RxContext, Fcb);
3474                     }
3475                 }
3476                 else
3477                 {
3478                     if (OwnerSet)
3479                     {
3480                         RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3481                     }
3482                     else
3483                     {
3484                         RxReleaseFcb(RxContext, Fcb);
3485                     }
3486                 }
3487             }
3488 
3489             /* Dereference/Delete context */
3490             if (PostRequest)
3491             {
3492                 RxDereferenceAndDeleteRxContext(RxContext);
3493             }
3494             else
3495             {
3496                 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
3497                 {
3498                     RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
3499                 }
3500             }
3501 
3502             /* We cannot return more than asked */
3503             if (Status == STATUS_SUCCESS)
3504             {
3505                 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
3506             }
3507         }
3508         else
3509         {
3510             ASSERT(!Sync);
3511 
3512             RxDereferenceAndDeleteRxContext(RxContext);
3513         }
3514     }
3515     _SEH2_END;
3516 
3517     return Status;
3518 }
3519 
3520 NTSTATUS
3521 NTAPI
3522 RxCommonSetEa(
3523     PRX_CONTEXT Context)
3524 {
3525     UNIMPLEMENTED;
3526     return STATUS_NOT_IMPLEMENTED;
3527 }
3528 
3529 /*
3530  * @implemented
3531  */
3532 NTSTATUS
3533 NTAPI
3534 RxCommonSetInformation(
3535     PRX_CONTEXT Context)
3536 {
3537     PIRP Irp;
3538     PFCB Fcb;
3539     PFOBX Fobx;
3540     NTSTATUS Status;
3541     PNET_ROOT NetRoot;
3542     PIO_STACK_LOCATION Stack;
3543     FILE_INFORMATION_CLASS Class;
3544     BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
3545 
3546     PAGED_CODE();
3547 
3548     Fcb = (PFCB)Context->pFcb;
3549     Fobx = (PFOBX)Context->pFobx;
3550     DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3551 
3552     Irp = Context->CurrentIrp;
3553     Stack = Context->CurrentIrpSp;
3554     Class = Stack->Parameters.SetFile.FileInformationClass;
3555     DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3556            Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
3557            Class, Stack->Parameters.SetFile.ReplaceIfExists);
3558 
3559     Status = STATUS_SUCCESS;
3560     CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
3561     FcbTableAcquired = FALSE;
3562     FcbAcquired = FALSE;
3563     NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3564 
3565 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3566 
3567     _SEH2_TRY
3568     {
3569         /* Valide the node type first */
3570         if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
3571             NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
3572         {
3573             if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
3574             {
3575                 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3576                 {
3577                     Status = STATUS_SUCCESS;
3578                 }
3579             }
3580             else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
3581             {
3582                 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
3583                 {
3584                     _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
3585                 }
3586                 else
3587                 {
3588                     DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
3589                     _SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER);
3590                 }
3591             }
3592         }
3593 
3594         /* We don't autorize advance operation */
3595         if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
3596         {
3597             DPRINT1("Not allowed\n");
3598 
3599             _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3600         }
3601 
3602         /* For these to classes, we'll have to deal with the FCB table (removal)
3603          * We thus need the exclusive FCB table lock
3604          */
3605         if (Class == FileDispositionInformation || Class == FileRenameInformation)
3606         {
3607             RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
3608             RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
3609 
3610             if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
3611             {
3612                 Context->PostRequest = TRUE;
3613                 _SEH2_TRY_RETURN(Status = STATUS_PENDING);
3614             }
3615 
3616             FcbTableAcquired = TRUE;
3617         }
3618 
3619         /* Finally, if not paging file, we need exclusive FCB lock */
3620         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3621         {
3622             Status = RxAcquireExclusiveFcb(Context, Fcb);
3623             if (Status == STATUS_LOCK_NOT_GRANTED)
3624             {
3625                 Context->PostRequest = TRUE;
3626                 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3627             }
3628             else if (Status != STATUS_SUCCESS)
3629             {
3630                 _SEH2_LEAVE;
3631             }
3632 
3633             FcbAcquired = TRUE;
3634         }
3635 
3636         Status = STATUS_SUCCESS;
3637 
3638         /* And now, perform the job! */
3639         switch (Class)
3640         {
3641             case FileBasicInformation:
3642                 Status = RxSetBasicInfo(Context);
3643                 break;
3644 
3645             case FileDispositionInformation:
3646             {
3647                 PFILE_DISPOSITION_INFORMATION FDI;
3648 
3649                 /* Check whether user wants deletion */
3650                 FDI = Irp->AssociatedIrp.SystemBuffer;
3651                 if (FDI->DeleteFile)
3652                 {
3653                     /* If so, check whether it's doable */
3654                     if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
3655                     {
3656                         Status = STATUS_CANNOT_DELETE;
3657                     }
3658 
3659                     /* And if doable, already remove from FCB table */
3660                     if (Status == STATUS_SUCCESS)
3661                     {
3662                         ASSERT(FcbAcquired && FcbTableAcquired);
3663                         RxRemoveNameNetFcb(Fcb);
3664 
3665                         RxReleaseFcbTableLock(&NetRoot->FcbTable);
3666                         FcbTableAcquired = FALSE;
3667                     }
3668                 }
3669 
3670                 /* If it succeed, perform the operation */
3671                 if (Status == STATUS_SUCCESS)
3672                 {
3673                     Status = RxSetDispositionInfo(Context);
3674                 }
3675 
3676                 break;
3677             }
3678 
3679             case FilePositionInformation:
3680                 Status = RxSetPositionInfo(Context);
3681                 break;
3682 
3683             case FileAllocationInformation:
3684                 Status = RxSetAllocationInfo(Context);
3685                 break;
3686 
3687             case FileEndOfFileInformation:
3688                 Status = RxSetEndOfFileInfo(Context);
3689                 break;
3690 
3691             case FilePipeInformation:
3692             case FilePipeLocalInformation:
3693             case FilePipeRemoteInformation:
3694                 Status = RxSetPipeInfo(Context);
3695                 break;
3696 
3697             case FileRenameInformation:
3698             case FileLinkInformation:
3699             case FileMoveClusterInformation:
3700                 /* If we can wait, try to perform the operation right now */
3701                 if (CanWait)
3702                 {
3703                     /* Of course, collapsing is not doable anymore, file is
3704                      * in an inbetween state
3705                      */
3706                     ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
3707 
3708                     /* Set the information */
3709                     Status = RxSetRenameInfo(Context);
3710                     /* If it succeed, drop the current entry from FCB table */
3711                     if (Status == STATUS_SUCCESS && Class == FileRenameInformation)
3712                     {
3713                         ASSERT(FcbAcquired && FcbTableAcquired);
3714                         RxRemoveNameNetFcb(Fcb);
3715                     }
3716                     _SEH2_TRY_RETURN(Status);
3717                 }
3718                 /* Can't wait? Post for async retry */
3719                 else
3720                 {
3721                     Status = RxFsdPostRequest(Context);
3722                     _SEH2_TRY_RETURN(Status);
3723                 }
3724                 break;
3725 
3726             case FileValidDataLengthInformation:
3727                 if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL))
3728                 {
3729                     Status = STATUS_USER_MAPPED_FILE;
3730                 }
3731                 break;
3732 
3733             case FileShortNameInformation:
3734                 Status = RxSetSimpleInfo(Context);
3735                 break;
3736 
3737             default:
3738                 DPRINT1("Insupported class: %x\n", Class);
3739                 Status = STATUS_INVALID_PARAMETER;
3740 
3741                 break;
3742         }
3743 
3744 try_exit: NOTHING;
3745         /* If mini-rdr was OK and wants a re-post on this, do it */
3746         if (Status == STATUS_SUCCESS)
3747         {
3748             if (Context->PostRequest)
3749             {
3750                 Status = RxFsdPostRequest(Context);
3751             }
3752         }
3753     }
3754     _SEH2_FINALLY
3755     {
3756         /* Release any acquired lock */
3757         if (FcbAcquired)
3758         {
3759             RxReleaseFcb(Context, Fcb);
3760         }
3761 
3762         if (FcbTableAcquired)
3763         {
3764             RxReleaseFcbTableLock(&NetRoot->FcbTable);
3765         }
3766     }
3767     _SEH2_END;
3768 
3769 #undef _SEH2_TRY_RETURN
3770 
3771     return Status;
3772 }
3773 
3774 NTSTATUS
3775 NTAPI
3776 RxCommonSetQuotaInformation(
3777     PRX_CONTEXT Context)
3778 {
3779     UNIMPLEMENTED;
3780     return STATUS_NOT_IMPLEMENTED;
3781 }
3782 
3783 NTSTATUS
3784 NTAPI
3785 RxCommonSetSecurity(
3786     PRX_CONTEXT Context)
3787 {
3788     UNIMPLEMENTED;
3789     return STATUS_NOT_IMPLEMENTED;
3790 }
3791 
3792 NTSTATUS
3793 NTAPI
3794 RxCommonSetVolumeInformation(
3795     PRX_CONTEXT Context)
3796 {
3797     UNIMPLEMENTED;
3798     return STATUS_NOT_IMPLEMENTED;
3799 }
3800 
3801 NTSTATUS
3802 NTAPI
3803 RxCommonUnimplemented(
3804     PRX_CONTEXT Context)
3805 {
3806     UNIMPLEMENTED;
3807     return STATUS_NOT_IMPLEMENTED;
3808 }
3809 
3810 NTSTATUS
3811 NTAPI
3812 RxCommonWrite(
3813     PRX_CONTEXT RxContext)
3814 {
3815     PIRP Irp;
3816     PFCB Fcb;
3817     PFOBX Fobx;
3818     NTSTATUS Status;
3819     PNET_ROOT NetRoot;
3820     PSRV_OPEN SrvOpen;
3821     PFILE_OBJECT FileObject;
3822     PIO_STACK_LOCATION Stack;
3823     LARGE_INTEGER ByteOffset;
3824     NODE_TYPE_CODE NodeTypeCode;
3825     PLOWIO_CONTEXT LowIoContext;
3826     PRDBSS_DEVICE_OBJECT RxDeviceObject;
3827     ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3828     LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
3829     BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
3830 
3831     PAGED_CODE();
3832 
3833     Fcb = (PFCB)RxContext->pFcb;
3834     NodeTypeCode = NodeType(Fcb);
3835     /* Validate FCB type */
3836     if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
3837         NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
3838     {
3839         return STATUS_INVALID_DEVICE_REQUEST;
3840     }
3841 
3842     /* We'll write to file, keep track of it */
3843     Fcb->IsFileWritten = TRUE;
3844 
3845     Stack = RxContext->CurrentIrpSp;
3846     /* Set write through if asked */
3847     if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
3848     {
3849         SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
3850     }
3851 
3852     Fobx = (PFOBX)RxContext->pFobx;
3853     DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3854 
3855     /* Get some parameters */
3856     Irp = RxContext->CurrentIrp;
3857     NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
3858     InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3859     CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3860     PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3861     NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3862     Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3863     WriteLength = Stack->Parameters.Write.Length;
3864     ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
3865     DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
3866            (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3867 
3868     RxItsTheSameContext();
3869 
3870     RxContext->FcbResourceAcquired = FALSE;
3871     RxContext->FcbPagingIoResourceAcquired = FALSE;
3872 
3873     LowIoContext = &RxContext->LowIoContext;
3874     CheckForLoudOperations(RxContext);
3875     if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3876     {
3877         DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3878                 ByteOffset, WriteLength,
3879                 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3880     }
3881 
3882     RxDeviceObject = RxContext->RxDeviceObject;
3883     /* Update stats */
3884     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3885     {
3886         InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
3887 
3888         if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
3889         {
3890             InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
3891         }
3892         Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
3893 
3894         if (PagingIo)
3895         {
3896             ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength);
3897         }
3898         else if (NoCache)
3899         {
3900             ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength);
3901         }
3902         else
3903         {
3904             ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength);
3905         }
3906     }
3907 
3908     NetRoot = (PNET_ROOT)Fcb->NetRoot;
3909     IsPipe = (NetRoot->Type == NET_ROOT_PIPE);
3910     /* Keep track for normal writes */
3911     if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
3912     {
3913         NormalFile = TRUE;
3914     }
3915     else
3916     {
3917         NormalFile = FALSE;
3918     }
3919 
3920     /* Zero-length write is immediate success */
3921     if (NormalFile && WriteLength == 0)
3922     {
3923         return STATUS_SUCCESS;
3924     }
3925 
3926     /* Check whether we have input data */
3927     if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
3928     {
3929         return STATUS_INVALID_PARAMETER;
3930     }
3931 
3932     /* Are we writting to EOF? */
3933     WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1));
3934     /* FIXME: validate length/offset */
3935 
3936     /* Get our SRV_OPEN in case of normal write */
3937     if (Fobx != NULL)
3938     {
3939         SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
3940     }
3941     else
3942     {
3943         SrvOpen = NULL;
3944     }
3945 
3946     FileObject = Stack->FileObject;
3947 
3948     /* If we have caching enabled, check whether we have to defer write */
3949     if (!NoCache)
3950     {
3951         if (RxWriteCacheingAllowed(Fcb, SrvOpen))
3952         {
3953             if (!CcCanIWrite(FileObject, WriteLength,
3954                              (CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)),
3955                              BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE)))
3956             {
3957                 BOOLEAN Retrying;
3958 
3959                 Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
3960 
3961                 RxPrePostIrp(RxContext, Irp);
3962 
3963                 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
3964 
3965                 CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
3966 
3967                 return STATUS_PENDING;
3968             }
3969         }
3970     }
3971 
3972     /* Initialize the low IO context for write */
3973     RxInitializeLowIoContext(LowIoContext, LOWIO_OP_WRITE);
3974 
3975     /* Initialize our (many) booleans */
3976     RecursiveWriteThrough = FALSE;
3977     CalledByLazyWriter = FALSE;
3978     SwitchBackToAsync = FALSE;
3979     ExtendingFile = FALSE;
3980     ExtendingValidData = FALSE;
3981     UnwindOutstandingAsync = FALSE;
3982     ResourceOwnerSet = FALSE;
3983     PostIrp = FALSE;
3984     ContextReferenced = FALSE;
3985 
3986 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3987 
3988     _SEH2_TRY
3989     {
3990         /* No volume FCB here! */
3991         ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) ||
3992                (NodeTypeCode == RDBSS_NTC_SPOOLFILE) ||
3993                (NodeTypeCode == RDBSS_NTC_MAILSLOT));
3994 
3995         /* Writing to EOF on a paging file is non sense */
3996         ASSERT(!(WriteToEof && PagingIo));
3997 
3998         RxItsTheSameContext();
3999 
4000         /* Start locking stuff */
4001         if (!PagingIo && !NoPreposting)
4002         {
4003             /* If it's already acquired, all fine */
4004             if (RxContext->FcbResourceAcquired)
4005             {
4006                 ASSERT(!IsPipe);
4007             }
4008             else
4009             {
4010                 /* Otherwise, try to acquire shared (excepted for pipes) */
4011                 if (IsPipe)
4012                 {
4013                     Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4014                 }
4015                 else if (CanWait ||
4016                          (!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen)))
4017                 {
4018                     Status = RxAcquireSharedFcb(RxContext, Fcb);
4019                 }
4020                 else
4021                 {
4022                     Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
4023                 }
4024 
4025                 /* We'll post IRP to retry */
4026                 if (Status == STATUS_LOCK_NOT_GRANTED)
4027                 {
4028                     PostIrp = TRUE;
4029                     DPRINT1("Failed to acquire lock!\n");
4030                     _SEH2_TRY_RETURN(Status);
4031                 }
4032 
4033                 /* We'll just fail */
4034                 if (Status != STATUS_SUCCESS)
4035                 {
4036                     _SEH2_TRY_RETURN(Status);
4037                 }
4038 
4039                 /* Resource acquired */
4040                 RxContext->FcbResourceAcquired = TRUE;
4041             }
4042 
4043             /* At that point, resource is acquired */
4044             if (IsPipe)
4045             {
4046                 ASSERT(RxContext->FcbResourceAcquired);
4047             }
4048             else
4049             {
4050                 BOOLEAN IsDormant;
4051 
4052                 /* Now, check whether we have to promote shared lock */
4053                 if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4054                 {
4055                     IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
4056                 }
4057                 else
4058                 {
4059                     IsDormant = FALSE;
4060                 }
4061 
4062                 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4063                 if (RxIsFcbAcquiredShared(Fcb) &&
4064                     ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart)
4065                 {
4066                     if (!IsDormant)
4067                     {
4068                         RxReleaseFcb(RxContext, Fcb);
4069                         RxContext->FcbResourceAcquired = FALSE;
4070 
4071                         Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4072                         if (Status == STATUS_LOCK_NOT_GRANTED)
4073                         {
4074                             PostIrp = TRUE;
4075                             DPRINT1("Failed to acquire lock!\n");
4076                             _SEH2_TRY_RETURN(Status);
4077                         }
4078 
4079                         if (Status != STATUS_SUCCESS)
4080                         {
4081                             _SEH2_TRY_RETURN(Status);
4082                         }
4083 
4084                         RxContext->FcbResourceAcquired = TRUE;
4085                     }
4086                 }
4087 
4088                 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4089                 if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart ||
4090                     IsDormant)
4091                 {
4092                     if (RxIsFcbAcquiredExclusive(Fcb))
4093                     {
4094                         RxConvertToSharedFcb(RxContext, Fcb);
4095                     }
4096                 }
4097                 else
4098                 {
4099                     /* We're extending file, disable collapsing */
4100                     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
4101 
4102                     DPRINT("Disabling collapsing\n");
4103 
4104                     if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4105                     {
4106                         SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
4107                     }
4108                 }
4109 
4110                 ASSERT(RxContext->FcbResourceAcquired);
4111             }
4112 
4113             /* Keep track of the acquired resource */
4114             LowIoContext->Resource = Fcb->Header.Resource;
4115         }
4116         else
4117         {
4118             /* Paging IO */
4119             ASSERT(!IsPipe);
4120 
4121             /* Lock the paging resource */
4122             RxAcquirePagingIoResourceShared(RxContext, Fcb, TRUE);
4123 
4124             /* Keep track of the acquired resource */
4125             LowIoContext->Resource = Fcb->Header.PagingIoResource;
4126         }
4127 
4128         if (IsPipe)
4129         {
4130             UNIMPLEMENTED;
4131             _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
4132         }
4133 
4134         /* If it's a non cached write, or if caching is disallowed */
4135         if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4136         {
4137             /* If cache was previously enabled, we'll have to flush before writing */
4138             if (!PagingIo && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
4139             {
4140                 LARGE_INTEGER FlushOffset;
4141 
4142                 /* FCB is lock */
4143                 ASSERT(RxIsFcbAcquiredExclusive(Fcb) || RxIsFcbAcquiredShared(Fcb));
4144 
4145                 /* If shared, we'll have to relock exclusive */
4146                 if (!RxIsFcbAcquiredExclusive(Fcb))
4147                 {
4148                     /* Release and retry exclusive */
4149                     RxReleaseFcb(RxContext, Fcb);
4150                     RxContext->FcbResourceAcquired = FALSE;
4151 
4152                     Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4153                     if (Status == STATUS_LOCK_NOT_GRANTED)
4154                     {
4155                         PostIrp = TRUE;
4156                         DPRINT1("Failed to acquire lock for flush!\n");
4157                         _SEH2_TRY_RETURN(Status);
4158                     }
4159 
4160                     if (Status != STATUS_SUCCESS)
4161                     {
4162                         _SEH2_TRY_RETURN(Status);
4163                     }
4164 
4165                     RxContext->FcbResourceAcquired = TRUE;
4166                 }
4167 
4168                 /* Get the length to flush */
4169                 if (WriteToEof)
4170                 {
4171                     RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart);
4172                 }
4173                 else
4174                 {
4175                     FlushOffset.QuadPart = ByteOffset.QuadPart;
4176                 }
4177 
4178                 /* Perform the flushing */
4179                 RxAcquirePagingIoResource(RxContext, Fcb);
4180                 CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset,
4181                              WriteLength, &Irp->IoStatus);
4182                 RxReleasePagingIoResource(RxContext, Fcb);
4183 
4184                 /* Cannot continue if flushing failed */
4185                 if (!NT_SUCCESS(Irp->IoStatus.Status))
4186                 {
4187                     _SEH2_TRY_RETURN(Status = Irp->IoStatus.Status);
4188                 }
4189 
4190                 /* Synchronize */
4191                 RxAcquirePagingIoResource(RxContext, Fcb);
4192                 RxReleasePagingIoResource(RxContext, Fcb);
4193 
4194                 /* And purge */
4195                 CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers,
4196                                     &FlushOffset, WriteLength, FALSE);
4197             }
4198         }
4199 
4200         /* If not paging IO, check if write is allowed */
4201         if (!PagingIo)
4202         {
4203             if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp))
4204             {
4205                 _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4206             }
4207         }
4208 
4209         /* Get file sizes */
4210         ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4211         RxGetFileSizeWithLock(Fcb, &FileSize);
4212         ASSERT(ValidDataLength <= FileSize);
4213 
4214         /* If paging IO, we cannot write past file size
4215          * so fix write length if needed
4216          */
4217         if (PagingIo)
4218         {
4219             if (ByteOffset.QuadPart >= FileSize)
4220             {
4221                 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
4222             }
4223 
4224             if (WriteLength > FileSize - ByteOffset.QuadPart)
4225             {
4226                 WriteLength = FileSize - ByteOffset.QuadPart;
4227             }
4228         }
4229 
4230         /* If we're being called by the lazywrite */
4231         if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread())
4232         {
4233             CalledByLazyWriter = TRUE;
4234 
4235             /* Fail if we're beyong VDL */
4236             if (BooleanFlagOn(Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE))
4237             {
4238                 if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) &&
4239                     (ByteOffset.QuadPart < FileSize))
4240                 {
4241                     if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
4242                     {
4243                         _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4244                     }
4245                 }
4246             }
4247         }
4248 
4249         /* If that's a recursive synchronous page write */
4250         if (BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
4251             BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
4252         {
4253             PIRP TopIrp;
4254 
4255             /* Check the top level IRP on the FastIO path */
4256             TopIrp = RxGetTopIrpIfRdbssIrp();
4257             if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP)
4258             {
4259                 PIO_STACK_LOCATION IrpStack;
4260 
4261                 ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
4262 
4263                 /* If the top level IRP was a cached write for this file, keep track */
4264                 IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
4265                 if (IrpStack->MajorFunction == IRP_MJ_WRITE &&
4266                     IrpStack->FileObject->FsContext == FileObject->FsContext)
4267                 {
4268                     RecursiveWriteThrough = TRUE;
4269                     SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
4270                 }
4271             }
4272         }
4273 
4274         /* Now, deal with file size and VDL */
4275         if (!CalledByLazyWriter && !RecursiveWriteThrough &&
4276             (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength))
4277         {
4278             /* Not sync? Let's make it sync, just the time we extended */
4279             if (!Sync)
4280             {
4281                 CanWait = TRUE;
4282                 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
4283                 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4284                 Sync = TRUE;
4285 
4286                 /* Keep track we'll have to switch back to async */
4287                 if (NoCache)
4288                 {
4289                     SwitchBackToAsync = TRUE;
4290                 }
4291             }
4292 
4293             /* Release all the locks */
4294             RxWriteReleaseResources(RxContext, 0);
4295 
4296             /* Acquire exclusive */
4297             Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4298             if (Status == STATUS_LOCK_NOT_GRANTED)
4299             {
4300                 PostIrp = TRUE;
4301                 DPRINT1("Failed to acquire lock for extension!\n");
4302                 _SEH2_TRY_RETURN(Status);
4303             }
4304 
4305             if (Status != STATUS_SUCCESS)
4306             {
4307                 _SEH2_TRY_RETURN(Status);
4308             }
4309 
4310             RxContext->FcbResourceAcquired = TRUE;
4311 
4312             RxItsTheSameContext();
4313 
4314             /* Get the sizes again, to be sure they didn't change in the meantime */
4315             ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4316             RxGetFileSizeWithLock(Fcb, &FileSize);
4317             ASSERT(ValidDataLength <= FileSize);
4318 
4319             /* Check we can switch back to async? */
4320             if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
4321                 (ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync)
4322             {
4323                 SwitchBackToAsync = FALSE;
4324             }
4325 
4326             /* If paging IO, check we don't try to extend the file */
4327             if (PagingIo)
4328             {
4329                 if (ByteOffset.QuadPart >= FileSize)
4330                 {
4331                     _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
4332                 }
4333 
4334                 if (WriteLength > FileSize - ByteOffset.QuadPart)
4335                 {
4336                     WriteLength = FileSize - ByteOffset.QuadPart;
4337                 }
4338             }
4339         }
4340 
4341         /* Save our initial sizes for potential rollback */
4342         InitialFileSize = FileSize;
4343         InitialValidDataLength = ValidDataLength;
4344         /* If writing to EOF, update byte offset with file size */
4345         if (WriteToEof)
4346         {
4347             ByteOffset.QuadPart = FileSize;
4348         }
4349 
4350         /* Check again whether we're allowed to write */
4351         if (!PagingIo)
4352         {
4353             if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp ))
4354             {
4355                 _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4356             }
4357 
4358             /* Do we have to extend? */
4359             if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize))
4360             {
4361                 DPRINT("Need to extend file\n");
4362                 ExtendingFile = TRUE;
4363                 SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE);
4364             }
4365         }
4366 
4367         /* Let's start to extend */
4368         if (ExtendingFile)
4369         {
4370             /* If we're past allocating, inform mini-rdr */
4371             FileSize = ByteOffset.QuadPart + WriteLength;
4372             if (FileSize > Fcb->Header.AllocationSize.QuadPart)
4373             {
4374                 LARGE_INTEGER NewAllocationSize;
4375 
4376                 DPRINT("Extending %p\n", RxContext);
4377 
4378                 if (NoCache)
4379                 {
4380                     C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4381                     MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache,
4382                                  (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4383                 }
4384                 else
4385                 {
4386                     C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4387                     MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache,
4388                                  (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4389                 }
4390 
4391                 if (!NT_SUCCESS(Status))
4392                 {
4393                     _SEH2_TRY_RETURN(Status);
4394                 }
4395 
4396                 if (FileSize > NewAllocationSize.QuadPart)
4397                 {
4398                     NewAllocationSize.QuadPart = FileSize;
4399                 }
4400 
4401                 /* And update FCB */
4402                 Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
4403             }
4404 
4405             /* Set the new sizes */
4406             RxSetFileSizeWithLock(Fcb, &FileSize);
4407             RxAdjustAllocationSizeforCC(Fcb);
4408 
4409             /* And inform Cc */
4410             if (CcIsFileCached(FileObject))
4411             {
4412                 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
4413             }
4414         }
4415 
4416         /* Do we have to extend VDL? */
4417         if (!CalledByLazyWriter && !RecursiveWriteThrough)
4418         {
4419             if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)
4420             {
4421                 ExtendingValidData = TRUE;
4422                 SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL);
4423             }
4424         }
4425 
4426         /* If none cached write */
4427         if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4428         {
4429             /* Switch back to async, if asked to */
4430             if (SwitchBackToAsync)
4431             {
4432                 CanWait = FALSE;
4433                 Sync = FALSE;
4434 
4435                 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
4436                 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4437             }
4438 
4439             /* If not synchronous, keep track of writes to be finished */
4440             if (!Sync)
4441             {
4442                 if (Fcb->NonPaged->OutstandingAsyncEvent == NULL)
4443                 {
4444                     Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent;
4445                     KeInitializeEvent(Fcb->NonPaged->OutstandingAsyncEvent,
4446                                       NotificationEvent, FALSE);
4447                 }
4448 
4449                 if (ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites,
4450                                           1,
4451                                           &RxStrucSupSpinLock) == 0)
4452                 {
4453                     KeResetEvent(Fcb->NonPaged->OutstandingAsyncEvent);
4454                 }
4455 
4456                 UnwindOutstandingAsync = TRUE;
4457                 LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
4458             }
4459 
4460             /* Set our LOWIO_CONTEXT information */
4461             LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
4462             LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
4463 
4464             RxItsTheSameContext();
4465 
4466             /* We have to be locked */
4467             ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
4468 
4469             /* Update thread ID if we're in FSP */
4470             if (InFsp)
4471             {
4472                 LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
4473 
4474                 if (RxContext->FcbResourceAcquired)
4475                 {
4476                     ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3));
4477                 }
4478 
4479                 if (RxContext->FcbPagingIoResourceAcquired)
4480                 {
4481                     ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3));
4482                 }
4483 
4484                 ResourceOwnerSet = TRUE;
4485             }
4486 
4487             /* And perform the write */
4488             Status = RxLowIoWriteShell(RxContext);
4489 
4490             RxItsTheSameContext();
4491 
4492             /* Not outstanding write anymore */
4493             if (UnwindOutstandingAsync && Status == STATUS_PENDING)
4494             {
4495                 UnwindOutstandingAsync = FALSE;
4496             }
4497         }
4498         /* Cached write */
4499         else
4500         {
4501             /* If cache wasn't enabled yet, do it */
4502             if (FileObject->PrivateCacheMap == NULL)
4503             {
4504                 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
4505                 {
4506                     _SEH2_TRY_RETURN(Status = STATUS_FILE_CLOSED);
4507                 }
4508 
4509                 RxAdjustAllocationSizeforCC(Fcb);
4510 
4511                 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4512                                      FALSE, &RxData.CacheManagerCallbacks, Fcb);
4513 
4514                 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
4515             }
4516 
4517             /* If that's a MDL backed write */
4518             if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
4519             {
4520                 /* Shouldn't happen */
4521                 ASSERT(FALSE);
4522                 ASSERT(CanWait);
4523 
4524                 /* Perform it, though */
4525                 CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength,
4526                                   &Irp->MdlAddress, &Irp->IoStatus);
4527 
4528                 Status = Irp->IoStatus.Status;
4529             }
4530             else
4531             {
4532                 PVOID SystemBuffer;
4533                 ULONG BreakpointsSave;
4534 
4535                 /* Map the user buffer */
4536                 SystemBuffer = RxNewMapUserBuffer(RxContext);
4537                 if (SystemBuffer == NULL)
4538                 {
4539                     _SEH2_TRY_RETURN(Status = STATUS_INSUFFICIENT_RESOURCES);
4540                 }
4541 
4542                 RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4543 
4544                 RxItsTheSameContext();
4545 
4546                 /* And deal with Cc */
4547                 if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait,
4548                                  SystemBuffer))
4549                 {
4550                     RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4551 
4552                     RxItsTheSameContext();
4553 
4554                     DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4555                             FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4556 
4557                     PostIrp = TRUE;
4558                 }
4559                 else
4560                 {
4561                     Irp->IoStatus.Status = STATUS_SUCCESS;
4562                     Irp->IoStatus.Information = WriteLength;
4563 
4564                     RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4565 
4566                     RxItsTheSameContext();
4567 
4568                     DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4569                            FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4570                 }
4571             }
4572         }
4573 
4574 try_exit: NOTHING;
4575 
4576         /* If we've to post the IRP */
4577         if (PostIrp)
4578         {
4579             /* Reset the file size if required */
4580             if (ExtendingFile && !IsPipe)
4581             {
4582                 ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen));
4583                 ASSERT(Fcb->Header.PagingIoResource != NULL);
4584 
4585                 RxAcquirePagingIoResource(RxContext, Fcb);
4586                 RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4587                 RxReleasePagingIoResource(RxContext, Fcb);
4588 
4589                 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4590                 {
4591                     *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4592                 }
4593             }
4594 
4595             InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
4596             ContextReferenced = TRUE;
4597 
4598             /* Release locks */
4599             ASSERT(!ResourceOwnerSet);
4600             RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4601 
4602 #ifdef RDBSS_TRACKER
4603             ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
4604 #endif
4605 
4606             /* And post the request */
4607             Status = RxFsdPostRequest(RxContext);
4608         }
4609         else
4610         {
4611             if (!IsPipe)
4612             {
4613                 /* Update FILE_OBJECT if synchronous write succeed */
4614                 if (!PagingIo)
4615                 {
4616                     if (NT_SUCCESS(Status) && BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4617                     {
4618                         FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
4619                     }
4620                 }
4621 
4622                 /* If write succeed, ,also update FILE_OBJECT flags */
4623                 if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
4624                 {
4625                     /* File was modified */
4626                     if (!PagingIo)
4627                     {
4628                         SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
4629                     }
4630 
4631                     /* If was even extended */
4632                     if (ExtendingFile)
4633                     {
4634                         SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
4635                     }
4636 
4637                     /* If VDL was extended, update FCB and inform Cc */
4638                     if (ExtendingValidData)
4639                     {
4640                         LONGLONG LastOffset;
4641 
4642                         LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information;
4643                         if (FileSize < LastOffset)
4644                         {
4645                             LastOffset = FileSize;
4646                         }
4647 
4648                         Fcb->Header.ValidDataLength.QuadPart = LastOffset;
4649 
4650                         if (NoCache && CcIsFileCached(FileObject))
4651                         {
4652                             CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
4653                         }
4654                     }
4655                 }
4656             }
4657         }
4658     }
4659     _SEH2_FINALLY
4660     {
4661         /* Finally, if we failed while extension was required */
4662         if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData))
4663         {
4664             /* Rollback! */
4665             if (!IsPipe)
4666             {
4667                 ASSERT(Fcb->Header.PagingIoResource != NULL);
4668 
4669                 RxAcquirePagingIoResource(RxContext, Fcb);
4670                 RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4671                 Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
4672                 RxReleasePagingIoResource(RxContext, Fcb);
4673 
4674                 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4675                 {
4676                     *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4677                 }
4678             }
4679         }
4680 
4681         /* One async write less */
4682         if (UnwindOutstandingAsync)
4683         {
4684             ASSERT(!IsPipe);
4685 
4686             ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock);
4687             KeSetEvent(Fcb->NonPaged->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
4688         }
4689 
4690         /* And now, cleanup everything */
4691         if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp)
4692         {
4693             /* If we didn't post, release every lock (for posting, it's already done) */
4694             if (!PostIrp)
4695             {
4696                 RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4697             }
4698 
4699             /* If the context was referenced - posting, dereference it */
4700             if (ContextReferenced)
4701             {
4702                 RxDereferenceAndDeleteRxContext(RxContext);
4703             }
4704 
4705             /* If that's a pipe operation, resume any blocked one */
4706             if (!PostIrp)
4707             {
4708                 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
4709                 {
4710                     RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
4711                 }
4712             }
4713 
4714             /* Sanity check for write */
4715             if (Status == STATUS_SUCCESS)
4716             {
4717                 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
4718             }
4719         }
4720         /* Just dereference our context */
4721         else
4722         {
4723             ASSERT(!Sync);
4724             RxDereferenceAndDeleteRxContext(RxContext);
4725         }
4726     }
4727     _SEH2_END;
4728 
4729 #undef _SEH2_TRY_RETURN
4730 
4731     return Status;
4732 }
4733 
4734 /*
4735  * @implemented
4736  */
4737 NTSTATUS
4738 NTAPI
4739 RxCompleteMdl(
4740     IN PRX_CONTEXT RxContext)
4741 {
4742     PIRP Irp;
4743     PFILE_OBJECT FileObject;
4744     PIO_STACK_LOCATION Stack;
4745 
4746 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4747 
4748     PAGED_CODE();
4749 
4750     Irp = RxContext->CurrentIrp;
4751     Stack = RxContext->CurrentIrpSp;
4752     FileObject = Stack->FileObject;
4753 
4754     /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4755     switch (RxContext->MajorFunction)
4756     {
4757         /* Call the Cc function */
4758         case IRP_MJ_READ:
4759             CcMdlReadComplete(FileObject, Irp->MdlAddress);
4760             break;
4761 
4762         case IRP_MJ_WRITE:
4763             /* If here, we can wait */
4764             ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
4765 
4766             /* Call the Cc function */
4767             CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
4768 
4769             Irp->IoStatus.Status = STATUS_SUCCESS;
4770             break;
4771 
4772         default:
4773             DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction);
4774             RxBugCheck(RxContext->MajorFunction, 0, 0);
4775             break;
4776     }
4777 
4778     /* MDL was freed */
4779     Irp->MdlAddress = NULL;
4780 
4781     /* And complete the IRP */
4782     RxCompleteRequest(RxContext, STATUS_SUCCESS);
4783 
4784 #undef BugCheckFileId
4785 
4786     return STATUS_SUCCESS;
4787 }
4788 
4789 /*
4790  * @implemented
4791  */
4792 VOID
4793 RxCopyCreateParameters(
4794     IN PRX_CONTEXT RxContext)
4795 {
4796     PIRP Irp;
4797     PVOID DfsContext;
4798     PFILE_OBJECT FileObject;
4799     PIO_STACK_LOCATION Stack;
4800     PDFS_NAME_CONTEXT DfsNameContext;
4801     PIO_SECURITY_CONTEXT SecurityContext;
4802 
4803     Irp = RxContext->CurrentIrp;
4804     Stack = RxContext->CurrentIrpSp;
4805     FileObject = Stack->FileObject;
4806     SecurityContext = Stack->Parameters.Create.SecurityContext;
4807 
4808     RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext;
4809     if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL)
4810     {
4811         RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor);
4812         DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext,
4813                RxContext->Create.SdLength);
4814     }
4815     if (SecurityContext->SecurityQos != NULL)
4816     {
4817         RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel;
4818     }
4819     else
4820     {
4821         RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation;
4822     }
4823     RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
4824 
4825     RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart;
4826     RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
4827     RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
4828     RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
4829     RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
4830 
4831     DfsContext = FileObject->FsContext2;
4832     DfsNameContext = FileObject->FsContext;
4833     RxContext->Create.NtCreateParameters.DfsContext = DfsContext;
4834     RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext;
4835     ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) ||
4836            DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) ||
4837            DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) ||
4838            DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT));
4839     ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT ||
4840            DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT ||
4841            DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT ||
4842            DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT);
4843     FileObject->FsContext2 = NULL;
4844     FileObject->FsContext = NULL;
4845 
4846     RxContext->pFcb = NULL;
4847     RxContext->Create.ReturnedCreateInformation = 0;
4848 
4849     /* if we stripped last \, it has to be a directory! */
4850     if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
4851     {
4852         SetFlag(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DIRECTORY_FILE);
4853     }
4854 
4855     RxContext->Create.EaLength = Stack->Parameters.Create.EaLength;
4856     if (RxContext->Create.EaLength == 0)
4857     {
4858         RxContext->Create.EaBuffer = NULL;
4859     }
4860     else
4861     {
4862         RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer;
4863         DPRINT("EA Buffer: %p, Length: %lx\n", Irp->AssociatedIrp.SystemBuffer, RxContext->Create.EaLength);
4864     }
4865 }
4866 
4867 NTSTATUS
4868 RxCreateFromNetRoot(
4869     PRX_CONTEXT Context,
4870     PUNICODE_STRING NetRootName)
4871 {
4872     PFCB Fcb;
4873     NTSTATUS Status;
4874     PNET_ROOT NetRoot;
4875     PFILE_OBJECT FileObject;
4876     PIO_STACK_LOCATION Stack;
4877     ACCESS_MASK DesiredAccess;
4878     USHORT DesiredShareAccess;
4879 
4880     PAGED_CODE();
4881 
4882     /* Validate that the context is consistent */
4883     if (Context->Create.pNetRoot == NULL)
4884     {
4885         return STATUS_BAD_NETWORK_PATH;
4886     }
4887 
4888     NetRoot = (PNET_ROOT)Context->Create.pNetRoot;
4889     if (Context->RxDeviceObject != NetRoot->pSrvCall->RxDeviceObject)
4890     {
4891         return STATUS_BAD_NETWORK_PATH;
4892     }
4893 
4894     if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) &&
4895         !BooleanFlagOn(NetRoot->pSrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER))
4896     {
4897         return STATUS_DFS_UNAVAILABLE;
4898     }
4899 
4900     if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
4901         BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT))
4902     {
4903         return STATUS_OBJECT_TYPE_MISMATCH;
4904     }
4905 
4906     Stack = Context->CurrentIrpSp;
4907     DesiredShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
4908     if (NetRoot->Type == NET_ROOT_PRINT)
4909     {
4910         DesiredShareAccess = FILE_SHARE_VALID_FLAGS;
4911     }
4912 
4913     DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
4914 
4915     /* Get file object */
4916     FileObject = Stack->FileObject;
4917 
4918     /* Do we have to open target directory for renaming? */
4919     if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
4920     {
4921         DPRINT("Opening target directory\n");
4922 
4923         /* If we have been asked for delete, try to purge first */
4924         if (BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, DELETE))
4925         {
4926             RxPurgeRelatedFobxs((PNET_ROOT)Context->Create.pVNetRoot->pNetRoot, Context,
4927                                 ATTEMPT_FINALIZE_ON_PURGE, NULL);
4928         }
4929 
4930         /* Create the FCB */
4931         Fcb = RxCreateNetFcb(Context, (PV_NET_ROOT)Context->Create.pVNetRoot, NetRootName);
4932         if (Fcb == NULL)
4933         {
4934             return STATUS_INSUFFICIENT_RESOURCES;
4935         }
4936 
4937         /* Fake it: it will be used only renaming */
4938         NodeType(Fcb) = RDBSS_NTC_OPENTARGETDIR_FCB;
4939         Context->Create.FcbAcquired = FALSE;
4940         Context->Create.NetNamePrefixEntry = NULL;
4941 
4942         /* Assign it to the FO */
4943         FileObject->FsContext = Fcb;
4944 
4945         /* If we have a FOBX already, check whether it's for DFS opening */
4946         if (Context->pFobx != NULL)
4947         {
4948             /* If so, reflect this in the FOBX */
4949             if (FileObject->FsContext2 == UIntToPtr(DFS_OPEN_CONTEXT))
4950             {
4951                 SetFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
4952             }
4953             else
4954             {
4955                 ClearFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
4956             }
4957         }
4958 
4959         /* Acquire the FCB */
4960         Status = RxAcquireExclusiveFcb(Context, Fcb);
4961         if (Status != STATUS_SUCCESS)
4962         {
4963             return Status;
4964         }
4965 
4966         /* Reference the FCB and release */
4967         RxReferenceNetFcb(Fcb);
4968         RxReleaseFcb(Context, Fcb);
4969 
4970         /* We're done! */
4971         return STATUS_SUCCESS;
4972     }
4973 
4974     /* Try to find (or create) the FCB for the file */
4975     Status = RxFindOrCreateFcb(Context, NetRootName);
4976     Fcb = (PFCB)Context->pFcb;
4977     if (Fcb == NULL)
4978     {
4979         ASSERT(!NT_SUCCESS(Status));
4980     }
4981     if (!NT_SUCCESS(Status) || Fcb == NULL)
4982     {
4983         return Status;
4984     }
4985 
4986     if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
4987     {
4988         Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT;
4989     }
4990     else
4991     {
4992         Status = STATUS_MORE_PROCESSING_REQUIRED;
4993     }
4994 
4995     /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4996     if (NT_SUCCESS(Status))
4997     {
4998         RxTransitionNetFcb(Fcb, Condition_Good);
4999         DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb, Fcb->Condition);
5000         ++Fcb->OpenCount;
5001         RxSetupNetFileObject(Context);
5002         return STATUS_SUCCESS;
5003     }
5004 
5005     /* Not mailslot! */
5006     /* Check SA for conflict */
5007     if (Fcb->OpenCount > 0)
5008     {
5009         Status = RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
5010                                     &Fcb->ShareAccess, FALSE, "early check per useropens", "EarlyPerUO");
5011         if (!NT_SUCCESS(Status))
5012         {
5013             RxDereferenceNetFcb(Fcb);
5014             return Status;
5015         }
5016     }
5017 
5018     if (BooleanFlagOn(Context->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE) &&
5019         !BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, ~SYNCHRONIZE))
5020     {
5021         UNIMPLEMENTED;
5022     }
5023 
5024     _SEH2_TRY
5025     {
5026         /* Find a SRV_OPEN that suits the opening */
5027         Status = RxCollapseOrCreateSrvOpen(Context);
5028         if (Status == STATUS_SUCCESS)
5029         {
5030             PFOBX Fobx;
5031             PSRV_OPEN SrvOpen;
5032 
5033             SrvOpen = (PSRV_OPEN)Context->pRelevantSrvOpen;
5034             Fobx = (PFOBX)Context->pFobx;
5035             /* There are already opens, check for conflict */
5036             if (Fcb->OpenCount != 0)
5037             {
5038                 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess, DesiredShareAccess,
5039                                                    FileObject, &Fcb->ShareAccess,
5040                                                    FALSE, "second check per useropens",
5041                                                    "2ndAccPerUO")))
5042                 {
5043                     ++SrvOpen->UncleanFobxCount;
5044                     RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
5045 
5046                     _SEH2_LEAVE;
5047                 }
5048             }
5049             else
5050             {
5051                 if (NetRoot->Type != NET_ROOT_PIPE)
5052                 {
5053                     RxSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
5054                                      &Fcb->ShareAccess, "initial shareaccess setup", "InitShrAcc");
5055                 }
5056             }
5057 
5058             RxSetupNetFileObject(Context);
5059 
5060             /* No conflict? Set up SA */
5061             if (Fcb->OpenCount != 0 && NetRoot->Type != NET_ROOT_PIPE)
5062             {
5063                 RxUpdateShareAccess(FileObject, &Fcb->ShareAccess, "update share access", "UpdShrAcc");
5064             }
5065 
5066             ++Fcb->UncleanCount;
5067             if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
5068             {
5069                 ++Fcb->UncachedUncleanCount;
5070             }
5071 
5072             if (SrvOpen->UncleanFobxCount == 0 && Fcb->UncleanCount == 1 &&
5073                 !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE))
5074             {
5075                 RxChangeBufferingState(SrvOpen, NULL, FALSE);
5076             }
5077 
5078             /* No pending close, we're active */
5079             ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
5080 
5081             ++Fcb->OpenCount;
5082             ++SrvOpen->UncleanFobxCount;
5083             ++SrvOpen->OpenCount;
5084             SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
5085 
5086             if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
5087             {
5088                 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING);
5089                 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
5090 
5091                 ClearFlag(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED);
5092                 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
5093 
5094                 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
5095             }
5096 
5097             /* Now, update SA for the SRV_OPEN */
5098             RxUpdateShareAccessPerSrvOpens(SrvOpen);
5099 
5100             if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
5101             {
5102                 SetFlag(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE);
5103             }
5104 
5105             /* Update the FOBX info */
5106             if (Fobx != NULL)
5107             {
5108                 if (Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
5109                 {
5110                     SetFlag(FileObject->Flags, FO_NAMED_PIPE);
5111                 }
5112 
5113                 if (Context->Create.pNetRoot->Type == NET_ROOT_PRINT ||
5114                     Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
5115                 {
5116                     Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
5117 
5118                     Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0;
5119                     Fobx->Specific.NamedPipe.CollectDataSize = Context->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
5120 
5121                     Fobx->Specific.NamedPipe.PipeHandleInformation.TypeOfPipe = Context->Create.PipeType;
5122                     Fobx->Specific.NamedPipe.PipeHandleInformation.ReadMode = Context->Create.PipeReadMode;
5123                     Fobx->Specific.NamedPipe.PipeHandleInformation.CompletionMode = Context->Create.PipeCompletionMode;
5124 
5125                     InitializeListHead(&Fobx->Specific.NamedPipe.ReadSerializationQueue);
5126                     InitializeListHead(&Fobx->Specific.NamedPipe.WriteSerializationQueue);
5127                 }
5128             }
5129 
5130             Status = STATUS_SUCCESS;
5131         }
5132     }
5133     _SEH2_FINALLY
5134     {
5135         if (Fcb->OpenCount == 0)
5136         {
5137             if (Context->Create.FcbAcquired)
5138             {
5139                 Context->Create.FcbAcquired = (RxDereferenceAndFinalizeNetFcb(Fcb,
5140                                                                               Context,
5141                                                                               FALSE,
5142                                                                               FALSE) == 0);
5143                 if (!Context->Create.FcbAcquired)
5144                 {
5145                     RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
5146                 }
5147             }
5148         }
5149         else
5150         {
5151             RxDereferenceNetFcb(Fcb);
5152         }
5153     }
5154     _SEH2_END;
5155 
5156     return Status;
5157 }
5158 
5159 /*
5160  * @implemented
5161  */
5162 NTSTATUS
5163 RxCreateTreeConnect(
5164     IN PRX_CONTEXT RxContext)
5165 {
5166     NTSTATUS Status;
5167     PV_NET_ROOT VNetRoot;
5168     PFILE_OBJECT FileObject;
5169     PIO_STACK_LOCATION Stack;
5170     NET_ROOT_TYPE NetRootType;
5171     UNICODE_STRING CanonicalName, RemainingName;
5172 
5173     PAGED_CODE();
5174 
5175     Stack = RxContext->CurrentIrpSp;
5176     FileObject = Stack->FileObject;
5177 
5178     RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
5179     /* As long as we don't know connection type, mark it wild */
5180     NetRootType = NET_ROOT_WILD;
5181     /* Get the type by parsing the name */
5182     Status = RxFirstCanonicalize(RxContext, &FileObject->FileName, &CanonicalName, &NetRootType);
5183     if (!NT_SUCCESS(Status))
5184     {
5185         return Status;
5186     }
5187 
5188     RxContext->Create.ThisIsATreeConnectOpen = TRUE;
5189     RxContext->Create.TreeConnectOpenDeferred = FALSE;
5190     RtlInitEmptyUnicodeString(&RxContext->Create.TransportName, NULL, 0);
5191     RtlInitEmptyUnicodeString(&RxContext->Create.UserName, NULL, 0);
5192     RtlInitEmptyUnicodeString(&RxContext->Create.Password, NULL, 0);
5193     RtlInitEmptyUnicodeString(&RxContext->Create.UserDomainName, NULL, 0);
5194 
5195     /* We don't handle EA - they come from DFS, don't care */
5196     if (Stack->Parameters.Create.EaLength > 0)
5197     {
5198         UNIMPLEMENTED;
5199     }
5200 
5201     /* Mount if required */
5202     Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
5203     if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT)
5204     {
5205         RxScavengeVNetRoots(RxContext->RxDeviceObject);
5206         Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
5207     }
5208 
5209     if (!NT_SUCCESS(Status))
5210     {
5211         return Status;
5212     }
5213 
5214     /* Validate the rest of the name with mini-rdr */
5215     if (RemainingName.Length > 0)
5216     {
5217         MINIRDR_CALL(Status, RxContext,
5218                      RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
5219                      MRxIsValidDirectory, (RxContext, &RemainingName));
5220     }
5221 
5222     if (!NT_SUCCESS(Status))
5223     {
5224         return Status;
5225     }
5226 
5227     VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
5228     RxReferenceVNetRoot(VNetRoot);
5229     if (InterlockedCompareExchange(&VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0)
5230     {
5231         RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
5232     }
5233 
5234     FileObject->FsContext = &RxDeviceFCB;
5235     FileObject->FsContext2 = VNetRoot;
5236 
5237     VNetRoot->ConstructionStatus = STATUS_SUCCESS;
5238     ++VNetRoot->NumberOfOpens;
5239 
5240     /* Create is over - clear context */
5241     RxContext->Create.pSrvCall = NULL;
5242     RxContext->Create.pNetRoot = NULL;
5243     RxContext->Create.pVNetRoot = NULL;
5244 
5245     return Status;
5246 }
5247 
5248 VOID
5249 NTAPI
5250 RxDebugControlCommand(
5251     _In_ PSTR ControlString)
5252 {
5253     UNIMPLEMENTED;
5254 }
5255 
5256 NTSTATUS
5257 NTAPI
5258 RxDriverEntry(
5259     IN PDRIVER_OBJECT DriverObject,
5260     IN PUNICODE_STRING RegistryPath)
5261 {
5262     NTSTATUS Status;
5263     USHORT i, State = 0;
5264 
5265     DPRINT("RxDriverEntry(%p, %p)\n", DriverObject, RegistryPath);
5266 
5267     _SEH2_TRY
5268     {
5269         RxCheckFcbStructuresForAlignment();
5270 
5271         RtlZeroMemory(&RxData, sizeof(RxData));
5272         RxData.NodeTypeCode = RDBSS_NTC_DATA_HEADER;
5273         RxData.NodeByteSize = sizeof(RxData);
5274         RxData.DriverObject = DriverObject;
5275 
5276         RtlZeroMemory(&RxDeviceFCB, sizeof(RxDeviceFCB));
5277         RxDeviceFCB.spacer.NodeTypeCode = RDBSS_NTC_DEVICE_FCB;
5278         RxDeviceFCB.spacer.NodeByteSize = sizeof(RxDeviceFCB);
5279 
5280         KeInitializeSpinLock(&RxStrucSupSpinLock);
5281         RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
5282 
5283         RxInitializeDebugSupport();
5284 
5285         RxFileSystemDeviceObject = (PRDBSS_DEVICE_OBJECT)&RxSpaceForTheWrappersDeviceObject;
5286         RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject, sizeof(RxSpaceForTheWrappersDeviceObject));
5287 
5288         RxInitializeLog();
5289         State = 2;
5290 
5291         RxGetRegistryParameters(RegistryPath);
5292         RxReadRegistryParameters();
5293 
5294         Status = RxInitializeRegistrationStructures();
5295         if (!NT_SUCCESS(Status))
5296         {
5297             _SEH2_LEAVE;
5298         }
5299         State = 1;
5300 
5301         RxInitializeDispatcher();
5302 
5303         ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
5304 
5305         InitializeListHead(&RxIrpsList);
5306         KeInitializeSpinLock(&RxIrpsListSpinLock);
5307 
5308         InitializeListHead(&RxActiveContexts);
5309         InitializeListHead(&RxSrvCalldownList);
5310 
5311         ExInitializeFastMutex(&RxContextPerFileSerializationMutex);
5312         ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex);
5313         KeInitializeMutex(&RxScavengerMutex, 1);
5314         KeInitializeMutex(&RxSerializationMutex, 1);
5315 
5316         for (i = 0; i < RxMaximumWorkQueue; ++i)
5317         {
5318             RxFileSystemDeviceObject->PostedRequestCount[i] = 0;
5319             RxFileSystemDeviceObject->OverflowQueueCount[i] = 0;
5320             InitializeListHead(&RxFileSystemDeviceObject->OverflowQueue[i]);
5321         }
5322 
5323         KeInitializeSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock);
5324 
5325         RxInitializeDispatchVectors(DriverObject);
5326 
5327         ExInitializeResourceLite(&RxData.Resource);
5328         RxData.OurProcess = IoGetCurrentProcess();
5329 
5330         RxInitializeRxTimer();
5331     }
5332     _SEH2_FINALLY
5333     {
5334         if (!NT_SUCCESS(Status))
5335         {
5336             RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BC4, Status);
5337             RxInitUnwind(DriverObject, State);
5338         }
5339     } _SEH2_END;
5340 
5341     /* There are still bits to init - be consider it's fine for now */
5342 #if 0
5343     UNIMPLEMENTED;
5344     return STATUS_NOT_IMPLEMENTED;
5345 #else
5346     return STATUS_SUCCESS;
5347 #endif
5348 }
5349 
5350 #if DBG
5351 /*
5352  * @implemented
5353  */
5354 VOID
5355 RxDumpCurrentAccess(
5356     _In_ PSZ where1,
5357     _In_ PSZ where2,
5358     _In_ PSZ wherelogtag,
5359     _In_ PSHARE_ACCESS ShareAccess)
5360 {
5361     PAGED_CODE();
5362 }
5363 
5364 /*
5365  * @implemented
5366  */
5367 VOID
5368 RxDumpWantedAccess(
5369     _In_ PSZ where1,
5370     _In_ PSZ where2,
5371     _In_ PSZ wherelogtag,
5372     _In_ ACCESS_MASK DesiredAccess,
5373     _In_ ULONG DesiredShareAccess)
5374 {
5375     PAGED_CODE();
5376 }
5377 #endif
5378 
5379 /*
5380  * @implemented
5381  */
5382 BOOLEAN
5383 NTAPI
5384 RxFastIoCheckIfPossible(
5385     PFILE_OBJECT FileObject,
5386     PLARGE_INTEGER FileOffset,
5387     ULONG Length, BOOLEAN Wait,
5388     ULONG LockKey, BOOLEAN CheckForReadOperation,
5389     PIO_STATUS_BLOCK IoStatus,
5390     PDEVICE_OBJECT DeviceObject)
5391 {
5392     PFCB Fcb;
5393     PSRV_OPEN SrvOpen;
5394     LARGE_INTEGER LargeLength;
5395 
5396     PAGED_CODE();
5397 
5398     /* Get the FCB to validate it */
5399     Fcb = FileObject->FsContext;
5400     if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
5401     {
5402         DPRINT1("Not a file, FastIO not possible!\n");
5403         return FALSE;
5404     }
5405 
5406     if (FileObject->DeletePending)
5407     {
5408         DPRINT1("File delete pending\n");
5409         return FALSE;
5410     }
5411 
5412     /* If there's a pending write operation, deny fast operation */
5413     if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
5414     {
5415         DPRINT1("Write operations to be completed\n");
5416         return FALSE;
5417     }
5418 
5419     /* Deny read on orphaned node */
5420     SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
5421     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
5422     {
5423         DPRINT1("SRV_OPEN orphaned\n");
5424         return FALSE;
5425     }
5426 
5427     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
5428     {
5429         DPRINT1("FCB orphaned\n");
5430         return FALSE;
5431     }
5432 
5433     /* If there's a buffering state change pending, deny fast operation (it might change
5434      * cache status)
5435      */
5436     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
5437     {
5438         DPRINT1("Buffering change pending\n");
5439         return FALSE;
5440     }
5441 
5442     /* File got renamed/deleted, deny operation */
5443     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
5444         BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
5445     {
5446         DPRINT1("File renamed/deleted\n");
5447         return FALSE;
5448     }
5449 
5450     /* Process pending change buffering state operations */
5451     FsRtlEnterFileSystem();
5452     RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
5453     FsRtlExitFileSystem();
5454 
5455     LargeLength.QuadPart = Length;
5456 
5457     /* If operation to come is a read operation */
5458     if (CheckForReadOperation)
5459     {
5460         /* Check that read cache is enabled */
5461         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
5462         {
5463             DPRINT1("Read caching disabled\n");
5464             return FALSE;
5465         }
5466 
5467         /* Check whether there's a lock conflict */
5468         if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
5469                                        FileOffset,
5470                                        &LargeLength,
5471                                        LockKey,
5472                                        FileObject,
5473                                        PsGetCurrentProcess()))
5474         {
5475             DPRINT1("FsRtlFastCheckLockForRead failed\n");
5476             return FALSE;
5477         }
5478 
5479         return TRUE;
5480     }
5481 
5482     /* Check that write cache is enabled */
5483     if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED))
5484     {
5485         DPRINT1("Write caching disabled\n");
5486         return FALSE;
5487     }
5488 
5489     /* Check whether there's a lock conflict */
5490     if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock,
5491                                     FileOffset,
5492                                     &LargeLength,
5493                                     LockKey,
5494                                     FileObject,
5495                                     PsGetCurrentProcess()))
5496     {
5497         DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5498         return FALSE;
5499     }
5500 
5501     return TRUE;
5502 }
5503 
5504 BOOLEAN
5505 NTAPI
5506 RxFastIoDeviceControl(
5507     PFILE_OBJECT FileObject,
5508     BOOLEAN Wait,
5509     PVOID InputBuffer OPTIONAL,
5510     ULONG InputBufferLength,
5511     PVOID OutputBuffer OPTIONAL,
5512     ULONG OutputBufferLength,
5513     ULONG IoControlCode,
5514     PIO_STATUS_BLOCK IoStatus,
5515     PDEVICE_OBJECT DeviceObject)
5516 {
5517     /* Only supported IOCTL */
5518     if (IoControlCode == IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
5519     {
5520         UNIMPLEMENTED;
5521         return FALSE;
5522     }
5523     else
5524     {
5525         return FALSE;
5526     }
5527 }
5528 
5529 /*
5530  * @implemented
5531  */
5532 BOOLEAN
5533 NTAPI
5534 RxFastIoRead(
5535     PFILE_OBJECT FileObject,
5536     PLARGE_INTEGER FileOffset,
5537     ULONG Length,
5538     BOOLEAN Wait,
5539     ULONG LockKey,
5540     PVOID Buffer,
5541     PIO_STATUS_BLOCK IoStatus,
5542     PDEVICE_OBJECT DeviceObject)
5543 {
5544     BOOLEAN Ret;
5545     RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5546 
5547     PAGED_CODE();
5548 
5549     DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
5550                                           FileObject->FsContext2);
5551     DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
5552 
5553     /* Prepare a TLI context */
5554     ASSERT(RxIsThisTheTopLevelIrp(NULL));
5555     RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
5556                                    (PRDBSS_DEVICE_OBJECT)DeviceObject);
5557 
5558     Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
5559                          IoStatus, DeviceObject, &TopLevelContext);
5560     if (Ret)
5561     {
5562         DPRINT("Read OK\n");
5563     }
5564     else
5565     {
5566         DPRINT1("Read failed!\n");
5567     }
5568 
5569     return Ret;
5570 }
5571 
5572 /*
5573  * @implemented
5574  */
5575 BOOLEAN
5576 NTAPI
5577 RxFastIoWrite(
5578     PFILE_OBJECT FileObject,
5579     PLARGE_INTEGER FileOffset,
5580     ULONG Length,
5581     BOOLEAN Wait,
5582     ULONG LockKey,
5583     PVOID Buffer,
5584     PIO_STATUS_BLOCK IoStatus,
5585     PDEVICE_OBJECT DeviceObject)
5586 {
5587     PFOBX Fobx;
5588     BOOLEAN Ret;
5589     RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5590 
5591     PAGED_CODE();
5592 
5593     Fobx = (PFOBX)FileObject->FsContext2;
5594     if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE))
5595     {
5596         return FALSE;
5597     }
5598 
5599     DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext,
5600                                            FileObject->FsContext2);
5601     DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
5602 
5603     /* Prepare a TLI context */
5604     ASSERT(RxIsThisTheTopLevelIrp(NULL));
5605     RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
5606                                    (PRDBSS_DEVICE_OBJECT)DeviceObject);
5607 
5608     Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
5609                           IoStatus, DeviceObject, &TopLevelContext);
5610     if (Ret)
5611     {
5612         DPRINT("Write OK\n");
5613     }
5614     else
5615     {
5616         DPRINT1("Write failed!\n");
5617     }
5618 
5619     return Ret;
5620 }
5621 
5622 NTSTATUS
5623 RxFindOrCreateFcb(
5624     PRX_CONTEXT RxContext,
5625     PUNICODE_STRING NetRootName)
5626 {
5627     PFCB Fcb;
5628     ULONG Version;
5629     NTSTATUS Status;
5630     PNET_ROOT NetRoot;
5631     PV_NET_ROOT VNetRoot;
5632     BOOLEAN TableAcquired, AcquiredExclusive;
5633 
5634     PAGED_CODE();
5635 
5636     NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
5637     VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
5638     ASSERT(NetRoot == VNetRoot->NetRoot);
5639 
5640     Status = STATUS_SUCCESS;
5641     AcquiredExclusive = FALSE;
5642 
5643     RxAcquireFcbTableLockShared(&NetRoot->FcbTable, TRUE);
5644     TableAcquired = TRUE;
5645     Version = NetRoot->FcbTable.Version;
5646 
5647     /* Look for a cached FCB */
5648     Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5649     if (Fcb == NULL)
5650     {
5651         DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName);
5652     }
5653     else
5654     {
5655         DPRINT("FCB found for %wZ\n", &Fcb->FcbTableEntry.Path);
5656         /* If FCB was to be orphaned, consider it as not suitable */
5657         if (Fcb->fShouldBeOrphaned)
5658         {
5659             RxDereferenceNetFcb(Fcb);
5660             RxReleaseFcbTableLock(&NetRoot->FcbTable);
5661 
5662             RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5663             TableAcquired = TRUE;
5664             AcquiredExclusive = TRUE;
5665 
5666             Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5667             if (Fcb != NULL && Fcb->fShouldBeOrphaned)
5668             {
5669                 RxOrphanThisFcb(Fcb);
5670                 RxDereferenceNetFcb(Fcb);
5671                 Fcb = NULL;
5672             }
5673         }
5674     }
5675 
5676     /* If FCB was not found or is not covering full path, prepare for more work */
5677     if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
5678     {
5679         if (Fcb != NULL)
5680         {
5681             DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb->FcbTableEntry.Path, NetRootName);
5682         }
5683 
5684         if (!AcquiredExclusive)
5685         {
5686             RxReleaseFcbTableLock(&NetRoot->FcbTable);
5687             RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5688             TableAcquired = TRUE;
5689         }
5690 
5691         /* If FCB table was updated in between, re-attempt a lookup */
5692         if (NetRoot->FcbTable.Version != Version)
5693         {
5694             Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5695             if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
5696             {
5697                 Fcb = NULL;
5698             }
5699         }
5700     }
5701 
5702     /* Allocate the FCB */
5703     _SEH2_TRY
5704     {
5705         if (Fcb == NULL)
5706         {
5707             Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName);
5708             if (Fcb == NULL)
5709             {
5710                 Status = STATUS_INSUFFICIENT_RESOURCES;
5711             }
5712             else
5713             {
5714                 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5715                 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5716             }
5717         }
5718     }
5719     _SEH2_FINALLY
5720     {
5721         if (_SEH2_AbnormalTermination())
5722         {
5723             RxReleaseFcbTableLock(&NetRoot->FcbTable);
5724             TableAcquired = FALSE;
5725 
5726             if (Fcb != NULL)
5727             {
5728                 RxTransitionNetFcb(Fcb, Condition_Bad);
5729 
5730                 ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
5731                 if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0)
5732                 {
5733                     ExReleaseResourceLite(Fcb->Header.Resource);
5734                 }
5735             }
5736         }
5737     }
5738     _SEH2_END;
5739 
5740     if (TableAcquired)
5741     {
5742         RxReleaseFcbTableLock(&NetRoot->FcbTable);
5743     }
5744 
5745     if (!NT_SUCCESS(Status))
5746     {
5747         return Status;
5748     }
5749 
5750     RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
5751     DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
5752 
5753     if (!RxContext->Create.FcbAcquired)
5754     {
5755         RxWaitForStableNetFcb(Fcb, RxContext);
5756         Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5757         RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5758     }
5759 
5760     return Status;
5761 }
5762 
5763 NTSTATUS
5764 RxFirstCanonicalize(
5765     PRX_CONTEXT RxContext,
5766     PUNICODE_STRING FileName,
5767     PUNICODE_STRING CanonicalName,
5768     PNET_ROOT_TYPE NetRootType)
5769 {
5770     NTSTATUS Status;
5771     NET_ROOT_TYPE Type;
5772     BOOLEAN UncName, PrependString, IsSpecial;
5773     USHORT CanonicalLength;
5774     UNICODE_STRING SessionIdString;
5775     WCHAR SessionIdBuffer[16];
5776 
5777     PAGED_CODE();
5778 
5779     Type = NET_ROOT_WILD;
5780     PrependString = FALSE;
5781     IsSpecial = FALSE;
5782     UncName = FALSE;
5783     Status = STATUS_SUCCESS;
5784 
5785     /* Name has to contain at least \\ */
5786     if (FileName->Length < 2 * sizeof(WCHAR))
5787     {
5788         return STATUS_OBJECT_NAME_INVALID;
5789     }
5790 
5791     /* First easy check, is that a path with a name? */
5792     CanonicalLength = FileName->Length;
5793     if (FileName->Length > 5 * sizeof(WCHAR))
5794     {
5795         if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';')
5796         {
5797             if (FileName->Buffer[3] == ':')
5798             {
5799                 Type = NET_ROOT_DISK;
5800             }
5801             else
5802             {
5803                 Type = NET_ROOT_PRINT;
5804             }
5805         }
5806     }
5807 
5808     /* Nope, attempt deeper parsing */
5809     if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';')
5810     {
5811         ULONG SessionId;
5812         PWSTR FirstSlash, EndOfString;
5813 
5814         SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME);
5815         UncName = TRUE;
5816 
5817         /* The lack of drive letter will be replaced by session ID */
5818         SessionId = RxGetSessionId(RxContext->CurrentIrpSp);
5819         RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer));
5820         RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
5821 
5822         EndOfString = Add2Ptr(FileName->Buffer, FileName->Length);
5823         for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash)
5824         {
5825             if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR)
5826             {
5827                 break;
5828             }
5829         }
5830 
5831         if (EndOfString - FirstSlash <= sizeof(WCHAR))
5832         {
5833             Status = STATUS_OBJECT_NAME_INVALID;
5834         }
5835         else
5836         {
5837             UNIMPLEMENTED;
5838             DPRINT1("WARNING: Assuming not special + disk!\n");
5839             Type = NET_ROOT_DISK;
5840             Status = STATUS_SUCCESS;
5841             //Status = STATUS_NOT_IMPLEMENTED;
5842             /* Should be check against IPC, mailslot, and so on */
5843         }
5844     }
5845 
5846     /* Update net root type with our deduced one */
5847     *NetRootType = Type;
5848     DPRINT("Returning type: %x\n", Type);
5849 
5850     if (!NT_SUCCESS(Status))
5851     {
5852         return Status;
5853     }
5854 
5855     /* Do we have to prepend session ID? */
5856     if (UncName)
5857     {
5858         if (!IsSpecial)
5859         {
5860             PrependString = TRUE;
5861             CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR);
5862         }
5863     }
5864 
5865     /* If not UNC path, we should preprend stuff */
5866     if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\')
5867     {
5868         return STATUS_OBJECT_PATH_INVALID;
5869     }
5870 
5871     /* Allocate the buffer */
5872     Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength);
5873     if (!NT_SUCCESS(Status))
5874     {
5875         return Status;
5876     }
5877 
5878     /* We don't support that case, we always return disk */
5879     if (IsSpecial)
5880     {
5881         ASSERT(CanonicalName->Length == CanonicalLength);
5882         UNIMPLEMENTED;
5883         Status = STATUS_NOT_IMPLEMENTED;
5884     }
5885     else
5886     {
5887         /* If we have to prepend, go ahead */
5888         if (PrependString)
5889         {
5890             CanonicalName->Buffer[0] = '\\';
5891             CanonicalName->Buffer[1] = ';';
5892             CanonicalName->Buffer[2] = ':';
5893             CanonicalName->Length = 3 * sizeof(WCHAR);
5894             RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString);
5895             RtlAppendUnicodeStringToString(CanonicalName, FileName);
5896 
5897             DPRINT1("CanonicalName: %wZ\n", CanonicalName);
5898         }
5899         /* Otherwise, that's a simple copy */
5900         else
5901         {
5902             RtlCopyUnicodeString(CanonicalName, FileName);
5903         }
5904     }
5905 
5906     return Status;
5907 }
5908 
5909 /*
5910  * @implemented
5911  */
5912 VOID
5913 RxFreeCanonicalNameBuffer(
5914     PRX_CONTEXT Context)
5915 {
5916     /* These two buffers are always the same */
5917     ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
5918 
5919     if (Context->Create.CanonicalNameBuffer != NULL)
5920     {
5921         RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
5922         Context->Create.CanonicalNameBuffer = NULL;
5923         Context->AlsoCanonicalNameBuffer = NULL;
5924     }
5925 
5926     ASSERT(Context->AlsoCanonicalNameBuffer == NULL);
5927 }
5928 
5929 NTSTATUS
5930 RxFsdCommonDispatch(
5931     PRX_FSD_DISPATCH_VECTOR DispatchVector,
5932     UCHAR MajorFunction,
5933     PIO_STACK_LOCATION Stack,
5934     PFILE_OBJECT FileObject,
5935     PIRP Irp,
5936     PRDBSS_DEVICE_OBJECT RxDeviceObject)
5937 {
5938     KIRQL OldIrql;
5939     NTSTATUS Status;
5940     PRX_CONTEXT Context;
5941     UCHAR MinorFunction;
5942     PFILE_OBJECT StackFileObject;
5943     PRX_FSD_DISPATCH DispatchFunc;
5944     RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5945     BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
5946 
5947     Status = STATUS_SUCCESS;
5948 
5949     DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
5950 
5951     FsRtlEnterFileSystem();
5952 
5953     TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
5954 
5955     _SEH2_TRY
5956     {
5957         CanWait = TRUE;
5958         Closing = FALSE;
5959         PostRequest = FALSE;
5960         SetCancelRoutine = TRUE;
5961         MinorFunction = Stack->MinorFunction;
5962         /* Can we wait? */
5963         switch (MajorFunction)
5964         {
5965             case IRP_MJ_FILE_SYSTEM_CONTROL:
5966                 if (FileObject != NULL)
5967                 {
5968                     CanWait = IoIsOperationSynchronous(Irp);
5969                 }
5970                 else
5971                 {
5972                     CanWait = TRUE;
5973                 }
5974                 break;
5975 
5976             case IRP_MJ_READ:
5977             case IRP_MJ_WRITE:
5978             case IRP_MJ_QUERY_INFORMATION:
5979             case IRP_MJ_SET_INFORMATION:
5980             case IRP_MJ_QUERY_EA:
5981             case IRP_MJ_SET_EA:
5982             case IRP_MJ_FLUSH_BUFFERS:
5983             case IRP_MJ_QUERY_VOLUME_INFORMATION:
5984             case IRP_MJ_SET_VOLUME_INFORMATION:
5985             case IRP_MJ_DIRECTORY_CONTROL:
5986             case IRP_MJ_DEVICE_CONTROL:
5987             case IRP_MJ_LOCK_CONTROL:
5988             case IRP_MJ_QUERY_SECURITY:
5989             case IRP_MJ_SET_SECURITY:
5990                 CanWait = IoIsOperationSynchronous(Irp);
5991                 break;
5992 
5993             case IRP_MJ_CLOSE:
5994             case IRP_MJ_CLEANUP:
5995                 Closing = TRUE;
5996                 SetCancelRoutine = FALSE;
5997                 break;
5998 
5999             default:
6000                 break;
6001         }
6002 
6003         KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
6004         /* Should we stop it right now, or mini-rdr deserves to know? */
6005         PassToDriver = TRUE;
6006         if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE)
6007         {
6008             if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing)
6009             {
6010                 PassToDriver = FALSE;
6011                 Status = STATUS_REDIRECTOR_NOT_STARTED;
6012                 DPRINT1("Not started!\n");
6013             }
6014         }
6015         else
6016         {
6017             if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL))
6018             {
6019                 PassToDriver = FALSE;
6020                 Status = STATUS_REDIRECTOR_NOT_STARTED;
6021                 DPRINT1("Not started!\n");
6022             }
6023         }
6024         KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
6025 
6026         StackFileObject = Stack->FileObject;
6027         /* Make sure we don't deal with orphaned stuff */
6028         if (StackFileObject != NULL && StackFileObject->FsContext != NULL)
6029         {
6030             if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) &&
6031                 StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
6032                 StackFileObject->FsContext != &RxDeviceFCB)
6033             {
6034                 PFCB Fcb;
6035                 PFOBX Fobx;
6036 
6037                 Fcb = StackFileObject->FsContext;
6038                 Fobx = StackFileObject->FsContext2;
6039 
6040                 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) ||
6041                     ((Fobx != NULL) && BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED)))
6042                 {
6043                     if (Closing)
6044                     {
6045                         PassToDriver = TRUE;
6046                     }
6047                     else
6048                     {
6049                         PassToDriver = FALSE;
6050                         Status = STATUS_UNEXPECTED_NETWORK_ERROR;
6051                         DPRINT1("Operation on orphaned FCB: %p\n", Fcb);
6052                     }
6053                 }
6054             }
6055         }
6056 
6057         /* Did we receive a close request whereas we're stopping? */
6058         if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing)
6059         {
6060             PFCB Fcb;
6061 
6062             Fcb = StackFileObject->FsContext;
6063 
6064             DPRINT1("Close received after stop\n");
6065             DPRINT1("Irp: %p  %d:%d FO: %p FCB: %p\n",
6066                     Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
6067 
6068             if (Fcb != NULL && Fcb != &RxDeviceFCB &&
6069                 NodeTypeIsFcb(Fcb))
6070             {
6071                 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6072                         Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path);
6073             }
6074         }
6075 
6076         /* Should we stop the whole thing now? */
6077         if (!PassToDriver)
6078         {
6079             if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE)
6080             {
6081                 IoMarkIrpPending(Irp);
6082                 Irp->IoStatus.Status = Status;
6083                 Irp->IoStatus.Information = 0;
6084                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6085                 Status = STATUS_PENDING;
6086             }
6087             else
6088             {
6089                 Irp->IoStatus.Status = Status;
6090                 Irp->IoStatus.Information = 0;
6091                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6092             }
6093 
6094             _SEH2_LEAVE;
6095         }
6096 
6097         /* No? Allocate a context to deal with the mini-rdr */
6098         Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0));
6099         if (Context == NULL)
6100         {
6101             Status = STATUS_INSUFFICIENT_RESOURCES;
6102             RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES);
6103             _SEH2_LEAVE;
6104         }
6105 
6106         /* Set cancel routine if required */
6107         if (SetCancelRoutine)
6108         {
6109             IoAcquireCancelSpinLock(&OldIrql);
6110             IoSetCancelRoutine(Irp, RxCancelRoutine);
6111         }
6112         else
6113         {
6114             IoAcquireCancelSpinLock(&OldIrql);
6115             IoSetCancelRoutine(Irp, NULL);
6116         }
6117         IoReleaseCancelSpinLock(OldIrql);
6118 
6119         ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6120 
6121         Irp->IoStatus.Status = STATUS_SUCCESS;
6122         Irp->IoStatus.Information = 0;
6123         /* Get the dispatch routine */
6124         DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
6125 
6126         if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE)
6127         {
6128             /* Handle the complete MDL case */
6129             if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE))
6130             {
6131                 DispatchFunc = RxCompleteMdl;
6132             }
6133             else
6134             {
6135                 /* Do we have to post request? */
6136                 if (BooleanFlagOn(MinorFunction, IRP_MN_DPC))
6137                 {
6138                     PostRequest = TRUE;
6139                 }
6140                 else
6141                 {
6142                     /* Our read function needs stack, make sure we won't overflow,
6143                      * otherwise, post the request
6144                      */
6145                     if (MajorFunction == IRP_MJ_READ)
6146                     {
6147                         if (IoGetRemainingStackSize() < 0xE00)
6148                         {
6149                             Context->PendingReturned = TRUE;
6150                             Status = RxPostStackOverflowRead(Context);
6151                             if (Status != STATUS_PENDING)
6152                             {
6153                                 Context->PendingReturned = FALSE;
6154                                 RxCompleteAsynchronousRequest(Context, Status);
6155                             }
6156 
6157                             _SEH2_LEAVE;
6158                         }
6159                     }
6160                 }
6161             }
6162         }
6163 
6164         Context->ResumeRoutine = DispatchFunc;
6165         /* There's a dispatch routine? Time to dispatch! */
6166         if (DispatchFunc != NULL)
6167         {
6168             Context->PendingReturned = TRUE;
6169             if (PostRequest)
6170             {
6171                 Status = RxFsdPostRequest(Context);
6172             }
6173             else
6174             {
6175                 /* Retry as long as we have */
6176                 do
6177                 {
6178                     Status = DispatchFunc(Context);
6179                 }
6180                 while (Status == STATUS_RETRY);
6181 
6182                 if (Status == STATUS_PENDING)
6183                 {
6184                     _SEH2_LEAVE;
6185                 }
6186 
6187                 /* Sanity check: did someone mess with our context? */
6188                 if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack ||
6189                     Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction)
6190                 {
6191                     DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context);
6192                     DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp);
6193                     DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack);
6194                     DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction);
6195                     DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction);
6196                 }
6197                 Context->PendingReturned = FALSE;
6198                 Status = RxCompleteAsynchronousRequest(Context, Status);
6199             }
6200         }
6201         else
6202         {
6203             Status = STATUS_NOT_IMPLEMENTED;
6204         }
6205     }
6206     _SEH2_FINALLY
6207     {
6208         if (TopLevel)
6209         {
6210             RxUnwindTopLevelIrp(&TopLevelContext);
6211         }
6212 
6213         FsRtlExitFileSystem();
6214     }
6215     _SEH2_END;
6216 
6217     DPRINT("RxFsdDispatch, Status: %lx\n", Status);
6218     return Status;
6219 }
6220 
6221 /*
6222  * @implemented
6223  */
6224 NTSTATUS
6225 NTAPI
6226 RxFsdDispatch(
6227     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
6228     IN PIRP Irp)
6229 {
6230     PFCB Fcb;
6231     PIO_STACK_LOCATION Stack;
6232     PRX_FSD_DISPATCH_VECTOR DispatchVector;
6233 
6234     PAGED_CODE();
6235 
6236     DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
6237 
6238     Stack = IoGetCurrentIrpStackLocation(Irp);
6239 
6240     /* Dispatch easy case */
6241     if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
6242     {
6243         return RxSystemControl(RxDeviceObject, Irp);
6244     }
6245 
6246     /* Bail out broken cases */
6247     if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ||
6248         Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE)
6249     {
6250         IoMarkIrpPending(Irp);
6251         Irp->IoStatus.Information = 0;
6252         Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
6253         IoCompleteRequest(Irp, IO_NO_INCREMENT);
6254         return STATUS_PENDING;
6255     }
6256 
6257     /* Immediately handle create */
6258     if (Stack->MajorFunction == IRP_MJ_CREATE)
6259     {
6260         return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6261     }
6262 
6263     /* If not a creation, we must have at least a FO with a FCB */
6264     if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL)
6265     {
6266         IoMarkIrpPending(Irp);
6267         Irp->IoStatus.Information = 0;
6268         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6269         IoCompleteRequest(Irp, IO_NO_INCREMENT);
6270         return STATUS_PENDING;
6271     }
6272 
6273     /* Set the dispatch vector if required */
6274     Fcb = Stack->FileObject->FsContext;
6275     if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL)
6276     {
6277         DispatchVector = &RxFsdDispatchVector[0];
6278     }
6279     else
6280     {
6281         DispatchVector = Fcb->PrivateDispatchVector;
6282     }
6283 
6284     /* Device cannot accept such requests */
6285     if (RxDeviceObject == RxFileSystemDeviceObject)
6286     {
6287         IoMarkIrpPending(Irp);
6288         Irp->IoStatus.Information = 0;
6289         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6290         IoCompleteRequest(Irp, IO_NO_INCREMENT);
6291         return STATUS_PENDING;
6292     }
6293 
6294     /* Dispatch for real! */
6295     return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6296 }
6297 
6298 /*
6299  * @implemented
6300  */
6301 NTSTATUS
6302 RxFsdPostRequest(
6303     IN PRX_CONTEXT RxContext)
6304 {
6305     /* Initialize posting if required */
6306     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
6307     {
6308         RxPrePostIrp(RxContext, RxContext->CurrentIrp);
6309     }
6310 
6311     DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6312            RxContext->MinorFunction, RxContext,
6313            RxContext->CurrentIrp, RxContext->LastExecutionThread,
6314            RxContext->SerialNumber);
6315 
6316     RxAddToWorkque(RxContext, RxContext->CurrentIrp);
6317     return STATUS_PENDING;
6318 }
6319 
6320 /*
6321  * @implemented
6322  */
6323 VOID
6324 NTAPI
6325 RxFspDispatch(
6326     IN PVOID Context)
6327 {
6328     KIRQL EntryIrql;
6329     WORK_QUEUE_TYPE Queue;
6330     PRDBSS_DEVICE_OBJECT VolumeDO;
6331     PRX_CONTEXT RxContext, EntryContext;
6332 
6333     PAGED_CODE();
6334 
6335     RxContext = Context;
6336     EntryContext = Context;
6337     /* Save IRQL at entry for later checking */
6338     EntryIrql = KeGetCurrentIrql();
6339 
6340     /* No FO, deal with device */
6341     if (RxContext->CurrentIrpSp->FileObject != NULL)
6342     {
6343         VolumeDO = RxFileSystemDeviceObject;
6344     }
6345     else
6346     {
6347         VolumeDO = NULL;
6348     }
6349 
6350     /* Which queue to used for delayed? */
6351     if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE))
6352     {
6353         Queue = DelayedWorkQueue;
6354     }
6355     else
6356     {
6357         ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
6358         Queue = CriticalWorkQueue;
6359     }
6360 
6361     do
6362     {
6363         PIRP Irp;
6364         NTSTATUS Status;
6365         BOOLEAN RecursiveCall;
6366         RX_TOPLEVELIRP_CONTEXT TopLevelContext;
6367 
6368         ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6369         ASSERT(!RxContext->PostRequest);
6370 
6371         RxContext->LastExecutionThread = PsGetCurrentThread();
6372         SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
6373 
6374         DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext->MinorFunction,
6375                RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
6376                RxContext->SerialNumber);
6377 
6378         Irp = RxContext->CurrentIrp;
6379 
6380         FsRtlEnterFileSystem();
6381 
6382         RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
6383         RxTryToBecomeTheTopLevelIrp(&TopLevelContext,
6384                                     (RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp),
6385                                     RxContext->RxDeviceObject, TRUE);
6386 
6387         ASSERT(RxContext->ResumeRoutine != NULL);
6388 
6389         if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL)
6390         {
6391             ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ));
6392             Irp->Tail.Overlay.Thread = PsGetCurrentThread();
6393         }
6394 
6395         /* Call the resume routine */
6396         do
6397         {
6398             BOOLEAN NoComplete;
6399 
6400             NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
6401 
6402             Status = RxContext->ResumeRoutine(RxContext);
6403             if (!NoComplete && Status != STATUS_PENDING)
6404             {
6405                 if (Status != STATUS_RETRY)
6406                 {
6407                     Status = RxCompleteRequest(RxContext, Status);
6408                 }
6409             }
6410         }
6411         while (Status == STATUS_RETRY);
6412 
6413         RxUnwindTopLevelIrp(&TopLevelContext);
6414         FsRtlExitFileSystem();
6415 
6416         if (VolumeDO != NULL)
6417         {
6418             RxContext = RxRemoveOverflowEntry(VolumeDO, Queue);
6419         }
6420         else
6421         {
6422             RxContext = NULL;
6423         }
6424     } while (RxContext != NULL);
6425 
6426     /* Did we mess with IRQL? */
6427     if (KeGetCurrentIrql() >= APC_LEVEL)
6428     {
6429         DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql);
6430     }
6431 }
6432 
6433 /*
6434  * @implemented
6435  */
6436 ULONG
6437 RxGetNetworkProviderPriority(
6438     PUNICODE_STRING DeviceName)
6439 {
6440     PAGED_CODE();
6441     return 1;
6442 }
6443 
6444 /*
6445  * @implemented
6446  */
6447 VOID
6448 NTAPI
6449 RxGetRegistryParameters(
6450     IN PUNICODE_STRING RegistryPath)
6451 {
6452     USHORT i;
6453     NTSTATUS Status;
6454     UCHAR Buffer[0x400];
6455     HANDLE DriverHandle, KeyHandle;
6456     UNICODE_STRING KeyName, OutString;
6457     OBJECT_ATTRIBUTES ObjectAttributes;
6458 
6459     PAGED_CODE();
6460 
6461     InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
6462     Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6463     if (!NT_SUCCESS(Status))
6464     {
6465         return;
6466     }
6467 
6468     RtlInitUnicodeString(&KeyName, L"Parameters");
6469     InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE);
6470     Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6471     if (NT_SUCCESS(Status))
6472     {
6473         /* The only parameter we deal with is InitialDebugString */
6474         RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0);
6475         if (OutString.Length != 0 && OutString.Length < 0x140)
6476         {
6477             PWSTR Read;
6478             PSTR Write;
6479 
6480             Read = OutString.Buffer;
6481             Write = (PSTR)OutString.Buffer;
6482             for (i = 0; i < OutString.Length; ++i)
6483             {
6484                 *Read = *Write;
6485                 ++Write;
6486                 *Write = ANSI_NULL;
6487                 ++Read;
6488             }
6489 
6490             /* Which is a string we'll just write out */
6491             DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer);
6492             RxDebugControlCommand((PSTR)OutString.Buffer);
6493         }
6494 
6495         ZwClose(KeyHandle);
6496     }
6497 
6498     ZwClose(DriverHandle);
6499 }
6500 
6501 /*
6502  * @implemented
6503  */
6504 ULONG
6505 RxGetSessionId(
6506     IN PIO_STACK_LOCATION IrpSp)
6507 {
6508     ULONG SessionId;
6509     PACCESS_TOKEN Token;
6510     PIO_SECURITY_CONTEXT SecurityContext;
6511 
6512     PAGED_CODE();
6513 
6514     /* If that's not a prefix claim, not an open request, session id will be 0 */
6515     if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH)
6516     {
6517         if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL)
6518         {
6519             return 0;
6520         }
6521 
6522         SecurityContext = IrpSp->Parameters.Create.SecurityContext;
6523     }
6524     else
6525     {
6526         SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext;
6527     }
6528 
6529     /* Query the session id */
6530     Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext);
6531     SeQuerySessionIdToken(Token, &SessionId);
6532 
6533     return SessionId;
6534 }
6535 
6536 /*
6537  * @implemented
6538  */
6539 NTSTATUS
6540 NTAPI
6541 RxGetStringRegistryParameter(
6542     IN HANDLE KeyHandle,
6543     IN PCWSTR KeyName,
6544     OUT PUNICODE_STRING OutString,
6545     IN PUCHAR Buffer,
6546     IN ULONG BufferLength,
6547     IN BOOLEAN LogFailure)
6548 {
6549     NTSTATUS Status;
6550     ULONG ResultLength;
6551     UNICODE_STRING KeyString;
6552 
6553     PAGED_CODE();
6554 
6555     RtlInitUnicodeString(&KeyString, KeyName);
6556     Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength);
6557     OutString->Length = 0;
6558     OutString->Buffer = 0;
6559     if (!NT_SUCCESS(Status))
6560     {
6561         if (LogFailure)
6562         {
6563             RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status);
6564         }
6565 
6566         return Status;
6567     }
6568 
6569     OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
6570     OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL);
6571     OutString->MaximumLength = OutString->Length;
6572 
6573     return STATUS_SUCCESS;
6574 }
6575 
6576 /*
6577  * @implemented
6578  */
6579 PRDBSS_DEVICE_OBJECT
6580 RxGetTopDeviceObjectIfRdbssIrp(
6581     VOID)
6582 {
6583     PIRP TopLevelIrp;
6584     PRDBSS_DEVICE_OBJECT TopDevice = NULL;
6585 
6586     TopLevelIrp = IoGetTopLevelIrp();
6587     if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6588     {
6589         TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject;
6590     }
6591 
6592     return TopDevice;
6593 }
6594 
6595 /*
6596  * @implemented
6597  */
6598 PIRP
6599 RxGetTopIrpIfRdbssIrp(
6600     VOID)
6601 {
6602     PIRP Irp = NULL;
6603     PRX_TOPLEVELIRP_CONTEXT TopLevel;
6604 
6605     TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
6606     if (RxIsThisAnRdbssTopLevelContext(TopLevel))
6607     {
6608         Irp = TopLevel->Irp;
6609     }
6610 
6611     return Irp;
6612 }
6613 
6614 /*
6615  * @implemented
6616  */
6617 LUID
6618 RxGetUid(
6619     IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
6620 {
6621     LUID Luid;
6622     PACCESS_TOKEN Token;
6623 
6624     PAGED_CODE();
6625 
6626     Token = SeQuerySubjectContextToken(SubjectSecurityContext);
6627     SeQueryAuthenticationIdToken(Token, &Luid);
6628 
6629     return Luid;
6630 }
6631 
6632 VOID
6633 NTAPI
6634 RxIndicateChangeOfBufferingStateForSrvOpen(
6635     PMRX_SRV_CALL SrvCall,
6636     PMRX_SRV_OPEN SrvOpen,
6637     PVOID SrvOpenKey,
6638     PVOID Context)
6639 {
6640     UNIMPLEMENTED;
6641 }
6642 
6643 VOID
6644 NTAPI
6645 RxInitializeDebugSupport(
6646     VOID)
6647 {
6648     UNIMPLEMENTED;
6649 }
6650 
6651 /*
6652  * @implemented
6653  */
6654 VOID
6655 NTAPI
6656 RxInitializeDispatchVectors(
6657     PDRIVER_OBJECT DriverObject)
6658 {
6659     USHORT i;
6660 
6661     PAGED_CODE();
6662 
6663     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
6664     {
6665         DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
6666     }
6667 
6668     RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector;
6669     ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6670     ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6671 
6672     DriverObject->FastIoDispatch = &RxFastIoDispatch;
6673     RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch);
6674     RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
6675     RxFastIoDispatch.FastIoRead = RxFastIoRead;
6676     RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
6677     RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
6678     RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
6679     RxFastIoDispatch.FastIoLock = NULL;
6680     RxFastIoDispatch.FastIoUnlockSingle = NULL;
6681     RxFastIoDispatch.FastIoUnlockAll = NULL;
6682     RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
6683     RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
6684     RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
6685     RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
6686     RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
6687     RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
6688 
6689     RxInitializeTopLevelIrpPackage();
6690 
6691     RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite;
6692     RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite;
6693     RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead;
6694     RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
6695 
6696     RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire;
6697     RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease;
6698     RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire;
6699     RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;
6700 }
6701 
6702 NTSTATUS
6703 NTAPI
6704 RxInitializeLog(
6705     VOID)
6706 {
6707     UNIMPLEMENTED;
6708     return STATUS_NOT_IMPLEMENTED;
6709 }
6710 
6711 /*
6712  * @implemented
6713  */
6714 VOID
6715 RxInitializeMinirdrDispatchTable(
6716     IN PDRIVER_OBJECT DriverObject)
6717 {
6718     PAGED_CODE();
6719 }
6720 
6721 /*
6722  * @implemented
6723  */
6724 NTSTATUS
6725 NTAPI
6726 RxInitializeRegistrationStructures(
6727     VOID)
6728 {
6729     PAGED_CODE();
6730 
6731     ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
6732     RxData.NumberOfMinirdrsRegistered = 0;
6733     RxData.NumberOfMinirdrsStarted = 0;
6734     InitializeListHead(&RxData.RegisteredMiniRdrs);
6735 
6736     return STATUS_SUCCESS;
6737 }
6738 
6739 /*
6740  * @implemented
6741  */
6742 VOID
6743 NTAPI
6744 RxInitializeTopLevelIrpPackage(
6745     VOID)
6746 {
6747     KeInitializeSpinLock(&TopLevelIrpSpinLock);
6748     InitializeListHead(&TopLevelIrpAllocatedContextsList);
6749 }
6750 
6751 VOID
6752 NTAPI
6753 RxInitUnwind(
6754     PDRIVER_OBJECT DriverObject,
6755     USHORT State)
6756 {
6757     UNIMPLEMENTED;
6758 }
6759 
6760 /*
6761  * @implemented
6762  */
6763 BOOLEAN
6764 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6765     PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6766 {
6767     KIRQL OldIrql;
6768     PLIST_ENTRY NextEntry;
6769     BOOLEAN Found = FALSE;
6770     PRX_TOPLEVELIRP_CONTEXT ListContext;
6771 
6772     /* Browse all the allocated TLC to find ours */
6773     KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
6774     for (NextEntry = TopLevelIrpAllocatedContextsList.Flink;
6775          NextEntry != &TopLevelIrpAllocatedContextsList;
6776          NextEntry = NextEntry->Flink)
6777     {
6778         ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry);
6779         ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6780         ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6781 
6782         /* Found! */
6783         if (ListContext == TopLevelContext)
6784         {
6785             Found = TRUE;
6786             break;
6787         }
6788     }
6789     KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
6790 
6791     return Found;
6792 }
6793 
6794 /*
6795  * @implemented
6796  */
6797 BOOLEAN
6798 RxIsOkToPurgeFcb(
6799     PFCB Fcb)
6800 {
6801     PLIST_ENTRY Entry;
6802 
6803     /* No associated SRV_OPEN, it's OK to purge */
6804     if (IsListEmpty(&Fcb->SrvOpenList))
6805     {
6806         return TRUE;
6807     }
6808 
6809     /* Only allow to purge if all the associated SRV_OPEN
6810      * - have no outstanding opens ongoing
6811      * - have only read attribute set
6812      */
6813     for (Entry = Fcb->SrvOpenList.Flink;
6814          Entry != &Fcb->SrvOpenList;
6815          Entry = Entry->Flink)
6816     {
6817         PSRV_OPEN SrvOpen;
6818 
6819         SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
6820 
6821         /* Failing previous needs, don't allow purge */
6822         if (SrvOpen->UncleanFobxCount != 0 ||
6823             (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
6824         {
6825             return FALSE;
6826         }
6827     }
6828 
6829     /* All correct, allow purge */
6830     return TRUE;
6831 }
6832 
6833 /*
6834  * @implemented
6835  */
6836 BOOLEAN
6837 RxIsThisAnRdbssTopLevelContext(
6838     PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6839 {
6840     ULONG_PTR StackTop, StackBottom;
6841 
6842     /* Bail out for flags */
6843     if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP)
6844     {
6845         return FALSE;
6846     }
6847 
6848     /* Is our provided TLC allocated on stack? */
6849     IoGetStackLimits(&StackTop, &StackBottom);
6850     if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) &&
6851         (ULONG_PTR)TopLevelContext >= StackTop)
6852     {
6853         /* Yes, so check whether it's really a TLC by checking alignement & signature */
6854         if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)
6855         {
6856             return TRUE;
6857         }
6858 
6859         return FALSE;
6860     }
6861 
6862     /* No, use the helper function */
6863     return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);
6864 }
6865 
6866 /*
6867  * @implemented
6868  */
6869 BOOLEAN
6870 RxIsThisTheTopLevelIrp(
6871     IN PIRP Irp)
6872 {
6873     PIRP TopLevelIrp;
6874 
6875     /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6876     TopLevelIrp = IoGetTopLevelIrp();
6877     if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6878     {
6879         TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp;
6880     }
6881 
6882     return (TopLevelIrp == Irp);
6883 }
6884 
6885 NTSTATUS
6886 NTAPI
6887 RxLockOperationCompletion(
6888     IN PVOID Context,
6889     IN PIRP Irp)
6890 {
6891     UNIMPLEMENTED;
6892     return STATUS_NOT_IMPLEMENTED;
6893 }
6894 
6895 /*
6896  * @implemented
6897  */
6898 VOID
6899 NTAPI
6900 RxLogEventDirect(
6901     IN PRDBSS_DEVICE_OBJECT DeviceObject,
6902     IN PUNICODE_STRING OriginatorId,
6903     IN ULONG EventId,
6904     IN NTSTATUS Status,
6905     IN ULONG Line)
6906 {
6907     PUNICODE_STRING Originator = OriginatorId;
6908     LARGE_INTEGER LargeLine;
6909 
6910     /* Set optional parameters */
6911     LargeLine.QuadPart = Line;
6912     if (OriginatorId == NULL || OriginatorId->Length == 0)
6913     {
6914         Originator = (PUNICODE_STRING)&unknownId;
6915     }
6916 
6917     /* And log */
6918     RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);
6919 }
6920 
6921 VOID
6922 NTAPI
6923 RxLogEventWithAnnotation(
6924     IN PRDBSS_DEVICE_OBJECT DeviceObject,
6925     IN ULONG EventId,
6926     IN NTSTATUS Status,
6927     IN PVOID DataBuffer,
6928     IN USHORT DataBufferLength,
6929     IN PUNICODE_STRING Annotation,
6930     IN ULONG AnnotationCount)
6931 {
6932     UNIMPLEMENTED;
6933 }
6934 
6935 NTSTATUS
6936 NTAPI
6937 RxLowIoCompletion(
6938     PRX_CONTEXT RxContext)
6939 {
6940     UNIMPLEMENTED;
6941     return STATUS_NOT_IMPLEMENTED;
6942 }
6943 
6944 /*
6945  * @implemented
6946  */
6947 NTSTATUS
6948 NTAPI
6949 RxLowIoIoCtlShellCompletion(
6950     PRX_CONTEXT RxContext)
6951 {
6952     PIRP Irp;
6953     NTSTATUS Status;
6954 
6955     PAGED_CODE();
6956 
6957     DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
6958 
6959     Irp = RxContext->CurrentIrp;
6960     Status = RxContext->IoStatusBlock.Status;
6961 
6962     /* Set information and status */
6963     if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
6964     {
6965         Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
6966     }
6967 
6968     Irp->IoStatus.Status = Status;
6969 
6970     return Status;
6971 }
6972 
6973 NTSTATUS
6974 RxLowIoLockControlShell(
6975     IN PRX_CONTEXT RxContext)
6976 {
6977     UNIMPLEMENTED;
6978     return STATUS_NOT_IMPLEMENTED;
6979 }
6980 
6981 /*
6982  * @implemented
6983  */
6984 NTSTATUS
6985 NTAPI
6986 RxLowIoNotifyChangeDirectoryCompletion(
6987     PRX_CONTEXT RxContext)
6988 {
6989     PAGED_CODE();
6990 
6991     DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
6992 
6993     /* Just copy back the IO_STATUS to the IRP */
6994     RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status);
6995     RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
6996 
6997     return RxContext->IoStatusBlock.Status;
6998 }
6999 
7000 /*
7001  * @implemented
7002  */
7003 NTSTATUS
7004 RxLowIoReadShell(
7005     PRX_CONTEXT RxContext)
7006 {
7007     PFCB Fcb;
7008     NTSTATUS Status;
7009 
7010     PAGED_CODE();
7011 
7012     DPRINT("RxLowIoReadShell(%p)\n", RxContext);
7013 
7014     Fcb = (PFCB)RxContext->pFcb;
7015     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
7016     {
7017         return STATUS_MORE_PROCESSING_REQUIRED;
7018     }
7019 
7020     /* Always update stats for disks */
7021     if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7022     {
7023         ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7024     }
7025 
7026     /* And forward the read to the mini-rdr */
7027     Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion);
7028     DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
7029 
7030     return Status;
7031 }
7032 
7033 NTSTATUS
7034 NTAPI
7035 RxLowIoReadShellCompletion(
7036     PRX_CONTEXT RxContext)
7037 {
7038     PIRP Irp;
7039     PFCB Fcb;
7040     NTSTATUS Status;
7041     BOOLEAN PagingIo, IsPipe;
7042     PIO_STACK_LOCATION Stack;
7043     PLOWIO_CONTEXT LowIoContext;
7044 
7045     PAGED_CODE();
7046 
7047     DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
7048 
7049     Status = RxContext->IoStatusBlock.Status;
7050     DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7051 
7052     Irp = RxContext->CurrentIrp;
7053     PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7054 
7055     /* Set IRP information from the RX_CONTEXT status block */
7056     Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7057 
7058     /* Fixup status for paging file if nothing was read */
7059     if (PagingIo)
7060     {
7061         if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0)
7062         {
7063             Status = STATUS_END_OF_FILE;
7064         }
7065     }
7066 
7067     LowIoContext = &RxContext->LowIoContext;
7068     ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7069 
7070     /* Check broken cases that should never happen */
7071     Fcb = (PFCB)RxContext->pFcb;
7072     if (Status == STATUS_FILE_LOCK_CONFLICT)
7073     {
7074         if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED))
7075         {
7076             ASSERT(FALSE);
7077             return STATUS_RETRY;
7078         }
7079     }
7080     else if (Status == STATUS_SUCCESS)
7081     {
7082         if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
7083         {
7084             if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) ||
7085                 BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED))
7086             {
7087                 ASSERT(FALSE);
7088             }
7089         }
7090 
7091         if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
7092         {
7093             ASSERT(FALSE);
7094         }
7095     }
7096 
7097     /* Readahead should go through Cc and not finish here */
7098     ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
7099 
7100     /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7101     if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7102     {
7103         return Status;
7104     }
7105 
7106     Stack = RxContext->CurrentIrpSp;
7107     IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
7108     /* Release lock if required */
7109     if (PagingIo)
7110     {
7111         RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7112     }
7113     else
7114     {
7115         /* Set FastIo if read was a success */
7116         if (NT_SUCCESS(Status) && !IsPipe)
7117         {
7118             SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ);
7119         }
7120 
7121         if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7122         {
7123             RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue);
7124         }
7125         else
7126         {
7127             RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7128         }
7129     }
7130 
7131     if (IsPipe)
7132     {
7133         UNIMPLEMENTED;
7134     }
7135 
7136     /* Final sanity checks */
7137     ASSERT(Status != STATUS_RETRY);
7138     ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
7139     ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
7140 
7141     return Status;
7142 }
7143 
7144 /*
7145  * @implemented
7146  */
7147 NTSTATUS
7148 RxLowIoWriteShell(
7149     IN PRX_CONTEXT RxContext)
7150 {
7151     PFCB Fcb;
7152     NTSTATUS Status;
7153 
7154     PAGED_CODE();
7155 
7156     DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
7157 
7158     Fcb = (PFCB)RxContext->pFcb;
7159 
7160     ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7161            !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7162 
7163     /* Always update stats for disks */
7164     if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7165     {
7166         ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7167     }
7168 
7169     /* And forward the write to the mini-rdr */
7170     Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion);
7171     DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
7172 
7173     return Status;
7174 }
7175 
7176 NTSTATUS
7177 NTAPI
7178 RxLowIoWriteShellCompletion(
7179     PRX_CONTEXT RxContext)
7180 {
7181     PIRP Irp;
7182     PFCB Fcb;
7183     NTSTATUS Status;
7184     BOOLEAN PagingIo;
7185     PLOWIO_CONTEXT LowIoContext;
7186 
7187     PAGED_CODE();
7188 
7189     DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
7190 
7191     Status = RxContext->IoStatusBlock.Status;
7192     DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7193 
7194     Irp = RxContext->CurrentIrp;
7195 
7196     /* Set IRP information from the RX_CONTEXT status block */
7197     Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7198 
7199     LowIoContext = &RxContext->LowIoContext;
7200     ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7201 
7202     /* Perform a few sanity checks */
7203     Fcb = (PFCB)RxContext->pFcb;
7204     if (Status == STATUS_SUCCESS)
7205     {
7206         if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED))
7207         {
7208             ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7209                    !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7210         }
7211 
7212         ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED));
7213     }
7214 
7215     PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7216     if (Status != STATUS_SUCCESS && PagingIo)
7217     {
7218         DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status);
7219     }
7220 
7221     /* In case of async call, perform last bits not done in RxCommonWrite */
7222     if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7223     {
7224         PFILE_OBJECT FileObject;
7225         PIO_STACK_LOCATION Stack;
7226 
7227         /* We only succeed if we wrote what was asked for */
7228         if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7229         {
7230             ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount);
7231         }
7232 
7233         /* If write succeed, ,also update FILE_OBJECT flags */
7234         Stack = RxContext->CurrentIrpSp;
7235         FileObject = Stack->FileObject;
7236         if (!PagingIo)
7237         {
7238             SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
7239         }
7240 
7241         if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE))
7242         {
7243             SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
7244         }
7245 
7246         /* If VDL was extended, fix attributes */
7247         if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL))
7248         {
7249             LONGLONG LastOffset, FileSize;
7250 
7251             LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset +
7252                          Irp->IoStatus.Information;
7253             RxGetFileSizeWithLock(Fcb, &FileSize);
7254 
7255             if (FileSize < LastOffset)
7256             {
7257                 LastOffset = FileSize;
7258             }
7259 
7260             Fcb->Header.ValidDataLength.QuadPart = LastOffset;
7261         }
7262 
7263         /* One less outstanding write */
7264         if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7265         {
7266             PNON_PAGED_FCB NonPagedFcb;
7267 
7268             NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
7269             if (NonPagedFcb != NULL)
7270             {
7271                 if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites,
7272                                           -1, &RxStrucSupSpinLock) == 1)
7273                 {
7274                     KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
7275                 }
7276             }
7277         }
7278 
7279         /* Release paging resource if acquired */
7280         if (RxContext->FcbPagingIoResourceAcquired)
7281         {
7282             RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7283         }
7284 
7285         /* Resume blocked operations for pipes */
7286         if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7287         {
7288             RxResumeBlockedOperations_Serially(RxContext,
7289                                                &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue);
7290         }
7291         else
7292         {
7293             /* And release FCB only for files */
7294             if (RxContext->FcbResourceAcquired)
7295             {
7296                 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7297             }
7298         }
7299 
7300         /* Final sanity checks */
7301         ASSERT(Status != STATUS_RETRY);
7302         ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length));
7303         ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
7304 
7305         if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7306         {
7307             UNIMPLEMENTED;
7308         }
7309     }
7310 
7311     return Status;
7312 }
7313 
7314 /*
7315  * @implemented
7316  */
7317 NTSTATUS
7318 RxNotifyChangeDirectory(
7319     PRX_CONTEXT RxContext)
7320 {
7321     PIRP Irp;
7322     NTSTATUS Status;
7323     PIO_STACK_LOCATION Stack;
7324 
7325     PAGED_CODE();
7326 
7327     /* The IRP can abviously wait */
7328     SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
7329 
7330     /* Initialize its lowio */
7331     RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
7332 
7333     _SEH2_TRY
7334     {
7335         /* Lock user buffer */
7336         Stack = RxContext->CurrentIrpSp;
7337         RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
7338 
7339         /* Copy parameters from IO_STACK */
7340         RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE);
7341         RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter;
7342         RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
7343 
7344         /* If we have an associated MDL */
7345         Irp = RxContext->CurrentIrp;
7346         if (Irp->MdlAddress != NULL)
7347         {
7348             /* Then, call mini-rdr */
7349             RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
7350             if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL)
7351             {
7352                 Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion);
7353             }
7354             else
7355             {
7356                 Status = STATUS_INSUFFICIENT_RESOURCES;
7357             }
7358         }
7359         else
7360         {
7361             Status = STATUS_INVALID_PARAMETER;
7362         }
7363     }
7364     _SEH2_FINALLY
7365     {
7366         /* All correct */
7367     }
7368     _SEH2_END;
7369 
7370     return Status;
7371 }
7372 
7373 NTSTATUS
7374 RxPostStackOverflowRead (
7375     IN PRX_CONTEXT RxContext)
7376 {
7377     PAGED_CODE();
7378 
7379     UNIMPLEMENTED;
7380     return STATUS_NOT_IMPLEMENTED;
7381 }
7382 
7383 /*
7384  * @implemented
7385  */
7386 VOID
7387 RxpPrepareCreateContextForReuse(
7388     PRX_CONTEXT RxContext)
7389 {
7390     /* Reuse can only happen for open operations (STATUS_RETRY) */
7391     ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7392 
7393     /* Release the FCB if it was acquired */
7394     if (RxContext->Create.FcbAcquired)
7395     {
7396         RxReleaseFcb(RxContext, RxContext->pFcb);
7397         RxContext->Create.FcbAcquired = FALSE;
7398     }
7399 
7400     /* Free the canonical name */
7401     RxFreeCanonicalNameBuffer(RxContext);
7402 
7403     /* If we have a VNetRoot associated */
7404     if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL)
7405     {
7406         /* Remove our link and thus, dereference the VNetRoot */
7407         RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE);
7408         if (RxContext->Create.pVNetRoot != NULL)
7409         {
7410             RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE);
7411             RxContext->Create.pVNetRoot = NULL;
7412         }
7413         RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
7414     }
7415 
7416     DPRINT("RxContext: %p prepared for reuse\n", RxContext);
7417 }
7418 
7419 /*
7420  * @implemented
7421  */
7422 NTSTATUS
7423 RxpQueryInfoMiniRdr(
7424     PRX_CONTEXT RxContext,
7425     FILE_INFORMATION_CLASS FileInfoClass,
7426     PVOID Buffer)
7427 {
7428     PFCB Fcb;
7429     NTSTATUS Status;
7430 
7431     Fcb = (PFCB)RxContext->pFcb;
7432 
7433     /* Set the RX_CONTEXT */
7434     RxContext->Info.FileInformationClass = FileInfoClass;
7435     RxContext->Info.Buffer = Buffer;
7436 
7437     /* Pass down */
7438     MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
7439 
7440     return Status;
7441 }
7442 
7443 /*
7444  * @implemented
7445  */
7446 NTSTATUS
7447 RxPrefixClaim(
7448     IN PRX_CONTEXT RxContext)
7449 {
7450     PIRP Irp;
7451     NTSTATUS Status;
7452     NET_ROOT_TYPE NetRootType;
7453     UNICODE_STRING CanonicalName, FileName, NetRootName;
7454 
7455     PAGED_CODE();
7456 
7457     Irp = RxContext->CurrentIrp;
7458 
7459     /* This has to come from MUP */
7460     if (Irp->RequestorMode == UserMode)
7461     {
7462         return STATUS_INVALID_DEVICE_REQUEST;
7463     }
7464 
7465     if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL)
7466     {
7467         PQUERY_PATH_REQUEST QueryRequest;
7468 
7469         /* Get parameters */
7470         QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7471 
7472         /* Don't overflow allocation */
7473         if (QueryRequest->PathNameLength >= MAXUSHORT - 1)
7474         {
7475             return STATUS_INVALID_DEVICE_REQUEST;
7476         }
7477 
7478         /* Forcefully rewrite IRP MJ */
7479         RxContext->MajorFunction = IRP_MJ_CREATE;
7480 
7481         /* Fake canon name */
7482         RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
7483         if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
7484         {
7485             Status = STATUS_INSUFFICIENT_RESOURCES;
7486             goto Leave;
7487         }
7488 
7489         /* Copy the prefix to look for */
7490         RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength);
7491         RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength;
7492         RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
7493 
7494         /* Zero the create parameters */
7495         RtlZeroMemory(&RxContext->Create,
7496                       FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters));
7497         RxContext->Create.ThisIsATreeConnectOpen = TRUE;
7498         RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext;
7499     }
7500     else
7501     {
7502         /* If not devcontrol, it comes from open, name was already copied */
7503         ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7504         ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL);
7505     }
7506 
7507     /* Canonilize name */
7508     NetRootType = NET_ROOT_WILD;
7509     RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
7510     FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7511     FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7512     FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7513     NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7514     NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7515     NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7516     Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType);
7517     /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7518     if (NT_SUCCESS(Status))
7519     {
7520         Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName);
7521     }
7522     if (Status == STATUS_PENDING)
7523     {
7524         return Status;
7525     }
7526     /* Reply to MUP */
7527     if (NT_SUCCESS(Status))
7528     {
7529         PQUERY_PATH_RESPONSE QueryResponse;
7530 
7531         /* We accept the length that was canon (minus netroot) */
7532         QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7533         QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length;
7534     }
7535 
7536 Leave:
7537     /* If we reach that point with MJ, reset everything and make IRP being a device control */
7538     if (RxContext->MajorFunction == IRP_MJ_CREATE)
7539     {
7540         if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
7541         {
7542             RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
7543         }
7544 
7545         RxpPrepareCreateContextForReuse(RxContext);
7546 
7547         RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
7548     }
7549 
7550     return Status;
7551 }
7552 
7553 /*
7554  * @implemented
7555  */
7556 NTSTATUS
7557 NTAPI
7558 RxPrepareToReparseSymbolicLink(
7559     PRX_CONTEXT RxContext,
7560     BOOLEAN SymbolicLinkEmbeddedInOldPath,
7561     PUNICODE_STRING NewPath,
7562     BOOLEAN NewPathIsAbsolute,
7563     PBOOLEAN ReparseRequired)
7564 {
7565     PWSTR NewBuffer;
7566     USHORT NewLength;
7567     PFILE_OBJECT FileObject;
7568 
7569     /* Assume no reparse is required first */
7570     *ReparseRequired = FALSE;
7571 
7572     /* Only supported for IRP_MJ_CREATE */
7573     if (RxContext->MajorFunction != IRP_MJ_CREATE)
7574     {
7575         return STATUS_INVALID_PARAMETER;
7576     }
7577 
7578     /* If symbolic link is not embedded, and DELETE is specified, fail */
7579     if (!SymbolicLinkEmbeddedInOldPath)
7580     {
7581         /* Excepted if DELETE is the only flag specified, then, open has to succeed
7582          * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7583          */
7584         if (BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, DELETE) &&
7585             BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, ~DELETE))
7586         {
7587             return STATUS_ACCESS_DENIED;
7588         }
7589     }
7590 
7591     /* At that point, assume reparse will be required */
7592     *ReparseRequired = TRUE;
7593 
7594     /* If new path isn't absolute, it's up to us to make it absolute */
7595     if (!NewPathIsAbsolute)
7596     {
7597         /* The prefix will be \Device\Mup */
7598         NewLength = NewPath->Length + (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL));
7599         NewBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, NewLength,
7600                                           RX_MISC_POOLTAG);
7601         if (NewBuffer == NULL)
7602         {
7603             return STATUS_INSUFFICIENT_RESOURCES;
7604         }
7605 
7606         /* Copy data for the new path */
7607         RtlMoveMemory(NewBuffer, L"\\Device\\Mup", (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL)));
7608         RtlMoveMemory(Add2Ptr(NewBuffer, (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))),
7609                       NewPath->Buffer, NewPath->Length);
7610     }
7611     /* Otherwise, use caller path as it */
7612     else
7613     {
7614         NewLength = NewPath->Length;
7615         NewBuffer = NewPath->Buffer;
7616     }
7617 
7618     /* Get the FILE_OBJECT we'll modify */
7619     FileObject = RxContext->CurrentIrpSp->FileObject;
7620 
7621     /* Free old path first */
7622     ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
7623     /* And setup new one */
7624     FileObject->FileName.Length = NewLength;
7625     FileObject->FileName.MaximumLength = NewLength;
7626     FileObject->FileName.Buffer = NewBuffer;
7627 
7628     /* And set reparse flag */
7629     SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE);
7630 
7631     /* Done! */
7632     return STATUS_SUCCESS;
7633 }
7634 
7635 /*
7636  * @implemented
7637  */
7638 VOID
7639 RxPrePostIrp(
7640     IN PVOID Context,
7641     IN PIRP Irp)
7642 {
7643     LOCK_OPERATION Lock;
7644     PIO_STACK_LOCATION Stack;
7645     PRX_CONTEXT RxContext = Context;
7646 
7647     /* NULL IRP is no option */
7648     if (Irp == NULL)
7649     {
7650         return;
7651     }
7652 
7653     /* Check whether preparation was really needed */
7654     if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
7655     {
7656         return;
7657     }
7658     /* Mark the context as prepared */
7659     SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
7660 
7661     /* Just lock the user buffer, with the correct length, depending on the MJ */
7662     Lock = IoReadAccess;
7663     Stack = RxContext->CurrentIrpSp;
7664     if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
7665     {
7666         if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
7667         {
7668             if (RxContext->MajorFunction == IRP_MJ_READ)
7669             {
7670                 Lock = IoWriteAccess;
7671             }
7672             RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length);
7673         }
7674     }
7675     else
7676     {
7677         if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) ||
7678             RxContext->MajorFunction == IRP_MJ_QUERY_EA)
7679         {
7680             Lock = IoWriteAccess;
7681             RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length);
7682         }
7683         else if (RxContext->MajorFunction == IRP_MJ_SET_EA)
7684         {
7685             RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length);
7686         }
7687     }
7688 
7689     /* As it will be posted (async), mark the IRP pending */
7690     IoMarkIrpPending(Irp);
7691 }
7692 
7693 /*
7694  * @implemented
7695  */
7696 NTSTATUS
7697 RxpSetInfoMiniRdr(
7698     PRX_CONTEXT RxContext,
7699     FILE_INFORMATION_CLASS Class)
7700 {
7701     PFCB Fcb;
7702     NTSTATUS Status;
7703 
7704     /* Initialize parameters in RX_CONTEXT */
7705     RxContext->Info.FileInformationClass = Class;
7706     RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
7707     RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
7708 
7709     /* And call mini-rdr */
7710     Fcb = (PFCB)RxContext->pFcb;
7711     MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
7712 
7713     return Status;
7714 }
7715 
7716 VOID
7717 NTAPI
7718 RxpUnregisterMinirdr(
7719     IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
7720 {
7721     UNIMPLEMENTED;
7722 }
7723 
7724 /*
7725  * @implemented
7726  */
7727 VOID
7728 RxPurgeNetFcb(
7729     PFCB Fcb,
7730     PRX_CONTEXT LocalContext)
7731 {
7732     NTSTATUS Status;
7733 
7734     PAGED_CODE();
7735 
7736     /* First, flush */
7737     MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
7738 
7739     /* And force close */
7740     RxReleaseFcb(NULL, Fcb);
7741     MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
7742     Status = RxAcquireExclusiveFcb(NULL, Fcb);
7743     ASSERT(Status == STATUS_SUCCESS);
7744 }
7745 
7746 NTSTATUS
7747 RxQueryAlternateNameInfo(
7748     PRX_CONTEXT RxContext,
7749     PFILE_NAME_INFORMATION AltNameInfo)
7750 {
7751     UNIMPLEMENTED;
7752     return STATUS_NOT_IMPLEMENTED;
7753 }
7754 
7755 /*
7756  * @implemented
7757  */
7758 NTSTATUS
7759 RxQueryBasicInfo(
7760     PRX_CONTEXT RxContext,
7761     PFILE_BASIC_INFORMATION BasicInfo)
7762 {
7763     PAGED_CODE();
7764 
7765     DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
7766 
7767     /* Simply zero and forward to mini-rdr */
7768     RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION));
7769     return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);
7770 }
7771 
7772 NTSTATUS
7773 RxQueryCompressedInfo(
7774     PRX_CONTEXT RxContext,
7775     PFILE_COMPRESSION_INFORMATION CompressionInfo)
7776 {
7777     UNIMPLEMENTED;
7778     return STATUS_NOT_IMPLEMENTED;
7779 }
7780 
7781 /*
7782  * @implemented
7783  */
7784 NTSTATUS
7785 RxQueryDirectory(
7786     PRX_CONTEXT RxContext)
7787 {
7788     PIRP Irp;
7789     PFCB Fcb;
7790     PFOBX Fobx;
7791     UCHAR Flags;
7792     NTSTATUS Status;
7793     BOOLEAN LockNotGranted;
7794     ULONG Length, FileIndex;
7795     PUNICODE_STRING FileName;
7796     PIO_STACK_LOCATION Stack;
7797     FILE_INFORMATION_CLASS FileInfoClass;
7798 
7799     PAGED_CODE();
7800 
7801     DPRINT("RxQueryDirectory(%p)\n", RxContext);
7802 
7803     /* Get parameters */
7804     Stack = RxContext->CurrentIrpSp;
7805     Length = Stack->Parameters.QueryDirectory.Length;
7806     FileName = Stack->Parameters.QueryDirectory.FileName;
7807     FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass;
7808     DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7809            FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length,
7810            FileName, FileInfoClass);
7811 
7812     Irp = RxContext->CurrentIrp;
7813     Flags = Stack->Flags;
7814     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
7815     DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
7816 
7817     if (FileName != NULL)
7818     {
7819         DPRINT("FileName: %wZ\n", FileName);
7820     }
7821 
7822     /* No FOBX: not a standard file/directory */
7823     Fobx = (PFOBX)RxContext->pFobx;
7824     if (Fobx == NULL)
7825     {
7826         return STATUS_OBJECT_NAME_INVALID;
7827     }
7828 
7829     /* We can only deal with a disk */
7830     Fcb = (PFCB)RxContext->pFcb;
7831     if (Fcb->pNetRoot->Type != NET_ROOT_DISK)
7832     {
7833         DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type);
7834         return STATUS_INVALID_DEVICE_REQUEST;
7835     }
7836 
7837     /* Setup RX_CONTEXT related fields */
7838     RxContext->QueryDirectory.FileIndex = FileIndex;
7839     RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN);
7840     RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY);
7841     RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED);
7842     RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7843 
7844     /* We don't support (yet?) a specific index being set */
7845     if (RxContext->QueryDirectory.IndexSpecified)
7846     {
7847         return STATUS_NOT_IMPLEMENTED;
7848     }
7849 
7850     /* Try to lock FCB */
7851     LockNotGranted = TRUE;
7852     if (RxContext->QueryDirectory.InitialQuery)
7853     {
7854         Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7855         if (Status != STATUS_LOCK_NOT_GRANTED)
7856         {
7857             if (!NT_SUCCESS(Status))
7858             {
7859                 return Status;
7860             }
7861 
7862             if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7863             {
7864                 RxContext->QueryDirectory.InitialQuery = FALSE;
7865                 RxConvertToSharedFcb(RxContext, Fcb);
7866             }
7867 
7868             LockNotGranted = FALSE;
7869         }
7870     }
7871     else
7872     {
7873         Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7874         if (Status != STATUS_LOCK_NOT_GRANTED)
7875         {
7876             if (!NT_SUCCESS(Status))
7877             {
7878                 return Status;
7879             }
7880 
7881             LockNotGranted = FALSE;
7882         }
7883     }
7884 
7885     /* If it failed, post request */
7886     if (LockNotGranted)
7887     {
7888         return RxFsdPostRequest(RxContext);
7889     }
7890 
7891     /* This cannot be done on a orphaned directory */
7892     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
7893     {
7894         RxReleaseFcb(RxContext, Fcb);
7895         return STATUS_FILE_CLOSED;
7896     }
7897 
7898     _SEH2_TRY
7899     {
7900         /* Set index */
7901         if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan)
7902         {
7903             RxContext->QueryDirectory.FileIndex = 0;
7904         }
7905 
7906         /* Assume success */
7907         Status = STATUS_SUCCESS;
7908         /* If initial query, prepare FOBX */
7909         if (RxContext->QueryDirectory.InitialQuery)
7910         {
7911             /* We cannot have a template already! */
7912             ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
7913 
7914             /* If we have a file name and a correct one, duplicate it in the FOBX */
7915             if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL &&
7916                 (FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') &&
7917                 (FileName->Length != 12 * sizeof(WCHAR) ||
7918                  RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR)))
7919             {
7920                 Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
7921 
7922                 Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
7923                 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7924                 {
7925                     /* UNICODE_STRING; length has to be even */
7926                     if ((FileName->Length & 1) != 0)
7927                     {
7928                         Status = STATUS_INVALID_PARAMETER;
7929                         RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
7930                     }
7931                     else
7932                     {
7933                         Fobx->UnicodeQueryTemplate.Length = FileName->Length;
7934                         Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
7935                         RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
7936 
7937                         SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE);
7938                     }
7939                 }
7940                 else
7941                 {
7942                     Status = STATUS_INSUFFICIENT_RESOURCES;
7943                 }
7944             }
7945             /* No name specified, or a match all wildcard? Match everything */
7946             else
7947             {
7948                 Fobx->ContainsWildCards = TRUE;
7949 
7950                 Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate;
7951                 Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
7952                 Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
7953 
7954                 SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7955             }
7956 
7957             /* No need for exclusive any longer */
7958             if (NT_SUCCESS(Status))
7959             {
7960                 RxConvertToSharedFcb(RxContext, Fcb);
7961             }
7962         }
7963 
7964         /* Lock user buffer and forward to mini-rdr */
7965         if (NT_SUCCESS(Status))
7966         {
7967             RxLockUserBuffer(RxContext, IoModifyAccess, Length);
7968             RxContext->Info.FileInformationClass = FileInfoClass;
7969             RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext);
7970             RxContext->Info.Length = Length;
7971 
7972             if (RxContext->Info.Buffer != NULL)
7973             {
7974                 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext));
7975             }
7976 
7977             /* Post if mini-rdr asks to */
7978             if (RxContext->PostRequest)
7979             {
7980                 RxFsdPostRequest(RxContext);
7981             }
7982             else
7983             {
7984                 Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining;
7985             }
7986         }
7987     }
7988     _SEH2_FINALLY
7989     {
7990         RxReleaseFcb(RxContext, Fcb);
7991     }
7992     _SEH2_END;
7993 
7994     return Status;
7995 }
7996 
7997 NTSTATUS
7998 RxQueryEaInfo(
7999     PRX_CONTEXT RxContext,
8000     PFILE_EA_INFORMATION EaInfo)
8001 {
8002     UNIMPLEMENTED;
8003     return STATUS_NOT_IMPLEMENTED;
8004 }
8005 
8006 NTSTATUS
8007 RxQueryInternalInfo(
8008     PRX_CONTEXT RxContext,
8009     PFILE_INTERNAL_INFORMATION InternalInfo)
8010 {
8011     UNIMPLEMENTED;
8012     return STATUS_NOT_IMPLEMENTED;
8013 }
8014 
8015 NTSTATUS
8016 RxQueryNameInfo(
8017     PRX_CONTEXT RxContext,
8018     PFILE_NAME_INFORMATION NameInfo)
8019 {
8020     UNIMPLEMENTED;
8021     return STATUS_NOT_IMPLEMENTED;
8022 }
8023 
8024 NTSTATUS
8025 RxQueryPipeInfo(
8026     PRX_CONTEXT RxContext,
8027     PFILE_PIPE_INFORMATION PipeInfo)
8028 {
8029     UNIMPLEMENTED;
8030     return STATUS_NOT_IMPLEMENTED;
8031 }
8032 
8033 NTSTATUS
8034 RxQueryPositionInfo(
8035     PRX_CONTEXT RxContext,
8036     PFILE_POSITION_INFORMATION PositionInfo)
8037 {
8038     UNIMPLEMENTED;
8039     return STATUS_NOT_IMPLEMENTED;
8040 }
8041 
8042 /*
8043  * @implemented
8044  */
8045 NTSTATUS
8046 RxQueryStandardInfo(
8047     PRX_CONTEXT RxContext,
8048     PFILE_STANDARD_INFORMATION StandardInfo)
8049 {
8050     PFCB Fcb;
8051     PFOBX Fobx;
8052     NTSTATUS Status;
8053 
8054     PAGED_CODE();
8055 
8056     DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
8057 
8058     /* Zero output buffer */
8059     RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
8060 
8061     Fcb = (PFCB)RxContext->pFcb;
8062     Fobx = (PFOBX)RxContext->pFobx;
8063     /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8064     if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
8065         BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
8066     {
8067         return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
8068     }
8069 
8070     /* Otherwise, fill what we can already */
8071     Status = STATUS_SUCCESS;
8072     StandardInfo->NumberOfLinks = Fcb->NumberOfLinks;
8073     StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8074     StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
8075     if (StandardInfo->NumberOfLinks == 0)
8076     {
8077         StandardInfo->NumberOfLinks = 1;
8078     }
8079 
8080     if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
8081     {
8082         StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
8083         RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart);
8084     }
8085 
8086     /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8087     if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED))
8088     {
8089         Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
8090     }
8091     else
8092     {
8093         RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION);
8094     }
8095 
8096     return Status;
8097 }
8098 
8099 /*
8100  * @implemented
8101  */
8102 VOID
8103 NTAPI
8104 RxReadRegistryParameters(
8105     VOID)
8106 {
8107     NTSTATUS Status;
8108     HANDLE KeyHandle;
8109     ULONG ResultLength;
8110     UCHAR Buffer[0x40];
8111     UNICODE_STRING KeyName, ParamName;
8112     OBJECT_ATTRIBUTES ObjectAttributes;
8113     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
8114 
8115     PAGED_CODE();
8116 
8117     RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8118     InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
8119     Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
8120     if (!NT_SUCCESS(Status))
8121     {
8122         return;
8123     }
8124 
8125     PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
8126     RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles");
8127     Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8128     if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8129     {
8130         DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
8131     }
8132 
8133     RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
8134     Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8135     if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8136     {
8137         ULONG Granularity = *(PULONG)PartialInfo->Data;
8138 
8139         if (Granularity > 16)
8140         {
8141             Granularity = 16;
8142         }
8143 
8144         ReadAheadGranularity = Granularity << PAGE_SHIFT;
8145     }
8146 
8147     RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup");
8148     Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8149     if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8150     {
8151         DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
8152     }
8153 
8154     ZwClose(KeyHandle);
8155 }
8156 
8157 /*
8158  * @implemented
8159  */
8160 NTSTATUS
8161 NTAPI
8162 RxRegisterMinirdr(
8163     OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
8164     IN OUT PDRIVER_OBJECT DriverObject,
8165     IN PMINIRDR_DISPATCH MrdrDispatch,
8166     IN ULONG Controls,
8167     IN PUNICODE_STRING DeviceName,
8168     IN ULONG DeviceExtensionSize,
8169     IN DEVICE_TYPE DeviceType,
8170     IN ULONG DeviceCharacteristics)
8171 {
8172     NTSTATUS Status;
8173     PRDBSS_DEVICE_OBJECT RDBSSDevice;
8174 
8175     PAGED_CODE();
8176 
8177     if (!DeviceObject)
8178     {
8179         return STATUS_INVALID_PARAMETER;
8180     }
8181 
8182     /* Create device object with provided parameters */
8183     Status = IoCreateDevice(DriverObject,
8184                             DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT),
8185                             DeviceName,
8186                             DeviceType,
8187                             DeviceCharacteristics,
8188                             FALSE,
8189                             (PDEVICE_OBJECT *)&RDBSSDevice);
8190     if (!NT_SUCCESS(Status))
8191     {
8192         return Status;
8193     }
8194 
8195     if (!RxData.DriverObject)
8196     {
8197         return STATUS_UNSUCCESSFUL;
8198     }
8199 
8200     /* Initialize our DO extension */
8201     RDBSSDevice->RDBSSDeviceObject = NULL;
8202     ++RxFileSystemDeviceObject->ReferenceCount;
8203     *DeviceObject = RDBSSDevice;
8204     RDBSSDevice->RdbssExports = &RxExports;
8205     RDBSSDevice->Dispatch = MrdrDispatch;
8206     RDBSSDevice->RegistrationControls = Controls;
8207     RDBSSDevice->DeviceName = *DeviceName;
8208     RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
8209     RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
8210     InitializeListHead(&RDBSSDevice->OverflowQueue[0]);
8211     InitializeListHead(&RDBSSDevice->OverflowQueue[1]);
8212     InitializeListHead(&RDBSSDevice->OverflowQueue[2]);
8213     KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock);
8214     RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
8215 
8216     DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
8217 
8218     ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex);
8219     InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks);
8220     ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
8221 
8222     /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8223     if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH))
8224     {
8225         RxInitializeMinirdrDispatchTable(DriverObject);
8226     }
8227 
8228     /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8229     if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER))
8230     {
8231         LARGE_INTEGER ScavengerTimeLimit;
8232 
8233         RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject;
8234         RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
8235         RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
8236         ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
8237         RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
8238         RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
8239     }
8240 
8241     RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
8242 
8243     return STATUS_SUCCESS;
8244 }
8245 
8246 /*
8247  * @implemented
8248  */
8249 VOID
8250 RxRemoveFromTopLevelIrpAllocatedContextsList(
8251     PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
8252 {
8253     KIRQL OldIrql;
8254 
8255     /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8256     ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
8257     ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
8258 
8259     KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
8260     RemoveEntryList(&TopLevelContext->ListEntry);
8261     KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
8262 }
8263 
8264 /*
8265  * @implemented
8266  */
8267 PRX_CONTEXT
8268 RxRemoveOverflowEntry(
8269     PRDBSS_DEVICE_OBJECT DeviceObject,
8270     WORK_QUEUE_TYPE Queue)
8271 {
8272     KIRQL OldIrql;
8273     PRX_CONTEXT Context;
8274 
8275     KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql);
8276     if (DeviceObject->OverflowQueueCount[Queue] <= 0)
8277     {
8278         /* No entries left, nothing to return */
8279         InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]);
8280         Context = NULL;
8281     }
8282     else
8283     {
8284         PLIST_ENTRY Entry;
8285 
8286         /* Decrement count */
8287         --DeviceObject->OverflowQueueCount[Queue];
8288 
8289         /* Return head */
8290         Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]);
8291         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry);
8292         ClearFlag(Context->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
8293         Context->OverflowListEntry.Flink = NULL;
8294     }
8295     KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
8296 
8297     return Context;
8298 }
8299 
8300 #if DBG
8301 /*
8302  * @implemented
8303  */
8304 VOID
8305 RxRemoveShareAccess(
8306     _Inout_ PFILE_OBJECT FileObject,
8307     _Inout_ PSHARE_ACCESS ShareAccess,
8308     _In_ PSZ where,
8309     _In_ PSZ wherelogtag)
8310 {
8311     PAGED_CODE();
8312 
8313     RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8314     IoRemoveShareAccess(FileObject, ShareAccess);
8315     RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8316 }
8317 #endif
8318 
8319 /*
8320  * @implemented
8321  */
8322 VOID
8323 RxRemoveShareAccessPerSrvOpens(
8324     IN OUT PSRV_OPEN SrvOpen)
8325 {
8326     ACCESS_MASK DesiredAccess;
8327     BOOLEAN ReadAccess;
8328     BOOLEAN WriteAccess;
8329     BOOLEAN DeleteAccess;
8330 
8331     PAGED_CODE();
8332 
8333     /* Get access that were granted to SRV_OPEN */
8334     DesiredAccess = SrvOpen->DesiredAccess;
8335     ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
8336     WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
8337     DeleteAccess = (DesiredAccess & DELETE) != 0;
8338 
8339     /* If any, drop them */
8340     if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
8341     {
8342         BOOLEAN SharedRead;
8343         BOOLEAN SharedWrite;
8344         BOOLEAN SharedDelete;
8345         ULONG DesiredShareAccess;
8346         PSHARE_ACCESS ShareAccess;
8347 
8348         ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
8349         DesiredShareAccess = SrvOpen->ShareAccess;
8350 
8351         ShareAccess->Readers -= ReadAccess;
8352         ShareAccess->Writers -= WriteAccess;
8353         ShareAccess->Deleters -= DeleteAccess;
8354 
8355         ShareAccess->OpenCount--;
8356 
8357         SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
8358         SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
8359         SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
8360         ShareAccess->SharedRead -= SharedRead;
8361         ShareAccess->SharedWrite -= SharedWrite;
8362         ShareAccess->SharedDelete -= SharedDelete;
8363     }
8364 }
8365 
8366 NTSTATUS
8367 RxSearchForCollapsibleOpen(
8368     PRX_CONTEXT RxContext,
8369     ACCESS_MASK DesiredAccess,
8370     ULONG ShareAccess)
8371 {
8372     PFCB Fcb;
8373     NTSTATUS Status;
8374     PLIST_ENTRY ListEntry;
8375     BOOLEAN ShouldTry, Purged, Scavenged;
8376 
8377     PAGED_CODE();
8378 
8379     DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
8380 
8381     Fcb = (PFCB)RxContext->pFcb;
8382 
8383     /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8384     if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
8385     {
8386         ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8387 
8388         RxScavengeRelatedFobxs(Fcb);
8389         RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8390 
8391         return STATUS_NOT_FOUND;
8392     }
8393 
8394     /* If basic open, ask the mini-rdr if we should try to collapse */
8395     if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN ||
8396         RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF)
8397     {
8398         ShouldTry = TRUE;
8399 
8400         if (Fcb->MRxDispatch != NULL)
8401         {
8402             ASSERT(RxContext->pRelevantSrvOpen == NULL);
8403             ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8404 
8405             ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext));
8406         }
8407     }
8408     else
8409     {
8410         ShouldTry = FALSE;
8411     }
8412 
8413     if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE))
8414     {
8415         ShouldTry = FALSE;
8416     }
8417 
8418     /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8419     if (!ShouldTry)
8420     {
8421         if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess)))
8422         {
8423             return STATUS_NOT_FOUND;
8424         }
8425 
8426         ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8427 
8428         RxScavengeRelatedFobxs(Fcb);
8429         RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8430 
8431         return STATUS_NOT_FOUND;
8432     }
8433 
8434     /* Only collapse for matching NET_ROOT & disks */
8435     if (Fcb->pNetRoot != RxContext->Create.pNetRoot ||
8436         Fcb->pNetRoot->Type != NET_ROOT_DISK)
8437     {
8438         return STATUS_NOT_FOUND;
8439     }
8440 
8441     Purged = FALSE;
8442     Scavenged = FALSE;
8443     Status = STATUS_NOT_FOUND;
8444 TryAgain:
8445     /* Browse all our SRV_OPEN to find the matching one */
8446     for (ListEntry = Fcb->SrvOpenList.Flink;
8447          ListEntry != &Fcb->SrvOpenList;
8448          ListEntry = ListEntry->Flink)
8449     {
8450         PSRV_OPEN SrvOpen;
8451 
8452         SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
8453         /* Not the same VNET_ROOT, move to the next one */
8454         if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8455         {
8456             RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8457             continue;
8458         }
8459 
8460         /* Is there a sharing violation? */
8461         if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess ||
8462             BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED)))
8463         {
8464             if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8465             {
8466                 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8467                 continue;
8468             }
8469 
8470             /* Check against the SRV_OPEN */
8471             Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess);
8472             if (!NT_SUCCESS(Status))
8473             {
8474                 break;
8475             }
8476         }
8477         else
8478         {
8479             /* Don't allow collaspse for reparse point opening */
8480             if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT))
8481             {
8482                 Purged = TRUE;
8483                 Scavenged = TRUE;
8484                 Status = STATUS_NOT_FOUND;
8485                 break;
8486             }
8487 
8488             /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8489             if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY))
8490             {
8491                 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
8492 
8493                 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8494                 if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)))
8495                 {
8496                     /* Is close delayed - great reuse*/
8497                     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
8498                     {
8499                         DPRINT("Delayed close successfull, reusing %p\n", SrvOpen);
8500                         InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
8501                         ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
8502                     }
8503 
8504                     return STATUS_SUCCESS;
8505                 }
8506 
8507                 Status = STATUS_NOT_FOUND;
8508                 break;
8509             }
8510         }
8511     }
8512     /* We browse the whole list and didn't find any matching? NOT_FOUND */
8513     if (ListEntry == &Fcb->SrvOpenList)
8514     {
8515         Status = STATUS_NOT_FOUND;
8516     }
8517 
8518     /* Only required access: read attributes? Don't reuse */
8519     if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES)
8520     {
8521         return STATUS_NOT_FOUND;
8522     }
8523 
8524     /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8525     if (!Scavenged)
8526     {
8527         ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8528         Scavenged = TRUE;
8529         RxScavengeRelatedFobxs(Fcb);
8530         goto TryAgain;
8531     }
8532 
8533     /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8534     if (!Purged && RxIsOkToPurgeFcb(Fcb))
8535     {
8536         RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8537         Purged = TRUE;
8538         goto TryAgain;
8539     }
8540 
8541     /* If sharing violation, keep track of it */
8542     if (Status == STATUS_SHARING_VIOLATION)
8543     {
8544         RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8545     }
8546 
8547     DPRINT("Status: %x\n", Status);
8548     return Status;
8549 }
8550 
8551 NTSTATUS
8552 RxSetAllocationInfo(
8553     PRX_CONTEXT RxContext)
8554 {
8555     UNIMPLEMENTED;
8556     return STATUS_NOT_IMPLEMENTED;
8557 }
8558 
8559 /*
8560  * @implemented
8561  */
8562 NTSTATUS
8563 RxSetBasicInfo(
8564     PRX_CONTEXT RxContext)
8565 {
8566     NTSTATUS Status;
8567 
8568     PAGED_CODE();
8569 
8570 #define FILE_ATTRIBUTE_VOLUME 0x8
8571 #define VALID_FILE_ATTRIBUTES (                                   \
8572     FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |             \
8573     FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME |               \
8574     FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE |              \
8575     FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE |       \
8576     FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED |    \
8577     FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8578     FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8579 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8580 
8581     /* First of all, call the mini-rdr */
8582     Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation);
8583     /* If it succeed, perform last bits */
8584     if (NT_SUCCESS(Status))
8585     {
8586         PIRP Irp;
8587         PFCB Fcb;
8588         PFOBX Fobx;
8589         PFILE_OBJECT FileObject;
8590         ULONG Attributes, CleanAttr;
8591         PFILE_BASIC_INFORMATION BasicInfo;
8592 
8593         Fcb = (PFCB)RxContext->pFcb;
8594         Fobx = (PFOBX)RxContext->pFobx;
8595         Irp = RxContext->CurrentIrp;
8596         BasicInfo = Irp->AssociatedIrp.SystemBuffer;
8597         FileObject = RxContext->CurrentIrpSp->FileObject;
8598 
8599         /* If caller provided flags, handle the change */
8600         Attributes = BasicInfo->FileAttributes;
8601         if (Attributes != 0)
8602         {
8603             /* Clean our flags first, with only stuff we support */
8604             if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
8605             {
8606                 CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY;
8607             }
8608             else
8609             {
8610                 CleanAttr = Attributes & VALID_FILE_ATTRIBUTES;
8611             }
8612 
8613             /* Handle the temporary mark (set/unset depending on caller) */
8614             if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY))
8615             {
8616                 SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8617                 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8618             }
8619             else
8620             {
8621                 ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8622                 ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8623             }
8624 
8625             /* And set new attributes */
8626             Fcb->Attributes = CleanAttr;
8627         }
8628 
8629         /* If caller provided a creation time, set it */
8630         if (BasicInfo->CreationTime.QuadPart != 0LL)
8631         {
8632             Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
8633             SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION);
8634         }
8635 
8636         /* If caller provided a last access time, set it */
8637         if (BasicInfo->LastAccessTime.QuadPart != 0LL)
8638         {
8639             Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
8640             SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS);
8641         }
8642 
8643         /* If caller provided a last write time, set it */
8644         if (BasicInfo->LastWriteTime.QuadPart != 0LL)
8645         {
8646             Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
8647             SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
8648         }
8649 
8650         /* If caller provided a last change time, set it */
8651         if (BasicInfo->ChangeTime.QuadPart != 0LL)
8652         {
8653             Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
8654             SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
8655         }
8656     }
8657 
8658     /* Done */
8659     return Status;
8660 }
8661 
8662 /*
8663  * @implemented
8664  */
8665 NTSTATUS
8666 RxSetDispositionInfo(
8667     PRX_CONTEXT RxContext)
8668 {
8669     NTSTATUS Status;
8670 
8671     PAGED_CODE();
8672 
8673     /* First, make the mini-rdr work! */
8674     Status = RxpSetInfoMiniRdr(RxContext, FileDispositionInformation);
8675     /* If it succeed, we'll keep track of the change */
8676     if (NT_SUCCESS(Status))
8677     {
8678         PFCB Fcb;
8679         PFILE_OBJECT FileObject;
8680         PFILE_DISPOSITION_INFORMATION FileDispo;
8681 
8682         Fcb = (PFCB)RxContext->pFcb;
8683         FileObject = RxContext->CurrentIrpSp->FileObject;
8684         FileDispo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
8685         /* Caller asks for deletion: mark as delete on close */
8686         if (FileDispo->DeleteFile)
8687         {
8688             SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8689             FileObject->DeletePending = TRUE;
8690         }
8691         /* Otherwise, clear it */
8692         else
8693         {
8694             ClearFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8695             FileObject->DeletePending = FALSE;
8696         }
8697 
8698         /* Sanitize output */
8699         Status = STATUS_SUCCESS;
8700     }
8701 
8702     return Status;
8703 }
8704 
8705 NTSTATUS
8706 RxSetEndOfFileInfo(
8707     PRX_CONTEXT RxContext)
8708 {
8709     UNIMPLEMENTED;
8710     return STATUS_NOT_IMPLEMENTED;
8711 }
8712 
8713 NTSTATUS
8714 RxSetPipeInfo(
8715     PRX_CONTEXT RxContext)
8716 {
8717     UNIMPLEMENTED;
8718     return STATUS_NOT_IMPLEMENTED;
8719 }
8720 
8721 NTSTATUS
8722 RxSetPositionInfo(
8723     PRX_CONTEXT RxContext)
8724 {
8725     UNIMPLEMENTED;
8726     return STATUS_NOT_IMPLEMENTED;
8727 }
8728 
8729 /*
8730  * @implemented
8731  */
8732 NTSTATUS
8733 RxSetRenameInfo(
8734     PRX_CONTEXT RxContext)
8735 {
8736     ULONG Length;
8737     NTSTATUS Status;
8738     PFCB RenameFcb, Fcb;
8739     PIO_STACK_LOCATION Stack;
8740     PFILE_RENAME_INFORMATION RenameInfo, UserInfo;
8741 
8742     PAGED_CODE();
8743 
8744     DPRINT("RxSetRenameInfo(%p)\n", RxContext);
8745 
8746     Stack = RxContext->CurrentIrpSp;
8747     DPRINT("FO: %p, Replace: %d\n", Stack->Parameters.SetFile.FileObject, Stack->Parameters.SetFile.ReplaceIfExists);
8748 
8749     /* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
8750     RxContext->Info.ReplaceIfExists = Stack->Parameters.SetFile.ReplaceIfExists;
8751     if (Stack->Parameters.SetFile.FileObject == NULL)
8752     {
8753         return RxpSetInfoMiniRdr(RxContext, Stack->Parameters.SetFile.FileInformationClass);
8754     }
8755 
8756     Fcb = (PFCB)RxContext->pFcb;
8757     RenameFcb = Stack->Parameters.SetFile.FileObject->FsContext;
8758     /* First, validate the received file object */
8759     ASSERT(NodeType(RenameFcb) == RDBSS_NTC_OPENTARGETDIR_FCB);
8760     if (Fcb->pNetRoot != RenameFcb->pNetRoot)
8761     {
8762         DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb, Fcb->pNetRoot, Fcb->pNetRoot->pNetRootName, RenameFcb, RenameFcb->pNetRoot, RenameFcb->pNetRoot->pNetRootName);
8763         return STATUS_NOT_SAME_DEVICE;
8764     }
8765 
8766     /* We'll reallocate a safe buffer */
8767     Length = Fcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize + RenameFcb->FcbTableEntry.Path.Length + FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName);
8768     RenameInfo = RxAllocatePoolWithTag(PagedPool, Length, '??xR');
8769     if (RenameInfo == NULL)
8770     {
8771         return STATUS_INSUFFICIENT_RESOURCES;
8772     }
8773 
8774     _SEH2_TRY
8775     {
8776         /* Copy the data */
8777         UserInfo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
8778         RenameInfo->ReplaceIfExists = UserInfo->ReplaceIfExists;
8779         RenameInfo->RootDirectory = UserInfo->RootDirectory;
8780         RenameInfo->FileNameLength = RenameFcb->FcbTableEntry.Path.Length;
8781         RtlMoveMemory(&RenameInfo->FileName[0], RenameFcb->FcbTableEntry.Path.Buffer, RenameFcb->FcbTableEntry.Path.Length);
8782 
8783         /* Set them in the RX_CONTEXT */
8784         RxContext->Info.FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
8785         RxContext->Info.Buffer = RenameInfo;
8786         RxContext->Info.Length = Length;
8787 
8788         /* And call the mini-rdr */
8789         MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
8790     }
8791     _SEH2_FINALLY
8792     {
8793         /* Free */
8794         RxFreePoolWithTag(RenameInfo, '??xR');
8795     }
8796     _SEH2_END;
8797 
8798     /* Done! */
8799     return Status;
8800 }
8801 
8802 #if DBG
8803 /*
8804  * @implemented
8805  */
8806 VOID
8807 RxSetShareAccess(
8808     _In_ ACCESS_MASK DesiredAccess,
8809     _In_ ULONG DesiredShareAccess,
8810     _Inout_ PFILE_OBJECT FileObject,
8811     _Out_ PSHARE_ACCESS ShareAccess,
8812     _In_ PSZ where,
8813     _In_ PSZ wherelogtag)
8814 {
8815     PAGED_CODE();
8816 
8817     RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8818     IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
8819     RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8820 }
8821 #endif
8822 
8823 NTSTATUS
8824 RxSetSimpleInfo(
8825     PRX_CONTEXT RxContext)
8826 {
8827     UNIMPLEMENTED;
8828     return STATUS_NOT_IMPLEMENTED;
8829 }
8830 
8831 /*
8832  * @implemented
8833  */
8834 VOID
8835 RxSetupNetFileObject(
8836     PRX_CONTEXT RxContext)
8837 {
8838     PFCB Fcb;
8839     PFOBX Fobx;
8840     PFILE_OBJECT FileObject;
8841     PIO_STACK_LOCATION Stack;
8842 
8843     PAGED_CODE();
8844 
8845     /* Assert FOBX is FOBX or NULL */
8846     Fobx = (PFOBX)RxContext->pFobx;
8847     ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
8848 
8849     Fcb = (PFCB)RxContext->pFcb;
8850     Stack = RxContext->CurrentIrpSp;
8851     FileObject = Stack->FileObject;
8852     /* If it's temporary mark FO as such */
8853     if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB &&
8854         BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY))
8855     {
8856         if (FileObject == NULL)
8857         {
8858             return;
8859         }
8860 
8861         FileObject->Flags |= FO_TEMPORARY_FILE;
8862     }
8863 
8864     /* No FO, nothing to setup */
8865     if (FileObject == NULL)
8866     {
8867         return;
8868     }
8869 
8870     /* Assign FCB & CCB (FOBX) to FO */
8871     FileObject->FsContext = Fcb;
8872     FileObject->FsContext2 = Fobx;
8873     if (Fobx != NULL)
8874     {
8875         ULONG_PTR StackTop, StackBottom;
8876 
8877         /* If FO is allocated on pool, keep track of it */
8878         IoGetStackLimits(&StackTop, &StackBottom);
8879         if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop)
8880         {
8881             Fobx->AssociatedFileObject = FileObject;
8882         }
8883         else
8884         {
8885             Fobx->AssociatedFileObject = NULL;
8886         }
8887 
8888         /* Make sure to mark FOBX if it's a DFS open */
8889         if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))
8890         {
8891             SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8892         }
8893         else
8894         {
8895             ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8896         }
8897     }
8898 
8899     /* Set Cc pointers */
8900     FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
8901 
8902     /* Update access state */
8903     if (Stack->Parameters.Create.SecurityContext != NULL)
8904     {
8905         PACCESS_STATE AccessState;
8906 
8907         AccessState = Stack->Parameters.Create.SecurityContext->AccessState;
8908         AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess;
8909         AccessState->RemainingDesiredAccess = 0;
8910     }
8911 }
8912 
8913 /*
8914  * @implemented
8915  */
8916 NTSTATUS
8917 NTAPI
8918 RxStartMinirdr(
8919     IN PRX_CONTEXT RxContext,
8920     OUT PBOOLEAN PostToFsp)
8921 {
8922     NTSTATUS Status;
8923     BOOLEAN Wait, AlreadyStarted;
8924     PRDBSS_DEVICE_OBJECT DeviceObject;
8925 
8926     /* If we've not been post, then, do it */
8927     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
8928     {
8929         SECURITY_SUBJECT_CONTEXT SubjectContext;
8930 
8931         SeCaptureSubjectContext(&SubjectContext);
8932         RxContext->FsdUid = RxGetUid(&SubjectContext);
8933         SeReleaseSubjectContext(&SubjectContext);
8934 
8935         *PostToFsp = TRUE;
8936         return STATUS_PENDING;
8937     }
8938 
8939     /* Acquire all the required locks */
8940     Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
8941     if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait))
8942     {
8943         *PostToFsp = TRUE;
8944         return STATUS_PENDING;
8945     }
8946 
8947     if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait))
8948     {
8949         ExReleaseResourceLite(&RxData.Resource);
8950         *PostToFsp = TRUE;
8951         return STATUS_PENDING;
8952     }
8953 
8954     AlreadyStarted = FALSE;
8955     DeviceObject = RxContext->RxDeviceObject;
8956     _SEH2_TRY
8957     {
8958         /* MUP handle set, means already registered */
8959         if (DeviceObject->MupHandle != NULL)
8960         {
8961             AlreadyStarted = TRUE;
8962             Status = STATUS_REDIRECTOR_STARTED;
8963             _SEH2_LEAVE;
8964         }
8965 
8966         /* If we're asked to register to MUP, then do it */
8967         Status = STATUS_SUCCESS;
8968         if (DeviceObject->RegisterUncProvider)
8969         {
8970             Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle,
8971                                               &DeviceObject->DeviceName,
8972                                               DeviceObject->RegisterMailSlotProvider);
8973         }
8974         if (!NT_SUCCESS(Status))
8975         {
8976             DeviceObject->MupHandle = NULL;
8977             _SEH2_LEAVE;
8978         }
8979 
8980         /* Register as file system */
8981         IoRegisterFileSystem(&DeviceObject->DeviceObject);
8982         DeviceObject->RegisteredAsFileSystem = TRUE;
8983 
8984         /* Inform mini-rdr it has to start */
8985         MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject));
8986         if (NT_SUCCESS(Status))
8987         {
8988             ++DeviceObject->StartStopContext.Version;
8989             RxSetRdbssState(DeviceObject, RDBSS_STARTED);
8990             InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
8991 
8992             Status = RxInitializeMRxDispatcher(DeviceObject);
8993         }
8994     }
8995     _SEH2_FINALLY
8996     {
8997         if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status))
8998         {
8999             if (!AlreadyStarted)
9000             {
9001                 RxUnstart(RxContext, DeviceObject);
9002             }
9003         }
9004 
9005         RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
9006         ExReleaseResourceLite(&RxData.Resource);
9007     }
9008     _SEH2_END;
9009 
9010     return Status;
9011 }
9012 
9013 NTSTATUS
9014 NTAPI
9015 RxStopMinirdr(
9016     IN PRX_CONTEXT RxContext,
9017     OUT PBOOLEAN PostToFsp)
9018 {
9019     UNIMPLEMENTED;
9020     return STATUS_NOT_IMPLEMENTED;
9021 }
9022 
9023 NTSTATUS
9024 RxSystemControl(
9025     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
9026     IN PIRP Irp)
9027 {
9028     UNIMPLEMENTED;
9029     return STATUS_NOT_IMPLEMENTED;
9030 }
9031 
9032 /*
9033  * @implemented
9034  */
9035 BOOLEAN
9036 RxTryToBecomeTheTopLevelIrp(
9037     IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
9038     IN PIRP Irp,
9039     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
9040     IN BOOLEAN ForceTopLevel
9041     )
9042 {
9043     BOOLEAN FromPool = FALSE;
9044 
9045     PAGED_CODE();
9046 
9047     /* If not top level, and not have to be, quit */
9048     if (IoGetTopLevelIrp() && !ForceTopLevel)
9049     {
9050         return FALSE;
9051     }
9052 
9053     /* If not TLC provider, allocate one */
9054     if (TopLevelContext == NULL)
9055     {
9056         TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
9057         if (TopLevelContext == NULL)
9058         {
9059             return FALSE;
9060         }
9061 
9062         FromPool = TRUE;
9063     }
9064 
9065     /* Init it */
9066     __RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
9067 
9068     ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
9069     if (FromPool)
9070     {
9071         ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
9072     }
9073 
9074     /* Make it top level IRP */
9075     IoSetTopLevelIrp((PIRP)TopLevelContext);
9076     return TRUE;
9077 }
9078 
9079 #if DBG
9080 /*
9081  * @implemented
9082  */
9083 VOID
9084 RxUpdateShareAccess(
9085     _Inout_ PFILE_OBJECT FileObject,
9086     _Inout_ PSHARE_ACCESS ShareAccess,
9087     _In_ PSZ where,
9088     _In_ PSZ wherelogtag)
9089 {
9090     PAGED_CODE();
9091 
9092     RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
9093     IoUpdateShareAccess(FileObject, ShareAccess);
9094     RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
9095 }
9096 #endif
9097 
9098 /*
9099  * @implemented
9100  */
9101 VOID
9102 RxUninitializeCacheMap(
9103     PRX_CONTEXT RxContext,
9104     PFILE_OBJECT FileObject,
9105     PLARGE_INTEGER TruncateSize)
9106 {
9107     PFCB Fcb;
9108     NTSTATUS Status;
9109     CACHE_UNINITIALIZE_EVENT UninitEvent;
9110 
9111     PAGED_CODE();
9112 
9113     Fcb = FileObject->FsContext;
9114     ASSERT(NodeTypeIsFcb(Fcb));
9115     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
9116 
9117     KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE);
9118     CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
9119 
9120     /* Always release the FCB before waiting for the uninit event */
9121     RxReleaseFcb(RxContext, Fcb);
9122 
9123     KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
9124 
9125     /* Re-acquire it afterwards */
9126     Status = RxAcquireExclusiveFcb(RxContext, Fcb);
9127     ASSERT(NT_SUCCESS(Status));
9128 }
9129 
9130 VOID
9131 NTAPI
9132 RxUnload(
9133     IN PDRIVER_OBJECT DriverObject)
9134 {
9135     UNIMPLEMENTED;
9136 }
9137 
9138 VOID
9139 NTAPI
9140 RxUnlockOperation(
9141     IN PVOID Context,
9142     IN PFILE_LOCK_INFO LockInfo)
9143 {
9144     UNIMPLEMENTED;
9145 }
9146 
9147 VOID
9148 RxUnstart(
9149     PRX_CONTEXT Context,
9150     PRDBSS_DEVICE_OBJECT DeviceObject)
9151 {
9152     UNIMPLEMENTED;
9153 }
9154 
9155 /*
9156  * @implemented
9157  */
9158 VOID
9159 RxUnwindTopLevelIrp(
9160     IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
9161 {
9162     DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
9163 
9164     /* No TLC provided? Ask the system for ours! */
9165     if (TopLevelContext == NULL)
9166     {
9167         TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
9168         if (TopLevelContext == NULL)
9169         {
9170             return;
9171         }
9172 
9173         /* In that case, just assert it's really ours */
9174         ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext));
9175         ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
9176     }
9177 
9178     ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
9179     ASSERT(TopLevelContext->Thread == PsGetCurrentThread());
9180     /* Restore the previous top level IRP */
9181     IoSetTopLevelIrp(TopLevelContext->Previous);
9182     /* If TLC was allocated from pool, remove it from list and release it */
9183     if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
9184     {
9185         RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
9186         RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
9187     }
9188 }
9189 
9190 /*
9191  * @implemented
9192  */
9193 VOID
9194 RxUpdateShareAccessPerSrvOpens(
9195     IN PSRV_OPEN SrvOpen)
9196 {
9197     ACCESS_MASK DesiredAccess;
9198     BOOLEAN ReadAccess;
9199     BOOLEAN WriteAccess;
9200     BOOLEAN DeleteAccess;
9201 
9202     PAGED_CODE();
9203 
9204     /* If already updated, no need to continue */
9205     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED))
9206     {
9207         return;
9208     }
9209 
9210     /* Check if any access wanted */
9211     DesiredAccess = SrvOpen->DesiredAccess;
9212     ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
9213     WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
9214     DeleteAccess = (DesiredAccess & DELETE) != 0;
9215 
9216     /* In that case, update it */
9217     if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
9218     {
9219         BOOLEAN SharedRead;
9220         BOOLEAN SharedWrite;
9221         BOOLEAN SharedDelete;
9222         ULONG DesiredShareAccess;
9223         PSHARE_ACCESS ShareAccess;
9224 
9225         ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
9226         DesiredShareAccess = SrvOpen->ShareAccess;
9227 
9228         SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
9229         SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
9230         SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
9231 
9232         ShareAccess->OpenCount++;
9233 
9234         ShareAccess->Readers += ReadAccess;
9235         ShareAccess->Writers += WriteAccess;
9236         ShareAccess->Deleters += DeleteAccess;
9237         ShareAccess->SharedRead += SharedRead;
9238         ShareAccess->SharedWrite += SharedWrite;
9239         ShareAccess->SharedDelete += SharedDelete;
9240     }
9241 
9242     SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);
9243 }
9244 
9245 /*
9246  * @implemented
9247  */
9248 NTSTATUS
9249 RxXXXControlFileCallthru(
9250     PRX_CONTEXT Context)
9251 {
9252     NTSTATUS Status;
9253 
9254     PAGED_CODE();
9255 
9256     DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
9257 
9258     /* No dispatch table? Nothing to dispatch */
9259     if (Context->RxDeviceObject->Dispatch == NULL)
9260     {
9261         Context->pFobx = NULL;
9262         return STATUS_INVALID_DEVICE_REQUEST;
9263     }
9264 
9265     /* Init the lowio context */
9266     Status = RxLowIoPopulateFsctlInfo(Context);
9267     if (!NT_SUCCESS(Status))
9268     {
9269         return Status;
9270     }
9271 
9272     /* Check whether we're consistent: a length means a buffer */
9273     if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) ||
9274         (Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL))
9275     {
9276         return STATUS_INVALID_PARAMETER;
9277     }
9278 
9279     /* Forward the call to the mini-rdr */
9280     DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile);
9281     Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context);
9282     if (Status != STATUS_PENDING)
9283     {
9284         Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn;
9285     }
9286 
9287     DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information);
9288     return Status;
9289 }
9290