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