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