3 * Copyright (C) 2017 ReactOS Team
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.
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.
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.
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)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
42 (NTAPI
*PRX_FSD_DISPATCH
) (
45 typedef struct _RX_FSD_DISPATCH_VECTOR
47 PRX_FSD_DISPATCH CommonRoutine
;
48 } RX_FSD_DISPATCH_VECTOR
, *PRX_FSD_DISPATCH_VECTOR
;
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject
);
58 PFILE_OBJECT FileObject
,
59 PDEVICE_OBJECT DeviceObject
);
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
89 RxCommonDevFCBCleanup(
100 PRX_CONTEXT Context
);
105 PRX_CONTEXT Context
);
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context
);
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context
);
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context
);
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context
);
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context
);
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context
);
140 PRX_CONTEXT Context
);
145 PRX_CONTEXT Context
);
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context
);
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context
);
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context
);
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context
);
170 PRX_CONTEXT Context
);
175 PRX_CONTEXT Context
);
179 RxCommonSetInformation(
180 PRX_CONTEXT Context
);
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context
);
190 PRX_CONTEXT Context
);
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context
);
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context
);
205 PRX_CONTEXT Context
);
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext
);
214 PUNICODE_STRING NetRootName
);
218 IN PRX_CONTEXT RxContext
);
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
);
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject
,
235 PVOID InputBuffer OPTIONAL
,
236 ULONG InputBufferLength
,
237 PVOID OutputBuffer OPTIONAL
,
238 ULONG OutputBufferLength
,
240 PIO_STATUS_BLOCK IoStatus
,
241 PDEVICE_OBJECT DeviceObject
);
246 PFILE_OBJECT FileObject
,
247 PLARGE_INTEGER FileOffset
,
252 PIO_STATUS_BLOCK IoStatus
,
253 PDEVICE_OBJECT DeviceObject
);
258 PFILE_OBJECT FileObject
,
259 PLARGE_INTEGER FileOffset
,
264 PIO_STATUS_BLOCK IoStatus
,
265 PDEVICE_OBJECT DeviceObject
);
269 PRX_CONTEXT RxContext
,
270 PUNICODE_STRING NetRootName
);
274 PRX_CONTEXT RxContext
,
275 PUNICODE_STRING FileName
,
276 PUNICODE_STRING CanonicalName
,
277 PNET_ROOT_TYPE NetRootType
);
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context
);
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath
);
295 RxGetStringRegistryParameter(
298 OUT PUNICODE_STRING OutString
,
300 IN ULONG BufferLength
,
301 IN BOOLEAN LogFailure
);
305 RxInitializeDebugSupport(
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject
);
315 RxInitializeRegistrationStructures(
320 RxInitializeTopLevelIrpPackage(
326 PDRIVER_OBJECT DriverObject
,
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext
);
340 PRX_CONTEXT RxContext
);
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext
);
349 IN PRX_CONTEXT RxContext
);
353 RxLowIoWriteShellCompletion(
354 PRX_CONTEXT RxContext
);
358 PRX_CONTEXT RxContext
);
361 RxNotifyChangeDirectory(
362 PRX_CONTEXT RxContext
);
366 PRX_CONTEXT RxContext
,
367 FILE_INFORMATION_CLASS FileInfoClass
,
373 PRX_CONTEXT LocalContext
);
376 RxQueryAlternateNameInfo(
377 PRX_CONTEXT RxContext
,
378 PFILE_NAME_INFORMATION AltNameInfo
);
382 PRX_CONTEXT RxContext
,
383 PFILE_BASIC_INFORMATION BasicInfo
);
386 RxQueryCompressedInfo(
387 PRX_CONTEXT RxContext
,
388 PFILE_COMPRESSION_INFORMATION CompressionInfo
);
392 PRX_CONTEXT RxContext
);
396 PRX_CONTEXT RxContext
,
397 PFILE_EA_INFORMATION EaInfo
);
401 PRX_CONTEXT RxContext
,
402 PFILE_INTERNAL_INFORMATION InternalInfo
);
406 PRX_CONTEXT RxContext
,
407 PFILE_NAME_INFORMATION NameInfo
);
411 PRX_CONTEXT RxContext
,
412 PFILE_PIPE_INFORMATION PipeInfo
);
416 PRX_CONTEXT RxContext
,
417 PFILE_POSITION_INFORMATION PositionInfo
);
421 PRX_CONTEXT RxContext
,
422 PFILE_STANDARD_INFORMATION StandardInfo
);
426 RxReadRegistryParameters(
431 RxReleaseFileForNtCreateSection(
432 PFILE_OBJECT FileObject
);
437 PFILE_OBJECT FileObject
,
438 PDEVICE_OBJECT DeviceObject
);
441 RxRemoveOverflowEntry(
442 PRDBSS_DEVICE_OBJECT DeviceObject
,
443 WORK_QUEUE_TYPE Queue
);
446 RxSearchForCollapsibleOpen(
447 PRX_CONTEXT RxContext
,
448 ACCESS_MASK DesiredAccess
,
453 PRX_CONTEXT RxContext
);
457 PRX_CONTEXT RxContext
);
460 RxSetDispositionInfo(
461 PRX_CONTEXT RxContext
);
465 PRX_CONTEXT RxContext
);
469 PRX_CONTEXT RxContext
);
473 PRX_CONTEXT RxContext
);
477 PRX_CONTEXT RxContext
);
481 PRX_CONTEXT RxContext
);
484 RxSetupNetFileObject(
485 PRX_CONTEXT RxContext
);
489 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
493 RxUninitializeCacheMap(
494 PRX_CONTEXT RxContext
,
495 PFILE_OBJECT FileObject
,
496 PLARGE_INTEGER TruncateSize
);
501 PRDBSS_DEVICE_OBJECT DeviceObject
);
504 RxXXXControlFileCallthru(
505 PRX_CONTEXT Context
);
509 _RxAllocatePoolWithTag(
510 _In_ POOL_TYPE PoolType
,
511 _In_ SIZE_T NumberOfBytes
,
525 WCHAR RxStarForTemplate
= '*';
526 WCHAR Rx8QMdot3QM
[] = L
">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles
= FALSE
;
528 BOOLEAN DisableFlushOnCleanup
= FALSE
;
529 ULONG ReadAheadGranularity
= 1 << PAGE_SHIFT
;
530 LIST_ENTRY RxActiveContexts
;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList
;
532 FAST_MUTEX RxContextPerFileSerializationMutex
;
535 BOOLEAN RxLoudLowIoOpsEnabled
= FALSE
;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
538 { RxCommonDispatchProblem
},
539 { RxCommonDispatchProblem
},
540 { RxCommonDevFCBClose
},
541 { RxCommonDispatchProblem
},
542 { RxCommonDispatchProblem
},
543 { RxCommonDispatchProblem
},
544 { RxCommonDispatchProblem
},
545 { RxCommonDispatchProblem
},
546 { RxCommonDispatchProblem
},
547 { RxCommonDispatchProblem
},
548 { RxCommonDevFCBQueryVolInfo
},
549 { RxCommonDispatchProblem
},
550 { RxCommonDispatchProblem
},
551 { RxCommonDevFCBFsCtl
},
552 { RxCommonDevFCBIoCtl
},
553 { RxCommonDevFCBIoCtl
},
554 { RxCommonDispatchProblem
},
555 { RxCommonDispatchProblem
},
556 { RxCommonDevFCBCleanup
},
557 { RxCommonDispatchProblem
},
558 { RxCommonDispatchProblem
},
559 { RxCommonDispatchProblem
},
560 { RxCommonUnimplemented
},
561 { RxCommonUnimplemented
},
562 { RxCommonUnimplemented
},
563 { RxCommonUnimplemented
},
564 { RxCommonUnimplemented
},
565 { RxCommonUnimplemented
},
567 RDBSS_EXPORTS RxExports
;
568 FAST_IO_DISPATCH RxFastIoDispatch
;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject
;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
573 { RxCommonUnimplemented
},
577 { RxCommonQueryInformation
},
578 { RxCommonSetInformation
},
581 { RxCommonFlushBuffers
},
582 { RxCommonQueryVolumeInformation
},
583 { RxCommonSetVolumeInformation
},
584 { RxCommonDirectoryControl
},
585 { RxCommonFileSystemControl
},
586 { RxCommonDeviceControl
},
587 { RxCommonDeviceControl
},
588 { RxCommonUnimplemented
},
589 { RxCommonLockControl
},
591 { RxCommonUnimplemented
},
592 { RxCommonQuerySecurity
},
593 { RxCommonSetSecurity
},
594 { RxCommonUnimplemented
},
595 { RxCommonUnimplemented
},
596 { RxCommonUnimplemented
},
597 { RxCommonQueryQuotaInformation
},
598 { RxCommonSetQuotaInformation
},
599 { RxCommonUnimplemented
},
601 ULONG RxFsdEntryCount
;
602 LIST_ENTRY RxIrpsList
;
603 KSPIN_LOCK RxIrpsListSpinLock
;
604 KMUTEX RxScavengerMutex
;
605 KMUTEX RxSerializationMutex
;
606 UCHAR RxSpaceForTheWrappersDeviceObject
[sizeof(*RxFileSystemDeviceObject
)];
607 KSPIN_LOCK TopLevelIrpSpinLock
;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList
;
609 BOOLEAN RxForceQFIPassThrough
= FALSE
;
610 BOOLEAN RxNoAsync
= FALSE
;
612 DECLARE_CONST_UNICODE_STRING(unknownId
, L
"???");
619 #define ASSERT(exp) \
622 RxAssert(#exp, __FILE__, __LINE__, NULL); \
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
637 /* FUNCTIONS ****************************************************************/
643 CheckForLoudOperations(
644 PRX_CONTEXT RxContext
)
650 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
652 /* Are loud operations enabled? */
653 if (RxLoudLowIoOpsEnabled
)
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 if (RtlCompareMemory(Add2Ptr(capFcb
->PrivateAlreadyPrefixedName
.Buffer
,
657 (capFcb
->PrivateAlreadyPrefixedName
.Length
- ALLSCR_LENGTH
)),
658 L
"all.scr", ALLSCR_LENGTH
) == ALLSCR_LENGTH
)
660 SetFlag(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
);
670 __RxInitializeTopLevelIrpContext(
671 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
673 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
676 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext
, Irp
, RxDeviceObject
, Flags
);
678 RtlZeroMemory(TopLevelContext
, sizeof(RX_TOPLEVELIRP_CONTEXT
));
679 TopLevelContext
->Irp
= Irp
;
680 TopLevelContext
->Flags
= (Flags
? RX_TOPLEVELCTX_FLAG_FROM_POOL
: 0);
681 TopLevelContext
->Signature
= RX_TOPLEVELIRP_CONTEXT_SIGNATURE
;
682 TopLevelContext
->RxDeviceObject
= RxDeviceObject
;
683 TopLevelContext
->Previous
= IoGetTopLevelIrp();
684 TopLevelContext
->Thread
= PsGetCurrentThread();
686 /* We cannot add to list something that'd come from stack */
687 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
689 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext
);
697 __RxWriteReleaseResources(
698 PRX_CONTEXT RxContext
,
699 BOOLEAN ResourceOwnerSet
,
708 ASSERT(RxContext
!= NULL
);
709 ASSERT(capFcb
!= NULL
);
711 /* If FCB resource was acquired, release it */
712 if (RxContext
->FcbResourceAcquired
)
714 /* Taking care of owner */
715 if (ResourceOwnerSet
)
717 RxReleaseFcbForThread(RxContext
, capFcb
, RxContext
->LowIoContext
.ResourceThreadId
);
721 RxReleaseFcb(RxContext
, capFcb
);
724 RxContext
->FcbResourceAcquired
= FALSE
;
727 /* If FCB paging resource was acquired, release it */
728 if (RxContext
->FcbPagingIoResourceAcquired
)
730 /* Taking care of owner */
731 if (ResourceOwnerSet
)
733 RxReleasePagingIoResourceForThread(RxContext
, capFcb
, RxContext
->LowIoContext
.ResourceThreadId
);
737 RxReleasePagingIoResource(RxContext
, capFcb
);
740 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
748 RxAddToTopLevelIrpAllocatedContextsList(
749 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
753 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
755 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
756 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
758 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
759 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
760 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
769 IN PRX_CONTEXT RxContext
,
774 WORK_QUEUE_TYPE Queue
;
778 RxContext
->PostRequest
= FALSE
;
780 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
781 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
782 capPARAMS
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
784 Queue
= DelayedWorkQueue
;
785 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
789 Queue
= CriticalWorkQueue
;
790 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
793 /* Check for overflow */
794 if (capPARAMS
->FileObject
!= NULL
)
796 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
798 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
799 /* In case of an overflow, add the new queued call to the overflow list */
802 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
803 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
804 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
806 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
810 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
813 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
814 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
821 RxAdjustFileTimesAndSize(
822 PRX_CONTEXT RxContext
)
825 LARGE_INTEGER CurrentTime
;
826 FILE_BASIC_INFORMATION FileBasicInfo
;
827 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
828 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
837 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
838 if (capFileObject
->PrivateCacheMap
== NULL
)
844 KeQuerySystemTime(&CurrentTime
);
846 /* Was the file modified? */
847 FileModified
= BooleanFlagOn(capFileObject
->Flags
, FO_FILE_MODIFIED
);
848 /* We'll set last write if it was modified and user didn't update yet */
849 SetLastWrite
= FileModified
&& !BooleanFlagOn(capFobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
850 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
851 SetLastAccess
= SetLastWrite
||
852 (BooleanFlagOn(capFileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
853 !BooleanFlagOn(capFobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
854 /* We'll set last change if it was modified and user didn't update yet */
855 SetLastChange
= FileModified
&& !BooleanFlagOn(capFobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
857 /* Nothing to update? Job done */
858 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
863 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
865 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
867 /* Update lastwrite time if required */
871 capFcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
872 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
875 /* Update lastaccess time if required */
879 capFcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
880 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
883 /* Update lastchange time if required */
887 capFcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
888 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
891 /* If one of the date was modified, issue a call to mini-rdr */
894 RxContext
->Info
.FileInformationClass
= FileBasicInformation
;
895 RxContext
->Info
.Buffer
= &FileBasicInfo
;
896 RxContext
->Info
.Length
= sizeof(FileBasicInfo
);
898 MINIRDR_CALL(Status
, RxContext
, capFcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (RxContext
));
902 /* If the file was modified, update its EOF */
905 FileEOFInfo
.EndOfFile
.QuadPart
= capFcb
->Header
.FileSize
.QuadPart
;
907 RxContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
908 RxContext
->Info
.Buffer
= &FileEOFInfo
;
909 RxContext
->Info
.Length
= sizeof(FileEOFInfo
);
911 MINIRDR_CALL(Status
, RxContext
, capFcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (RxContext
));
920 RxAllocateCanonicalNameBuffer(
921 PRX_CONTEXT RxContext
,
922 PUNICODE_STRING CanonicalName
,
923 USHORT CanonicalLength
)
927 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
929 /* Context must be free of any already allocated name */
930 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
932 /* Validate string length */
933 if (CanonicalLength
> USHRT_MAX
- 1)
935 CanonicalName
->Buffer
= NULL
;
936 return STATUS_OBJECT_PATH_INVALID
;
939 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
940 if (CanonicalName
->Buffer
== NULL
)
942 return STATUS_INSUFFICIENT_RESOURCES
;
945 CanonicalName
->Length
= 0;
946 CanonicalName
->MaximumLength
= CanonicalLength
;
948 /* Set the two places - they must always be identical */
949 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
950 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
952 return STATUS_SUCCESS
;
959 RxCancelNotifyChangeDirectoryRequestsForFobx(
965 LIST_ENTRY ContextsToCancel
;
967 /* Init a list for the contexts to cancel */
968 InitializeListHead(&ContextsToCancel
);
970 /* Lock our list lock */
971 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
973 /* Now, browse all the active contexts, to find the associated ones */
974 Entry
= RxActiveContexts
.Flink
;
975 while (Entry
!= &RxActiveContexts
)
977 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
978 Entry
= Entry
->Flink
;
980 /* Not the IRP we're looking for, ignore */
981 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
982 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
987 /* Not the FOBX we're looking for, ignore */
988 if ((PFOBX
)Context
->pFobx
!= Fobx
)
993 /* No cancel routine (can't be cancel, then), ignore */
994 if (Context
->MRxCancelRoutine
== NULL
)
999 /* Mark our context as cancelled */
1000 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1002 /* Move it to our list */
1003 RemoveEntryList(&Context
->ContextListEntry
);
1004 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1006 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1009 /* Done with the contexts */
1010 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1012 /* Now, handle all our "extracted" contexts */
1013 while (!IsListEmpty(&ContextsToCancel
))
1015 Entry
= RemoveHeadList(&ContextsToCancel
);
1016 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1018 /* If they had an associated IRP (should be always true) */
1019 if (Context
->CurrentIrp
!= NULL
)
1021 /* Then, call cancel routine */
1022 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1023 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1024 Context
->MRxCancelRoutine(Context
);
1027 /* And delete the context */
1028 RxDereferenceAndDeleteRxContext(Context
);
1036 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1037 PV_NET_ROOT VNetRoot
,
1038 BOOLEAN ForceFilesClosed
)
1043 PRX_CONTEXT Context
;
1044 LIST_ENTRY ContextsToCancel
;
1046 /* Init a list for the contexts to cancel */
1047 InitializeListHead(&ContextsToCancel
);
1049 /* Lock our list lock */
1050 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1052 /* Assume success */
1053 Status
= STATUS_SUCCESS
;
1055 /* Now, browse all the active contexts, to find the associated ones */
1056 Entry
= RxActiveContexts
.Flink
;
1057 while (Entry
!= &RxActiveContexts
)
1059 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1060 Entry
= Entry
->Flink
;
1062 /* Not the IRP we're looking for, ignore */
1063 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1064 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1069 /* Not the VNetRoot we're looking for, ignore */
1070 if (Context
->pFcb
== NULL
||
1071 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1076 /* No cancel routine (can't be cancel, then), ignore */
1077 if (Context
->MRxCancelRoutine
== NULL
)
1082 /* At that point, we found a matching context
1083 * If we're not asked to force close, then fail - it's still open
1085 if (!ForceFilesClosed
)
1087 Status
= STATUS_FILES_OPEN
;
1091 /* Mark our context as cancelled */
1092 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1094 /* Move it to our list */
1095 RemoveEntryList(&Context
->ContextListEntry
);
1096 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1098 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1101 /* Done with the contexts */
1102 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1104 if (Status
!= STATUS_SUCCESS
)
1109 /* Now, handle all our "extracted" contexts */
1110 while (!IsListEmpty(&ContextsToCancel
))
1112 Entry
= RemoveHeadList(&ContextsToCancel
);
1113 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1115 /* If they had an associated IRP (should be always true) */
1116 if (Context
->CurrentIrp
!= NULL
)
1118 /* Then, call cancel routine */
1119 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1120 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1121 Context
->MRxCancelRoutine(Context
);
1124 /* And delete the context */
1125 RxDereferenceAndDeleteRxContext(Context
);
1134 PDEVICE_OBJECT DeviceObject
,
1144 RxCanonicalizeFileNameByServerSpecs(
1145 PRX_CONTEXT RxContext
,
1146 PUNICODE_STRING NetRootName
)
1148 USHORT NextChar
, CurChar
;
1153 /* Validate file name is not empty */
1154 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1157 return STATUS_MORE_PROCESSING_REQUIRED
;
1160 /* Validate name is correct */
1161 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1165 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1167 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1174 if (CurChar
== NextChar
)
1176 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1183 if (CurChar
>= MaxChars
- 1)
1188 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1190 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1195 if (NetRootName
->Buffer
[1] != ':')
1197 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1203 if ((CurChar
- NextChar
) == 1)
1205 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1210 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1212 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1217 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1218 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1223 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1225 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1231 return STATUS_MORE_PROCESSING_REQUIRED
;
1235 RxCanonicalizeNameAndObtainNetRoot(
1236 PRX_CONTEXT RxContext
,
1237 PUNICODE_STRING FileName
,
1238 PUNICODE_STRING NetRootName
)
1241 NET_ROOT_TYPE NetRootType
;
1242 UNICODE_STRING CanonicalName
;
1244 RxCaptureParamBlock
;
1245 RxCaptureFileObject
;
1249 NetRootType
= NET_ROOT_WILD
;
1251 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1252 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1254 /* if not relative opening, just handle the passed name */
1255 if (capFileObject
->RelatedFileObject
== NULL
)
1257 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1258 if (!NT_SUCCESS(Status
))
1267 /* Make sure we have a valid FCB and a FOBX */
1268 Fcb
= capFileObject
->RelatedFileObject
->FsContext
;
1269 if (Fcb
== NULL
|| capFileObject
->RelatedFileObject
->FsContext2
== NULL
)
1271 return STATUS_INVALID_PARAMETER
;
1274 if (!NodeTypeIsFcb(Fcb
))
1276 return STATUS_INVALID_PARAMETER
;
1282 /* Get/Create the associated VNetRoot for opening */
1283 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1284 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1285 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1287 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1289 RxFreeCanonicalNameBuffer(RxContext
);
1290 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1291 if (NT_SUCCESS(Status
))
1293 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1297 /* Filename cannot contain wildcards */
1298 if (FsRtlDoesNameContainWildCards(NetRootName
))
1300 Status
= STATUS_OBJECT_NAME_INVALID
;
1303 /* Make sure file name is correct */
1304 if (NT_SUCCESS(Status
))
1306 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1309 /* Give the mini-redirector a chance to prepare the name */
1310 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1312 if (RxContext
->Create
.pNetRoot
!= NULL
)
1314 NTSTATUS IgnoredStatus
;
1316 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1317 MRxPreparseName
, (RxContext
, NetRootName
));
1318 (void)IgnoredStatus
;
1330 RxCheckFcbStructuresForAlignment(
1339 _In_ ACCESS_MASK DesiredAccess
,
1340 _In_ ULONG DesiredShareAccess
,
1341 _Inout_ PFILE_OBJECT FileObject
,
1342 _Inout_ PSHARE_ACCESS ShareAccess
,
1343 _In_ BOOLEAN Update
,
1345 _In_ PSZ wherelogtag
)
1349 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1350 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1352 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1360 RxCheckShareAccessPerSrvOpens(
1362 IN ACCESS_MASK DesiredAccess
,
1363 IN ULONG DesiredShareAccess
)
1366 BOOLEAN WriteAccess
;
1367 BOOLEAN DeleteAccess
;
1368 PSHARE_ACCESS ShareAccess
;
1372 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1374 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1375 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1377 /* Check if any access wanted */
1378 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1379 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1380 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1382 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1384 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1385 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1386 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1388 /* Check whether there's a violation */
1390 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1392 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1394 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1395 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1396 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1397 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1399 return STATUS_SHARING_VIOLATION
;
1403 return STATUS_SUCCESS
;
1407 RxCleanupPipeQueues(
1408 PRX_CONTEXT Context
)
1417 RxCloseAssociatedSrvOpen(
1419 IN PRX_CONTEXT RxContext OPTIONAL
)
1424 BOOLEAN CloseSrvOpen
;
1425 PRX_CONTEXT LocalContext
;
1429 /* Assume SRV_OPEN is already closed */
1430 CloseSrvOpen
= FALSE
;
1431 /* If we have a FOBX, we'll have to close it */
1434 /* If the FOBX isn't closed yet */
1435 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1437 SrvOpen
= Fobx
->SrvOpen
;
1438 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1439 /* Check whether we've to close SRV_OPEN first */
1440 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1442 CloseSrvOpen
= TRUE
;
1446 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1448 /* Not much to do */
1449 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1451 if (SrvOpen
->OpenCount
> 0)
1453 --SrvOpen
->OpenCount
;
1458 /* No need to close SRV_OPEN, so close FOBX */
1461 RxMarkFobxOnClose(Fobx
);
1463 return STATUS_SUCCESS
;
1468 /* No FOBX? No RX_CONTEXT, ok, job done! */
1469 if (RxContext
== NULL
)
1471 return STATUS_SUCCESS
;
1474 /* Get the FCB from RX_CONTEXT */
1475 Fcb
= (PFCB
)RxContext
->pFcb
;
1479 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1480 if (RxContext
== NULL
)
1482 ASSERT(Fobx
!= NULL
);
1484 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1485 if (LocalContext
== NULL
)
1487 return STATUS_INSUFFICIENT_RESOURCES
;
1490 LocalContext
->MajorFunction
= 2;
1491 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1492 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1493 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1497 LocalContext
= RxContext
;
1500 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1502 /* Now, close the FOBX */
1505 RxMarkFobxOnClose(Fobx
);
1509 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1512 /* If not a "standard" file, SRV_OPEN can be null */
1513 if (SrvOpen
== NULL
)
1515 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1516 RxDereferenceNetFcb(Fcb
);
1518 if (LocalContext
!= RxContext
)
1520 RxDereferenceAndDeleteRxContext(LocalContext
);
1523 return STATUS_SUCCESS
;
1526 /* If SRV_OPEN isn't in a good condition, nothing to close */
1527 if (SrvOpen
->Condition
!= Condition_Good
)
1529 if (LocalContext
!= RxContext
)
1531 RxDereferenceAndDeleteRxContext(LocalContext
);
1534 return STATUS_SUCCESS
;
1537 /* Decrease open count */
1538 if (SrvOpen
->OpenCount
> 0)
1540 --SrvOpen
->OpenCount
;
1543 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1544 if (SrvOpen
->OpenCount
== 1)
1546 if (!IsListEmpty(&SrvOpen
->FobxList
))
1548 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1550 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1555 /* Nothing left, purge FCB */
1556 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1558 RxPurgeNetFcb(Fcb
, LocalContext
);
1561 /* Already closed? Job done! */
1562 SrvOpen
= Fobx
->SrvOpen
;
1563 if (SrvOpen
== NULL
||
1564 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1565 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1567 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1568 if (LocalContext
!= RxContext
)
1570 RxDereferenceAndDeleteRxContext(LocalContext
);
1573 return STATUS_SUCCESS
;
1576 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1578 /* Inform mini-rdr about closing */
1579 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1580 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1581 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1583 /* And mark as such */
1584 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1585 SrvOpen
->Key
= (PVOID
)-1;
1587 /* If we were delayed, we're not! */
1588 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1590 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1594 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1595 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1598 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1600 /* Mark the FOBX closed as well */
1601 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1603 if (LocalContext
!= RxContext
)
1605 RxDereferenceAndDeleteRxContext(LocalContext
);
1615 RxCollapseOrCreateSrvOpen(
1616 PRX_CONTEXT RxContext
)
1622 ACCESS_MASK DesiredAccess
;
1623 RX_BLOCK_CONDITION FcbCondition
;
1626 RxCaptureParamBlock
;
1630 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1632 ASSERT(RxIsFcbAcquiredExclusive(capFcb
));
1633 ++capFcb
->UncleanCount
;
1635 DesiredAccess
= capPARAMS
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1636 ShareAccess
= capPARAMS
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1638 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1640 /* Try to find a reusable SRV_OPEN */
1641 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1642 if (Status
== STATUS_NOT_FOUND
)
1644 /* If none found, create one */
1645 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, capFcb
);
1646 if (SrvOpen
== NULL
)
1648 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1652 SrvOpen
->DesiredAccess
= DesiredAccess
;
1653 SrvOpen
->ShareAccess
= ShareAccess
;
1654 Status
= STATUS_SUCCESS
;
1657 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1659 if (Status
!= STATUS_SUCCESS
)
1661 FcbCondition
= Condition_Bad
;
1665 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1667 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1668 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1669 /* Inform the mini-rdr we're handling a create */
1670 MINIRDR_CALL(Status
, RxContext
, capFcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1671 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1673 DPRINT("MRxCreate returned: %x\n", Status
);
1674 if (Status
== STATUS_SUCCESS
)
1676 /* In case of overwrite, reset file size */
1677 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1679 RxAcquirePagingIoResource(RxContext
, capFcb
);
1680 capFcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1681 capFcb
->Header
.FileSize
.QuadPart
= 0LL;
1682 capFcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1683 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &capFcb
->NonPaged
->SectionObjectPointers
;
1684 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&capFcb
->Header
.AllocationSize
);
1685 RxReleasePagingIoResource(RxContext
, capFcb
);
1689 /* Otherwise, adjust sizes */
1690 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &capFcb
->NonPaged
->SectionObjectPointers
;
1691 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1693 RxAdjustAllocationSizeforCC(capFcb
);
1695 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&capFcb
->Header
.AllocationSize
);
1699 /* Set the IoStatus with information returned by mini-rdr */
1700 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1702 SrvOpen
->OpenStatus
= Status
;
1703 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1704 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1706 ASSERT(RxIsFcbAcquiredExclusive(capFcb
));
1708 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1710 if (Status
== STATUS_SUCCESS
)
1712 if (BooleanFlagOn(capPARAMS
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1714 ClearFlag(capFcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1716 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1717 FcbCondition
= Condition_Good
;
1721 FcbCondition
= Condition_Bad
;
1722 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1723 RxContext
->pRelevantSrvOpen
= NULL
;
1725 if (RxContext
->pFobx
!= NULL
)
1727 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1728 RxContext
->pFobx
= NULL
;
1733 /* Set FCB state - good or bad - depending on whether create succeed */
1734 DPRINT("Transitioning FCB %p to condition %lx\n", capFcb
, capFcb
->Condition
);
1735 RxTransitionNetFcb(capFcb
, FcbCondition
);
1737 else if (Status
== STATUS_SUCCESS
)
1739 BOOLEAN IsGood
, ExtraOpen
;
1741 /* A reusable SRV_OPEN was found */
1742 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1745 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1747 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1748 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1749 if (!StableCondition(SrvOpen
->Condition
))
1751 RxReferenceSrvOpen(SrvOpen
);
1752 ++SrvOpen
->OpenCount
;
1755 RxReleaseFcb(RxContext
, capFcb
);
1756 RxContext
->Create
.FcbAcquired
= FALSE
;
1758 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1760 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, capFcb
)))
1762 RxContext
->Create
.FcbAcquired
= TRUE
;
1765 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1768 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1771 MINIRDR_CALL(Status
, RxContext
, capFcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1773 ASSERT(RxIsFcbAcquiredExclusive(capFcb
));
1777 Status
= SrvOpen
->OpenStatus
;
1782 --SrvOpen
->OpenCount
;
1783 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1787 --capFcb
->UncleanCount
;
1789 DPRINT("Status: %x\n", Status
);
1799 PRX_CONTEXT Context
)
1801 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1807 PFILE_OBJECT FileObject
;
1808 LARGE_INTEGER TruncateSize
;
1809 PLARGE_INTEGER TruncateSizePtr
;
1810 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1814 Fcb
= (PFCB
)Context
->pFcb
;
1815 Fobx
= (PFOBX
)Context
->pFobx
;
1816 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1818 /* File system closing, it's OK */
1821 if (Fcb
->UncleanCount
> 0)
1823 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1826 return STATUS_SUCCESS
;
1829 /* Check we have a correct FCB type */
1830 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1831 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1832 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1833 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1835 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1836 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1839 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1840 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1842 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1844 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1845 if (!NT_SUCCESS(Status
))
1852 Fobx
->AssociatedFileObject
= NULL
;
1854 /* In case it was already orphaned */
1855 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
1857 ASSERT(Fcb
->UncleanCount
!= 0);
1858 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1860 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1862 --Fcb
->UncachedUncleanCount
;
1865 /* Inform mini-rdr */
1866 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1868 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1869 --Fobx
->SrvOpen
->UncleanFobxCount
;
1871 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1873 RxReleaseFcb(Context
, Fcb
);
1875 return STATUS_SUCCESS
;
1878 /* Report the fact that file could be set as delete on close */
1879 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1881 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1884 /* Cancel any pending notification */
1885 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1887 /* Backup open count before we start playing with it */
1888 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1890 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1891 FcbTableAcquired
= FALSE
;
1892 LeftForDelete
= FALSE
;
1893 OneLeft
= (Fcb
->UncleanCount
== 1);
1897 /* Unclean count and delete on close? Verify whether we're the one */
1898 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1900 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1902 FcbTableAcquired
= TRUE
;
1906 RxReleaseFcb(Context
, Fcb
);
1908 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1910 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1911 if (Status
!= STATUS_SUCCESS
)
1913 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1917 FcbTableAcquired
= TRUE
;
1920 /* That means we'll perform the delete on close! */
1921 if (Fcb
->UncleanCount
== 1)
1923 LeftForDelete
= TRUE
;
1927 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1928 FcbTableAcquired
= FALSE
;
1933 TruncateSizePtr
= NULL
;
1934 /* Handle cleanup for pipes and printers */
1935 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1937 RxCleanupPipeQueues(Context
);
1939 /* Handle cleanup for files */
1940 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1942 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1943 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1946 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1948 /* If there are still locks to release, proceed */
1949 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1951 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1952 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1953 Status
= RxLowIoLockControlShell(Context
);
1956 /* Fix times and size */
1957 RxAdjustFileTimesAndSize(Context
);
1959 /* If we're the only one left... */
1962 /* And if we're supposed to delete on close */
1965 /* Update the sizes */
1966 RxAcquirePagingIoResource(Context
, Fcb
);
1967 Fcb
->Header
.FileSize
.QuadPart
= 0;
1968 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1969 RxReleasePagingIoResource(Context
, Fcb
);
1971 /* Otherwise, call the mini-rdr to adjust sizes */
1974 /* File got grown up, fill with zeroes */
1975 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1976 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1978 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1979 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1982 /* File was truncated, let mini-rdr proceed */
1983 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1985 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1986 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1988 /* Keep track of file change for Cc uninit */
1989 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1990 TruncateSizePtr
= &TruncateSize
;
1995 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2003 /* Otherwise, try to see whether we can purge */
2006 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2013 /* We have to still be there! */
2014 ASSERT(Fcb
->UncleanCount
!= 0);
2015 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2017 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2019 --Fcb
->UncachedUncleanCount
;
2022 /* Inform mini-rdr about ongoing cleanup */
2023 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2025 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2026 --Fobx
->SrvOpen
->UncleanFobxCount
;
2029 if (DisableFlushOnCleanup
)
2031 /* Only if we're the last standing */
2032 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2033 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2035 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2036 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2042 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2044 DPRINT("Flushing %p on cleanup\n", Context
);
2045 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2049 /* If only remaining uncached & unclean, then flush and purge */
2050 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2052 if (Fcb
->UncachedUncleanCount
!= 0)
2054 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2055 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2057 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2058 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2063 /* If purge required, and not about to delete, flush */
2064 if (!LeftForDelete
&& NeedPurge
)
2066 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2067 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2070 /* If it was a file, drop cache */
2073 DPRINT("Uninit cache map for file\n");
2074 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2077 /* If that's the one left for deletion, or if it needs purge, flush */
2078 if (LeftForDelete
|| NeedPurge
)
2080 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2081 /* If that's for deletion, also remove from FCB table */
2084 RxRemoveNameNetFcb(Fcb
);
2085 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2086 FcbTableAcquired
= FALSE
;
2090 /* Remove any share access */
2091 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2093 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2096 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2097 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2098 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2100 NTSTATUS InternalStatus
;
2101 PRX_CONTEXT InternalContext
;
2103 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2104 InternalStatus
= STATUS_UNSUCCESSFUL
;
2105 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2106 Fcb
->RxDeviceObject
,
2107 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2108 if (InternalContext
!= NULL
)
2110 FILE_END_OF_FILE_INFORMATION FileEOF
;
2112 InternalStatus
= STATUS_SUCCESS
;
2114 /* Initialize the context for file information set */
2115 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2116 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2117 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2119 /* Get EOF from the FCB */
2120 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2121 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2122 InternalContext
->Info
.Buffer
= &FileEOF
;
2123 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2125 /* Call the mini-rdr */
2126 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2129 RxDereferenceAndDeleteRxContext(InternalContext
);
2132 /* We tried, so, clean the FOBX flag */
2133 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2134 /* If it failed, then, disable collapsing on the FCB */
2135 if (!NT_SUCCESS(InternalStatus
))
2137 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2142 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2144 FcbAcquired
= FALSE
;
2145 RxReleaseFcb(Context
, Fcb
);
2151 RxReleaseFcb(Context
, Fcb
);
2154 if (FcbTableAcquired
)
2156 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2162 #undef BugCheckFileId
2168 PRX_CONTEXT Context
)
2170 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2174 PFILE_OBJECT FileObject
;
2175 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2179 Fcb
= (PFCB
)Context
->pFcb
;
2180 Fobx
= (PFOBX
)Context
->pFobx
;
2181 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2182 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2184 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2185 if (!NT_SUCCESS(Status
))
2195 /* Check our FCB type is expected */
2196 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2197 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2198 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2200 RxBugCheck(NodeType(Fcb
), 0, 0);
2203 RxReferenceNetFcb(Fcb
);
2205 DereferenceFobx
= FALSE
;
2206 /* If we're not closing FS */
2212 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2213 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2214 /* Handle delayed close */
2215 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2217 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2219 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2221 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2223 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2225 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2227 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2231 DereferenceFobx
= TRUE
;
2232 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2239 /* If we reach maximum of delayed close/or if there are no delayed close */
2240 if (!DereferenceFobx
)
2244 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2245 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2247 /* Delete if asked */
2248 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2250 RxScavengeRelatedFobxs(Fcb
);
2251 RxSynchronizeWithScavenger(Context
);
2253 RxReleaseFcb(Context
, Fcb
);
2255 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2256 RxOrphanThisFcb(Fcb
);
2257 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2259 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2260 ASSERT(NT_SUCCESS(Status
));
2265 RxMarkFobxOnClose(Fobx
);
2268 if (DereferenceFobx
)
2270 ASSERT(Fobx
!= NULL
);
2271 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2275 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2278 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2282 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2283 AcquiredFcb
= !Freed
;
2285 FileObject
->FsContext
= (PVOID
)-1;
2289 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2293 RxReleaseFcb(Context
, Fcb
);
2294 AcquiredFcb
= FALSE
;
2299 if (_SEH2_AbnormalTermination())
2303 RxReleaseFcb(Context
, Fcb
);
2308 ASSERT(!AcquiredFcb
);
2313 DPRINT("Status: %x\n", Status
);
2315 #undef BugCheckFileId
2324 PRX_CONTEXT Context
)
2328 PFILE_OBJECT FileObject
;
2329 PIO_STACK_LOCATION Stack
;
2333 DPRINT("RxCommonCreate(%p)\n", Context
);
2335 Irp
= Context
->CurrentIrp
;
2336 Stack
= Context
->CurrentIrpSp
;
2337 FileObject
= Stack
->FileObject
;
2339 /* Check whether that's a device opening */
2340 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2342 FileObject
->FsContext
= &RxDeviceFCB
;
2343 FileObject
->FsContext2
= NULL
;
2345 ++RxDeviceFCB
.NodeReferenceCount
;
2346 ++RxDeviceFCB
.OpenCount
;
2348 Irp
->IoStatus
.Information
= FILE_OPENED
;
2349 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2351 Status
= STATUS_SUCCESS
;
2355 PFCB RelatedFcb
= NULL
;
2357 /* Make sure caller is consistent */
2358 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2359 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2361 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2362 return STATUS_INVALID_PARAMETER
;
2365 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2366 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2367 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2368 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2370 if (FileObject
->RelatedFileObject
!= NULL
)
2372 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2373 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2376 /* Going to rename? */
2377 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2379 DPRINT("TargetDir!\n");
2382 /* Copy create parameters to the context */
2383 RxCopyCreateParameters(Context
);
2385 /* If the caller wants to establish a connection, go ahead */
2386 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2388 Status
= RxCreateTreeConnect(Context
);
2392 /* Validate file name */
2393 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2394 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2395 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2397 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2398 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2399 FileObject
->FileName
.Length
);
2401 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2402 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2403 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2405 return STATUS_OBJECT_NAME_INVALID
;
2409 /* Attempt to open the file */
2412 UNICODE_STRING NetRootName
;
2414 /* Strip last \ if required */
2415 if (FileObject
->FileName
.Length
!= 0 &&
2416 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2418 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2420 return STATUS_OBJECT_NAME_INVALID
;
2423 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2424 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2427 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2429 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2432 /* Get the associated net root to opening */
2433 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2434 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2439 /* And attempt to open */
2440 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2441 if (Status
== STATUS_SHARING_VIOLATION
)
2443 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2445 /* If that happens for file creation, fail for real */
2446 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2448 Status
= STATUS_OBJECT_NAME_COLLISION
;
2452 /* Otherwise, if possible, attempt to scavenger current FOBX
2453 * to check whether a dormant FOBX is the reason for sharing violation
2455 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2456 !Context
->Create
.ScavengingAlreadyTried
)
2458 /* Only doable with a VNetRoot */
2459 if (Context
->Create
.pVNetRoot
!= NULL
)
2461 PV_NET_ROOT VNetRoot
;
2462 NT_CREATE_PARAMETERS SavedParameters
;
2464 /* Save create parameters */
2465 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2467 /* Reference the VNetRoot for the scavenging time */
2468 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2469 RxReferenceVNetRoot(VNetRoot
);
2471 /* Prepare the RX_CONTEXT for reuse */
2472 RxpPrepareCreateContextForReuse(Context
);
2473 RxReinitializeContext(Context
);
2475 /* Copy what we saved */
2476 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2478 /* And recopy what can be */
2479 RxCopyCreateParameters(Context
);
2481 /* And start purging, then scavenging FOBX */
2482 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2483 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2484 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2487 /* Ask for a second round */
2488 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2490 /* Keep track we already scavenged */
2491 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2493 /* Reference our SRV_CALL for CBS handling */
2494 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2495 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2497 /* Drop our extra reference */
2498 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2503 else if (Status
== STATUS_REPARSE
)
2505 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2509 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2512 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2515 if (Status
== STATUS_RETRY
)
2517 RxpPrepareCreateContextForReuse(Context
);
2519 ASSERT(Status
!= STATUS_PENDING
);
2522 DPRINT("Status: %lx\n", Status
);
2531 RxCommonDevFCBCleanup(
2532 PRX_CONTEXT Context
)
2539 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2541 Fcb
= Context
->pFcb
;
2542 Status
= STATUS_SUCCESS
;
2543 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2545 /* Our FOBX if set, has to be a VNetRoot */
2546 if (Context
->pFobx
!= NULL
)
2548 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2549 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2551 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2553 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2557 --Fcb
->UncleanCount
;
2568 RxCommonDevFCBClose(
2569 PRX_CONTEXT Context
)
2573 PMRX_V_NET_ROOT NetRoot
;
2577 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2579 Fcb
= Context
->pFcb
;
2580 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2581 Status
= STATUS_SUCCESS
;
2582 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2584 /* Our FOBX if set, has to be a VNetRoot */
2585 if (NetRoot
!= NULL
)
2587 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2588 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2590 --NetRoot
->NumberOfOpens
;
2591 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2595 Status
= STATUS_NOT_IMPLEMENTED
;
2597 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2609 RxCommonDevFCBFsCtl(
2610 PRX_CONTEXT Context
)
2613 return STATUS_NOT_IMPLEMENTED
;
2621 RxCommonDevFCBIoCtl(
2622 PRX_CONTEXT Context
)
2628 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2630 if (Context
->pFobx
!= NULL
)
2632 return STATUS_INVALID_HANDLE
;
2635 /* Is that a prefix claim from MUP? */
2636 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2638 return RxPrefixClaim(Context
);
2641 /* Otherwise, pass through the mini-rdr */
2642 Status
= RxXXXControlFileCallthru(Context
);
2643 if (Status
!= STATUS_PENDING
)
2645 if (Context
->PostRequest
)
2647 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2648 Status
= RxFsdPostRequest(Context
);
2652 DPRINT("Status: %lx\n", Status
);
2658 RxCommonDevFCBQueryVolInfo(
2659 PRX_CONTEXT Context
)
2662 return STATUS_NOT_IMPLEMENTED
;
2670 RxCommonDeviceControl(
2671 PRX_CONTEXT Context
)
2677 /* Prefix claim is only allowed for device, not files */
2678 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2680 return STATUS_INVALID_DEVICE_REQUEST
;
2683 /* Submit to mini-rdr */
2684 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2685 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2686 if (Status
== STATUS_PENDING
)
2688 RxDereferenceAndDeleteRxContext_Real(Context
);
2699 RxCommonDirectoryControl(
2700 PRX_CONTEXT Context
)
2705 PIO_STACK_LOCATION Stack
;
2709 Fcb
= (PFCB
)Context
->pFcb
;
2710 Fobx
= (PFOBX
)Context
->pFobx
;
2711 Stack
= Context
->CurrentIrpSp
;
2712 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2714 /* Call the appropriate helper */
2715 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2717 Status
= RxQueryDirectory(Context
);
2719 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2721 Status
= RxNotifyChangeDirectory(Context
);
2722 if (Status
== STATUS_PENDING
)
2724 RxDereferenceAndDeleteRxContext_Real(Context
);
2729 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2737 RxCommonDispatchProblem(
2738 PRX_CONTEXT Context
)
2741 return STATUS_NOT_IMPLEMENTED
;
2746 RxCommonFileSystemControl(
2747 PRX_CONTEXT Context
)
2751 PIO_STACK_LOCATION Stack
;
2755 Irp
= Context
->CurrentIrp
;
2756 Stack
= Context
->CurrentIrpSp
;
2757 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2759 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2762 return STATUS_NOT_IMPLEMENTED
;
2767 RxCommonFlushBuffers(
2768 PRX_CONTEXT Context
)
2771 return STATUS_NOT_IMPLEMENTED
;
2776 RxCommonLockControl(
2777 PRX_CONTEXT Context
)
2780 return STATUS_NOT_IMPLEMENTED
;
2786 PRX_CONTEXT Context
)
2789 return STATUS_NOT_IMPLEMENTED
;
2797 RxCommonQueryInformation(
2798 PRX_CONTEXT Context
)
2800 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2801 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2802 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2809 PIO_STACK_LOCATION Stack
;
2810 FILE_INFORMATION_CLASS FileInfoClass
;
2814 Fcb
= (PFCB
)Context
->pFcb
;
2815 Fobx
= (PFOBX
)Context
->pFobx
;
2816 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2818 Irp
= Context
->CurrentIrp
;
2819 Stack
= Context
->CurrentIrpSp
;
2820 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2821 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2823 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2824 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2831 /* Get a writable buffer */
2832 Buffer
= RxMapSystemBuffer(Context
);
2835 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2839 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2841 /* Validate file type */
2842 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2844 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2846 Status
= STATUS_INVALID_PARAMETER
;
2849 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2851 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2853 Status
= STATUS_NOT_IMPLEMENTED
;
2857 Status
= STATUS_INVALID_PARAMETER
;
2864 /* Acquire the right lock */
2865 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2866 FileInfoClass
!= FileNameInformation
)
2868 if (FileInfoClass
== FileCompressionInformation
)
2870 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2874 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2877 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2879 Status
= STATUS_PENDING
;
2882 else if (!NT_SUCCESS(Status
))
2890 /* Dispatch to the right helper */
2891 switch (FileInfoClass
)
2893 case FileBasicInformation
:
2894 Status
= RxQueryBasicInfo(Context
, Buffer
);
2897 case FileStandardInformation
:
2898 Status
= RxQueryStandardInfo(Context
, Buffer
);
2901 case FileInternalInformation
:
2902 Status
= RxQueryInternalInfo(Context
, Buffer
);
2905 case FileEaInformation
:
2906 Status
= RxQueryEaInfo(Context
, Buffer
);
2909 case FileNameInformation
:
2910 Status
= RxQueryNameInfo(Context
, Buffer
);
2913 case FileAllInformation
:
2914 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2915 if (!NT_SUCCESS(Status
))
2920 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2921 if (!NT_SUCCESS(Status
))
2926 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2927 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2928 if (!NT_SUCCESS(Status
))
2933 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2934 sizeof(FILE_STANDARD_INFORMATION
) +
2935 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2936 if (!NT_SUCCESS(Status
))
2941 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2942 sizeof(FILE_STANDARD_INFORMATION
) +
2943 sizeof(FILE_INTERNAL_INFORMATION
) +
2944 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2945 if (!NT_SUCCESS(Status
))
2950 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2951 sizeof(FILE_STANDARD_INFORMATION
) +
2952 sizeof(FILE_INTERNAL_INFORMATION
) +
2953 sizeof(FILE_EA_INFORMATION
) +
2954 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2957 case FileAlternateNameInformation
:
2958 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2961 case FilePipeInformation
:
2962 case FilePipeLocalInformation
:
2963 case FilePipeRemoteInformation
:
2964 Status
= RxQueryPipeInfo(Context
, Buffer
);
2967 case FileCompressionInformation
:
2968 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2972 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2973 Status
= Context
->IoStatusBlock
.Status
;
2977 if (Context
->Info
.Length
< 0)
2979 Status
= STATUS_BUFFER_OVERFLOW
;
2980 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2983 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2989 RxReleaseFcb(Context
, Fcb
);
2994 DPRINT("Status: %x\n", Status
);
2997 #undef SET_SIZE_AND_QUERY
3002 RxCommonQueryQuotaInformation(
3003 PRX_CONTEXT Context
)
3006 return STATUS_NOT_IMPLEMENTED
;
3011 RxCommonQuerySecurity(
3012 PRX_CONTEXT Context
)
3015 return STATUS_NOT_IMPLEMENTED
;
3023 RxCommonQueryVolumeInformation(
3024 PRX_CONTEXT Context
)
3030 PIO_STACK_LOCATION Stack
;
3034 Fcb
= (PFCB
)Context
->pFcb
;
3035 Fobx
= (PFOBX
)Context
->pFobx
;
3037 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3039 Irp
= Context
->CurrentIrp
;
3040 Stack
= Context
->CurrentIrpSp
;
3041 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3042 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3044 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3045 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3046 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3048 /* Forward to mini-rdr */
3049 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3051 /* Post request if mini-rdr asked to */
3052 if (Context
->PostRequest
)
3054 Status
= RxFsdPostRequest(Context
);
3058 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3061 DPRINT("Status: %x\n", Status
);
3068 PRX_CONTEXT RxContext
)
3076 PFILE_OBJECT FileObject
;
3077 LARGE_INTEGER ByteOffset
;
3078 PIO_STACK_LOCATION Stack
;
3079 PLOWIO_CONTEXT LowIoContext
;
3080 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3081 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3082 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3086 Fcb
= (PFCB
)RxContext
->pFcb
;
3087 Fobx
= (PFOBX
)RxContext
->pFobx
;
3088 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3090 /* Get some parameters */
3091 Irp
= RxContext
->CurrentIrp
;
3092 Stack
= RxContext
->CurrentIrpSp
;
3093 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3094 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3095 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3096 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3097 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3098 ReadLength
= Stack
->Parameters
.Read
.Length
;
3099 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3100 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3101 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3103 RxItsTheSameContext();
3105 Irp
->IoStatus
.Information
= 0;
3107 /* Should the read be loud - so far, it's just ignored on ReactOS:
3108 * s/DPRINT/DPRINT1/g will make it loud
3110 LowIoContext
= &RxContext
->LowIoContext
;
3111 CheckForLoudOperations(RxContext
);
3112 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3114 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3115 ByteOffset
, ReadLength
,
3116 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3119 RxDeviceObject
= RxContext
->RxDeviceObject
;
3121 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3123 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3125 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3127 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3129 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3133 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3137 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3141 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3145 /* A pagefile cannot be a pipe */
3146 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3147 if (IsPipe
&& PagingIo
)
3149 return STATUS_INVALID_DEVICE_REQUEST
;
3152 /* Null-length read is no-op */
3153 if (ReadLength
== 0)
3155 return STATUS_SUCCESS
;
3158 /* Validate FCB type */
3159 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3161 return STATUS_INVALID_DEVICE_REQUEST
;
3164 /* Init the lowio context for possible forward */
3165 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3167 PostRequest
= FALSE
;
3168 ReadCachingDisabled
= FALSE
;
3170 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3171 FileObject
= Stack
->FileObject
;
3172 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3177 /* If no caching, make sure current Cc data have been flushed */
3178 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3180 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3181 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3186 else if (Status
!= STATUS_SUCCESS
)
3191 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3192 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3193 RxReleasePagingIoResource(RxContext
, Fcb
);
3195 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3197 Status
= Irp
->IoStatus
.Status
;
3201 RxAcquirePagingIoResource(RxContext
, Fcb
);
3202 RxReleasePagingIoResource(RxContext
, Fcb
);
3205 /* Acquire the appropriate lock */
3206 if (PagingIo
&& !ReadCachingEnabled
)
3210 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3218 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3223 if (!ReadCachingEnabled
)
3225 if (!CanWait
&& NoCache
)
3227 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3228 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3230 DPRINT1("RdAsyLNG %x\n", RxContext
);
3234 if (Status
!= STATUS_SUCCESS
)
3236 DPRINT1("RdAsyOthr %x\n", RxContext
);
3240 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3242 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3252 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3253 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3258 else if (Status
!= STATUS_SUCCESS
)
3266 RxItsTheSameContext();
3268 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3274 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3276 /* Make sure FLOCK doesn't conflict */
3279 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3281 Status
= STATUS_FILE_LOCK_CONFLICT
;
3286 /* Validate byteoffset vs length */
3287 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3289 if (ByteOffset
.QuadPart
>= FileSize
)
3291 Status
= STATUS_END_OF_FILE
;
3295 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3297 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3302 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3303 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3305 /* File was not cached yet, do it */
3306 if (FileObject
->PrivateCacheMap
== NULL
)
3308 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3310 Status
= STATUS_FILE_CLOSED
;
3314 RxAdjustAllocationSizeforCC(Fcb
);
3316 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3317 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3319 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3321 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3325 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3326 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3329 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3332 /* This should never happen - fix your RDR */
3333 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3338 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3339 Status
= Irp
->IoStatus
.Status
;
3340 ASSERT(NT_SUCCESS(Status
));
3345 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3346 if (SystemBuffer
== NULL
)
3348 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3352 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3354 RxItsTheSameContext();
3356 /* Perform the read */
3357 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3359 if (!ReadCachingEnabled
)
3361 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3364 RxItsTheSameContext();
3370 if (!ReadCachingEnabled
)
3372 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3375 Status
= Irp
->IoStatus
.Status
;
3376 ASSERT(NT_SUCCESS(Status
));
3381 /* Validate the reading */
3382 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3383 ByteOffset
.QuadPart
>= 4096)
3385 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3386 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3389 /* If it's consistent, forward to mini-rdr */
3390 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3391 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3393 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3394 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3396 RxItsTheSameContext();
3398 if (InFsp
&& ReadCachingDisabled
)
3400 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3401 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3405 Status
= RxLowIoReadShell(RxContext
);
3407 RxItsTheSameContext();
3411 if (ByteOffset
.QuadPart
> FileSize
)
3414 Irp
->IoStatus
.Information
= ReadLength
;
3418 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3420 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3423 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3424 RtlZeroMemory(SystemBuffer
, ReadLength
);
3425 Irp
->IoStatus
.Information
= ReadLength
;
3431 RxItsTheSameContext();
3433 /* Post if required */
3436 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3437 Status
= RxFsdPostRequest(RxContext
);
3441 /* Update FO in case of sync IO */
3442 if (!IsPipe
&& !PagingIo
)
3444 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3446 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3451 /* Set FastIo if read was a success */
3452 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3454 if (!IsPipe
&& !PagingIo
)
3456 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3460 /* In case we're done (not expected any further processing */
3461 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3463 /* Release everything that can be */
3464 if (ReadCachingDisabled
)
3470 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3474 RxReleasePagingIoResource(RxContext
, Fcb
);
3481 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3485 RxReleaseFcb(RxContext
, Fcb
);
3490 /* Dereference/Delete context */
3493 RxDereferenceAndDeleteRxContext(RxContext
);
3497 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3499 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3503 /* We cannot return more than asked */
3504 if (Status
== STATUS_SUCCESS
)
3506 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3513 RxDereferenceAndDeleteRxContext(RxContext
);
3524 PRX_CONTEXT Context
)
3527 return STATUS_NOT_IMPLEMENTED
;
3535 RxCommonSetInformation(
3536 PRX_CONTEXT Context
)
3543 PIO_STACK_LOCATION Stack
;
3544 FILE_INFORMATION_CLASS Class
;
3545 BOOLEAN CanWait
, FcbTableAcquired
, FcbAcquired
;
3549 Fcb
= (PFCB
)Context
->pFcb
;
3550 Fobx
= (PFOBX
)Context
->pFobx
;
3551 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3553 Irp
= Context
->CurrentIrp
;
3554 Stack
= Context
->CurrentIrpSp
;
3555 Class
= Stack
->Parameters
.SetFile
.FileInformationClass
;
3556 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3557 Irp
->AssociatedIrp
.SystemBuffer
, Stack
->Parameters
.SetFile
.Length
,
3558 Class
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
3560 Status
= STATUS_SUCCESS
;
3561 CanWait
= BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3562 FcbTableAcquired
= FALSE
;
3563 FcbAcquired
= FALSE
;
3564 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3566 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3570 /* Valide the node type first */
3571 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3572 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3574 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
3576 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3578 Status
= STATUS_SUCCESS
;
3581 else if (NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
3583 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
3585 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3589 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb
));
3590 _SEH2_TRY_RETURN(Status
= STATUS_INVALID_PARAMETER
);
3595 /* We don't autorize advance operation */
3596 if (Class
== FileEndOfFileInformation
&& Stack
->Parameters
.SetFile
.AdvanceOnly
)
3598 DPRINT1("Not allowed\n");
3600 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3603 /* For these to classes, we'll have to deal with the FCB table (removal)
3604 * We thus need the exclusive FCB table lock
3606 if (Class
== FileDispositionInformation
|| Class
== FileRenameInformation
)
3608 RxPurgeRelatedFobxs(NetRoot
, Context
, TRUE
, Fcb
);
3609 RxScavengeFobxsForNetRoot(NetRoot
, Fcb
, TRUE
);
3611 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, CanWait
))
3613 Context
->PostRequest
= TRUE
;
3614 _SEH2_TRY_RETURN(Status
= STATUS_PENDING
);
3617 FcbTableAcquired
= TRUE
;
3620 /* Finally, if not paging file, we need exclusive FCB lock */
3621 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3623 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
3624 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3626 Context
->PostRequest
= TRUE
;
3627 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3629 else if (Status
!= STATUS_SUCCESS
)
3637 Status
= STATUS_SUCCESS
;
3639 /* And now, perform the job! */
3642 case FileBasicInformation
:
3643 Status
= RxSetBasicInfo(Context
);
3646 case FileDispositionInformation
:
3648 PFILE_DISPOSITION_INFORMATION FDI
;
3650 /* Check whether user wants deletion */
3651 FDI
= Irp
->AssociatedIrp
.SystemBuffer
;
3652 if (FDI
->DeleteFile
)
3654 /* If so, check whether it's doable */
3655 if (!MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForDelete
))
3657 Status
= STATUS_CANNOT_DELETE
;
3660 /* And if doable, already remove from FCB table */
3661 if (Status
== STATUS_SUCCESS
)
3663 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3664 RxRemoveNameNetFcb(Fcb
);
3666 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3667 FcbTableAcquired
= FALSE
;
3671 /* If it succeed, perform the operation */
3672 if (Status
== STATUS_SUCCESS
)
3674 Status
= RxSetDispositionInfo(Context
);
3680 case FilePositionInformation
:
3681 Status
= RxSetPositionInfo(Context
);
3684 case FileAllocationInformation
:
3685 Status
= RxSetAllocationInfo(Context
);
3688 case FileEndOfFileInformation
:
3689 Status
= RxSetEndOfFileInfo(Context
);
3692 case FilePipeInformation
:
3693 case FilePipeLocalInformation
:
3694 case FilePipeRemoteInformation
:
3695 Status
= RxSetPipeInfo(Context
);
3698 case FileRenameInformation
:
3699 case FileLinkInformation
:
3700 case FileMoveClusterInformation
:
3701 /* If we can wait, try to perform the operation right now */
3704 /* Of course, collapsing is not doable anymore, file is
3705 * in an inbetween state
3707 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
3709 /* Set the information */
3710 Status
= RxSetRenameInfo(Context
);
3711 /* If it succeed, drop the current entry from FCB table */
3712 if (Status
== STATUS_SUCCESS
&& Class
== FileRenameInformation
)
3714 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3715 RxRemoveNameNetFcb(Fcb
);
3717 _SEH2_TRY_RETURN(Status
);
3719 /* Can't wait? Post for async retry */
3722 Status
= RxFsdPostRequest(Context
);
3723 _SEH2_TRY_RETURN(Status
);
3727 case FileValidDataLengthInformation
:
3728 if (!MmCanFileBeTruncated(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
))
3730 Status
= STATUS_USER_MAPPED_FILE
;
3734 case FileShortNameInformation
:
3735 Status
= RxSetSimpleInfo(Context
);
3739 DPRINT1("Insupported class: %x\n", Class
);
3740 Status
= STATUS_INVALID_PARAMETER
;
3746 /* If mini-rdr was OK and wants a re-post on this, do it */
3747 if (Status
== STATUS_SUCCESS
)
3749 if (Context
->PostRequest
)
3751 Status
= RxFsdPostRequest(Context
);
3757 /* Release any acquired lock */
3760 RxReleaseFcb(Context
, Fcb
);
3763 if (FcbTableAcquired
)
3765 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3770 #undef _SEH2_TRY_RETURN
3777 RxCommonSetQuotaInformation(
3778 PRX_CONTEXT Context
)
3781 return STATUS_NOT_IMPLEMENTED
;
3786 RxCommonSetSecurity(
3787 PRX_CONTEXT Context
)
3790 return STATUS_NOT_IMPLEMENTED
;
3795 RxCommonSetVolumeInformation(
3796 PRX_CONTEXT Context
)
3799 return STATUS_NOT_IMPLEMENTED
;
3804 RxCommonUnimplemented(
3805 PRX_CONTEXT Context
)
3808 return STATUS_NOT_IMPLEMENTED
;
3814 PRX_CONTEXT RxContext
)
3822 PFILE_OBJECT FileObject
;
3823 PIO_STACK_LOCATION Stack
;
3824 LARGE_INTEGER ByteOffset
;
3825 NODE_TYPE_CODE NodeTypeCode
;
3826 PLOWIO_CONTEXT LowIoContext
;
3827 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3828 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3829 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3830 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3834 Fcb
= (PFCB
)RxContext
->pFcb
;
3835 NodeTypeCode
= NodeType(Fcb
);
3836 /* Validate FCB type */
3837 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3838 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3840 return STATUS_INVALID_DEVICE_REQUEST
;
3843 /* We'll write to file, keep track of it */
3844 Fcb
->IsFileWritten
= TRUE
;
3846 Stack
= RxContext
->CurrentIrpSp
;
3847 /* Set write through if asked */
3848 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3850 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3853 Fobx
= (PFOBX
)RxContext
->pFobx
;
3854 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3856 /* Get some parameters */
3857 Irp
= RxContext
->CurrentIrp
;
3858 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3859 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3860 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3861 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3862 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3863 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3864 WriteLength
= Stack
->Parameters
.Write
.Length
;
3865 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3866 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3867 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3869 RxItsTheSameContext();
3871 RxContext
->FcbResourceAcquired
= FALSE
;
3872 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3874 LowIoContext
= &RxContext
->LowIoContext
;
3875 CheckForLoudOperations(RxContext
);
3876 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3878 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3879 ByteOffset
, WriteLength
,
3880 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3883 RxDeviceObject
= RxContext
->RxDeviceObject
;
3885 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3887 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3889 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3891 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3893 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3897 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3901 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3905 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3909 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3910 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3911 /* Keep track for normal writes */
3912 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3921 /* Zero-length write is immediate success */
3922 if (NormalFile
&& WriteLength
== 0)
3924 return STATUS_SUCCESS
;
3927 /* Check whether we have input data */
3928 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3930 return STATUS_INVALID_PARAMETER
;
3933 /* Are we writting to EOF? */
3934 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3935 /* FIXME: validate length/offset */
3937 /* Get our SRV_OPEN in case of normal write */
3940 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3947 FileObject
= Stack
->FileObject
;
3949 /* If we have caching enabled, check whether we have to defer write */
3952 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3954 if (!CcCanIWrite(FileObject
, WriteLength
,
3955 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3956 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
3960 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3962 RxPrePostIrp(RxContext
, Irp
);
3964 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3966 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
3968 return STATUS_PENDING
;
3973 /* Initialize the low IO context for write */
3974 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
3976 /* Initialize our (many) booleans */
3977 RecursiveWriteThrough
= FALSE
;
3978 CalledByLazyWriter
= FALSE
;
3979 SwitchBackToAsync
= FALSE
;
3980 ExtendingFile
= FALSE
;
3981 ExtendingValidData
= FALSE
;
3982 UnwindOutstandingAsync
= FALSE
;
3983 ResourceOwnerSet
= FALSE
;
3985 ContextReferenced
= FALSE
;
3987 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3991 /* No volume FCB here! */
3992 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
3993 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
3994 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
3996 /* Writing to EOF on a paging file is non sense */
3997 ASSERT(!(WriteToEof
&& PagingIo
));
3999 RxItsTheSameContext();
4001 /* Start locking stuff */
4002 if (!PagingIo
&& !NoPreposting
)
4004 /* If it's already acquired, all fine */
4005 if (RxContext
->FcbResourceAcquired
)
4011 /* Otherwise, try to acquire shared (excepted for pipes) */
4014 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4017 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
4019 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
4023 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
4026 /* We'll post IRP to retry */
4027 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4030 DPRINT1("Failed to acquire lock!\n");
4031 _SEH2_TRY_RETURN(Status
);
4034 /* We'll just fail */
4035 if (Status
!= STATUS_SUCCESS
)
4037 _SEH2_TRY_RETURN(Status
);
4040 /* Resource acquired */
4041 RxContext
->FcbResourceAcquired
= TRUE
;
4044 /* At that point, resource is acquired */
4047 ASSERT(RxContext
->FcbResourceAcquired
);
4053 /* Now, check whether we have to promote shared lock */
4054 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4056 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
4063 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4064 if (RxIsFcbAcquiredShared(Fcb
) &&
4065 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
4069 RxReleaseFcb(RxContext
, Fcb
);
4070 RxContext
->FcbResourceAcquired
= FALSE
;
4072 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4073 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4076 DPRINT1("Failed to acquire lock!\n");
4077 _SEH2_TRY_RETURN(Status
);
4080 if (Status
!= STATUS_SUCCESS
)
4082 _SEH2_TRY_RETURN(Status
);
4085 RxContext
->FcbResourceAcquired
= TRUE
;
4089 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4090 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
4093 if (RxIsFcbAcquiredExclusive(Fcb
))
4095 RxConvertToSharedFcb(RxContext
, Fcb
);
4100 /* We're extending file, disable collapsing */
4101 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
4103 DPRINT("Disabling collapsing\n");
4105 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4107 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
4111 ASSERT(RxContext
->FcbResourceAcquired
);
4114 /* Keep track of the acquired resource */
4115 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
4122 /* Lock the paging resource */
4123 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
4125 /* Keep track of the acquired resource */
4126 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
4132 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
4135 /* If it's a non cached write, or if caching is disallowed */
4136 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4138 /* If cache was previously enabled, we'll have to flush before writing */
4139 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
4141 LARGE_INTEGER FlushOffset
;
4144 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
4146 /* If shared, we'll have to relock exclusive */
4147 if (!RxIsFcbAcquiredExclusive(Fcb
))
4149 /* Release and retry exclusive */
4150 RxReleaseFcb(RxContext
, Fcb
);
4151 RxContext
->FcbResourceAcquired
= FALSE
;
4153 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4154 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4157 DPRINT1("Failed to acquire lock for flush!\n");
4158 _SEH2_TRY_RETURN(Status
);
4161 if (Status
!= STATUS_SUCCESS
)
4163 _SEH2_TRY_RETURN(Status
);
4166 RxContext
->FcbResourceAcquired
= TRUE
;
4169 /* Get the length to flush */
4172 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
4176 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
4179 /* Perform the flushing */
4180 RxAcquirePagingIoResource(RxContext
, Fcb
);
4181 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
4182 WriteLength
, &Irp
->IoStatus
);
4183 RxReleasePagingIoResource(RxContext
, Fcb
);
4185 /* Cannot continue if flushing failed */
4186 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
4188 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
4192 RxAcquirePagingIoResource(RxContext
, Fcb
);
4193 RxReleasePagingIoResource(RxContext
, Fcb
);
4196 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
4197 &FlushOffset
, WriteLength
, FALSE
);
4201 /* If not paging IO, check if write is allowed */
4204 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4206 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4210 /* Get file sizes */
4211 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4212 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4213 ASSERT(ValidDataLength
<= FileSize
);
4215 /* If paging IO, we cannot write past file size
4216 * so fix write length if needed
4220 if (ByteOffset
.QuadPart
>= FileSize
)
4222 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4225 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4227 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4231 /* If we're being called by the lazywrite */
4232 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4234 CalledByLazyWriter
= TRUE
;
4236 /* Fail if we're beyong VDL */
4237 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4239 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4240 (ByteOffset
.QuadPart
< FileSize
))
4242 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4244 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4250 /* If that's a recursive synchronous page write */
4251 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4252 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4256 /* Check the top level IRP on the FastIO path */
4257 TopIrp
= RxGetTopIrpIfRdbssIrp();
4258 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4260 PIO_STACK_LOCATION IrpStack
;
4262 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4264 /* If the top level IRP was a cached write for this file, keep track */
4265 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4266 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4267 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4269 RecursiveWriteThrough
= TRUE
;
4270 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4275 /* Now, deal with file size and VDL */
4276 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4277 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4279 /* Not sync? Let's make it sync, just the time we extended */
4283 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4284 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4287 /* Keep track we'll have to switch back to async */
4290 SwitchBackToAsync
= TRUE
;
4294 /* Release all the locks */
4295 RxWriteReleaseResources(RxContext
, 0);
4297 /* Acquire exclusive */
4298 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4299 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4302 DPRINT1("Failed to acquire lock for extension!\n");
4303 _SEH2_TRY_RETURN(Status
);
4306 if (Status
!= STATUS_SUCCESS
)
4308 _SEH2_TRY_RETURN(Status
);
4311 RxContext
->FcbResourceAcquired
= TRUE
;
4313 RxItsTheSameContext();
4315 /* Get the sizes again, to be sure they didn't change in the meantime */
4316 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4317 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4318 ASSERT(ValidDataLength
<= FileSize
);
4320 /* Check we can switch back to async? */
4321 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4322 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4324 SwitchBackToAsync
= FALSE
;
4327 /* If paging IO, check we don't try to extend the file */
4330 if (ByteOffset
.QuadPart
>= FileSize
)
4332 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4335 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4337 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4342 /* Save our initial sizes for potential rollback */
4343 InitialFileSize
= FileSize
;
4344 InitialValidDataLength
= ValidDataLength
;
4345 /* If writing to EOF, update byte offset with file size */
4348 ByteOffset
.QuadPart
= FileSize
;
4351 /* Check again whether we're allowed to write */
4354 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4356 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4359 /* Do we have to extend? */
4360 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4362 DPRINT("Need to extend file\n");
4363 ExtendingFile
= TRUE
;
4364 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4368 /* Let's start to extend */
4371 /* If we're past allocating, inform mini-rdr */
4372 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4373 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4375 LARGE_INTEGER NewAllocationSize
;
4377 DPRINT("Extending %p\n", RxContext
);
4381 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4382 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4383 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4387 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4388 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4389 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4392 if (!NT_SUCCESS(Status
))
4394 _SEH2_TRY_RETURN(Status
);
4397 if (FileSize
> NewAllocationSize
.QuadPart
)
4399 NewAllocationSize
.QuadPart
= FileSize
;
4402 /* And update FCB */
4403 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4406 /* Set the new sizes */
4407 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4408 RxAdjustAllocationSizeforCC(Fcb
);
4411 if (CcIsFileCached(FileObject
))
4413 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4417 /* Do we have to extend VDL? */
4418 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4420 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4422 ExtendingValidData
= TRUE
;
4423 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4427 /* If none cached write */
4428 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4430 /* Switch back to async, if asked to */
4431 if (SwitchBackToAsync
)
4436 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4437 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4440 /* If not synchronous, keep track of writes to be finished */
4443 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4445 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4446 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4447 NotificationEvent
, FALSE
);
4450 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4452 &RxStrucSupSpinLock
) == 0)
4454 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4457 UnwindOutstandingAsync
= TRUE
;
4458 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4461 /* Set our LOWIO_CONTEXT information */
4462 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4463 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4465 RxItsTheSameContext();
4467 /* We have to be locked */
4468 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4470 /* Update thread ID if we're in FSP */
4473 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4475 if (RxContext
->FcbResourceAcquired
)
4477 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4480 if (RxContext
->FcbPagingIoResourceAcquired
)
4482 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4485 ResourceOwnerSet
= TRUE
;
4488 /* And perform the write */
4489 Status
= RxLowIoWriteShell(RxContext
);
4491 RxItsTheSameContext();
4493 /* Not outstanding write anymore */
4494 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4496 UnwindOutstandingAsync
= FALSE
;
4502 /* If cache wasn't enabled yet, do it */
4503 if (FileObject
->PrivateCacheMap
== NULL
)
4505 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4507 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4510 RxAdjustAllocationSizeforCC(Fcb
);
4512 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4513 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4515 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4518 /* If that's a MDL backed write */
4519 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4521 /* Shouldn't happen */
4525 /* Perform it, though */
4526 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4527 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4529 Status
= Irp
->IoStatus
.Status
;
4534 ULONG BreakpointsSave
;
4536 /* Map the user buffer */
4537 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4538 if (SystemBuffer
== NULL
)
4540 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4543 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4545 RxItsTheSameContext();
4547 /* And deal with Cc */
4548 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4551 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4553 RxItsTheSameContext();
4555 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4556 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4562 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4563 Irp
->IoStatus
.Information
= WriteLength
;
4565 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4567 RxItsTheSameContext();
4569 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4570 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4577 /* If we've to post the IRP */
4580 /* Reset the file size if required */
4581 if (ExtendingFile
&& !IsPipe
)
4583 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4584 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4586 RxAcquirePagingIoResource(RxContext
, Fcb
);
4587 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4588 RxReleasePagingIoResource(RxContext
, Fcb
);
4590 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4592 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4596 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4597 ContextReferenced
= TRUE
;
4600 ASSERT(!ResourceOwnerSet
);
4601 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4603 #ifdef RDBSS_TRACKER
4604 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4607 /* And post the request */
4608 Status
= RxFsdPostRequest(RxContext
);
4614 /* Update FILE_OBJECT if synchronous write succeed */
4617 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4619 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4623 /* If write succeed, ,also update FILE_OBJECT flags */
4624 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4626 /* File was modified */
4629 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4632 /* If was even extended */
4635 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4638 /* If VDL was extended, update FCB and inform Cc */
4639 if (ExtendingValidData
)
4641 LONGLONG LastOffset
;
4643 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4644 if (FileSize
< LastOffset
)
4646 LastOffset
= FileSize
;
4649 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4651 if (NoCache
&& CcIsFileCached(FileObject
))
4653 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4662 /* Finally, if we failed while extension was required */
4663 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4668 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4670 RxAcquirePagingIoResource(RxContext
, Fcb
);
4671 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4672 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4673 RxReleasePagingIoResource(RxContext
, Fcb
);
4675 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4677 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4682 /* One async write less */
4683 if (UnwindOutstandingAsync
)
4687 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4688 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4691 /* And now, cleanup everything */
4692 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4694 /* If we didn't post, release every lock (for posting, it's already done) */
4697 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4700 /* If the context was referenced - posting, dereference it */
4701 if (ContextReferenced
)
4703 RxDereferenceAndDeleteRxContext(RxContext
);
4706 /* If that's a pipe operation, resume any blocked one */
4709 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4711 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4715 /* Sanity check for write */
4716 if (Status
== STATUS_SUCCESS
)
4718 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4721 /* Just dereference our context */
4725 RxDereferenceAndDeleteRxContext(RxContext
);
4730 #undef _SEH2_TRY_RETURN
4741 IN PRX_CONTEXT RxContext
)
4744 PFILE_OBJECT FileObject
;
4745 PIO_STACK_LOCATION Stack
;
4747 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4751 Irp
= RxContext
->CurrentIrp
;
4752 Stack
= RxContext
->CurrentIrpSp
;
4753 FileObject
= Stack
->FileObject
;
4755 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4756 switch (RxContext
->MajorFunction
)
4758 /* Call the Cc function */
4760 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4764 /* If here, we can wait */
4765 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4767 /* Call the Cc function */
4768 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4770 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4774 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4775 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4780 Irp
->MdlAddress
= NULL
;
4782 /* And complete the IRP */
4783 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4785 #undef BugCheckFileId
4787 return STATUS_SUCCESS
;
4794 RxConjureOriginalName(
4797 PULONG ActualNameLength
,
4798 PWCHAR OriginalName
,
4799 PLONG LengthRemaining
,
4800 RX_NAME_CONJURING_METHODS NameConjuringMethod
)
4803 PV_NET_ROOT VNetRoot
;
4804 USHORT PrefixLength
, NameLength
, ToCopy
;
4808 VNetRoot
= Fcb
->VNetRoot
;
4809 /* We will use the prefix contained in NET_ROOT, if we don't have
4810 * a V_NET_ROOT, or if it wasn't null deviced or if we already have
4812 if (VNetRoot
== NULL
|| VNetRoot
->PrefixEntry
.Prefix
.Buffer
[1] != L
';' ||
4813 BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_UNC_NAME
))
4815 Prefix
= ((PNET_ROOT
)Fcb
->pNetRoot
)->PrefixEntry
.Prefix
.Buffer
;
4816 PrefixLength
= ((PNET_ROOT
)Fcb
->pNetRoot
)->PrefixEntry
.Prefix
.Length
;
4819 /* In that case, keep track that we will have a prefix as buffer */
4820 NameConjuringMethod
= VNetRoot_As_Prefix
;
4824 ASSERT(NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
4826 /* Otherwise, return the prefix from our V_NET_ROOT */
4827 Prefix
= VNetRoot
->PrefixEntry
.Prefix
.Buffer
;
4828 PrefixLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
;
4829 NameLength
= VNetRoot
->NamePrefix
.Length
;
4831 /* If we want a UNC path, skip potential device */
4832 if (NameConjuringMethod
== VNetRoot_As_UNC_Name
)
4837 PrefixLength
-= sizeof(WCHAR
);
4838 } while (PrefixLength
> 0 && Prefix
[0] != L
'\\');
4842 /* If we added an extra backslash, skip it */
4843 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ADDEDBACKSLASH
))
4845 NameLength
+= sizeof(WCHAR
);
4848 /* If we're asked for a drive letter, skip the prefix */
4849 if (NameConjuringMethod
== VNetRoot_As_DriveLetter
)
4853 /* And make sure we arrive at a backslash */
4854 if (Fcb
->FcbTableEntry
.Path
.Length
> NameLength
&&
4855 Fcb
->FcbTableEntry
.Path
.Buffer
[NameLength
/ sizeof(WCHAR
)] != L
'\\')
4857 NameLength
-= sizeof(WCHAR
);
4862 /* Prepare to copy the prefix, make sure not to overflow */
4863 if (*LengthRemaining
>= PrefixLength
)
4865 /* Copy everything */
4866 ToCopy
= PrefixLength
;
4867 *LengthRemaining
= *LengthRemaining
- PrefixLength
;
4871 /* Copy as much as we can */
4872 ToCopy
= *LengthRemaining
;
4873 /* And return failure */
4874 *LengthRemaining
= -1;
4877 /* Copy the prefix */
4878 RtlCopyMemory(OriginalName
, Prefix
, ToCopy
);
4881 /* Do we have a name to copy now? */
4882 if (Fcb
->FcbTableEntry
.Path
.Length
> NameLength
)
4884 ToCopy
= Fcb
->FcbTableEntry
.Path
.Length
- NameLength
;
4885 Name
= Fcb
->FcbTableEntry
.Path
.Buffer
;
4889 /* Just use slash for now */
4890 ToCopy
= sizeof(WCHAR
);
4895 /* Total length we will have in the output buffer (if everything is alright) */
4896 *ActualNameLength
= ToCopy
+ PrefixLength
;
4897 /* If we still have room to write data */
4898 if (*LengthRemaining
!= -1)
4900 /* If we can copy everything, it's fine! */
4901 if (*LengthRemaining
> ToCopy
)
4903 *LengthRemaining
= *LengthRemaining
- ToCopy
;
4905 /* Otherwise, copy as much as possible, and return failure */
4908 ToCopy
= *LengthRemaining
;
4909 *LengthRemaining
= -1;
4912 /* Copy name after the prefix */
4913 RtlCopyMemory(Add2Ptr(OriginalName
, PrefixLength
),
4914 Add2Ptr(Name
, NameLength
), ToCopy
);
4922 RxCopyCreateParameters(
4923 IN PRX_CONTEXT RxContext
)
4927 PFILE_OBJECT FileObject
;
4928 PIO_STACK_LOCATION Stack
;
4929 PDFS_NAME_CONTEXT DfsNameContext
;
4930 PIO_SECURITY_CONTEXT SecurityContext
;
4932 Irp
= RxContext
->CurrentIrp
;
4933 Stack
= RxContext
->CurrentIrpSp
;
4934 FileObject
= Stack
->FileObject
;
4935 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4937 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4938 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4940 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4941 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4942 RxContext
->Create
.SdLength
);
4944 if (SecurityContext
->SecurityQos
!= NULL
)
4946 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4950 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4952 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4954 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4955 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4956 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4957 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4958 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4960 DfsContext
= FileObject
->FsContext2
;
4961 DfsNameContext
= FileObject
->FsContext
;
4962 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4963 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4964 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4965 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4966 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4967 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4968 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4969 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4970 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4971 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4972 FileObject
->FsContext2
= NULL
;
4973 FileObject
->FsContext
= NULL
;
4975 RxContext
->pFcb
= NULL
;
4976 RxContext
->Create
.ReturnedCreateInformation
= 0;
4978 /* if we stripped last \, it has to be a directory! */
4979 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4981 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4984 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4985 if (RxContext
->Create
.EaLength
== 0)
4987 RxContext
->Create
.EaBuffer
= NULL
;
4991 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4992 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4997 RxCreateFromNetRoot(
4998 PRX_CONTEXT Context
,
4999 PUNICODE_STRING NetRootName
)
5004 PFILE_OBJECT FileObject
;
5005 PIO_STACK_LOCATION Stack
;
5006 ACCESS_MASK DesiredAccess
;
5007 USHORT DesiredShareAccess
;
5011 /* Validate that the context is consistent */
5012 if (Context
->Create
.pNetRoot
== NULL
)
5014 return STATUS_BAD_NETWORK_PATH
;
5017 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
5018 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
5020 return STATUS_BAD_NETWORK_PATH
;
5023 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
5024 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
5026 return STATUS_DFS_UNAVAILABLE
;
5029 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
5030 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
5032 return STATUS_OBJECT_TYPE_MISMATCH
;
5035 Stack
= Context
->CurrentIrpSp
;
5036 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
5037 if (NetRoot
->Type
== NET_ROOT_PRINT
)
5039 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
5042 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
5044 /* Get file object */
5045 FileObject
= Stack
->FileObject
;
5047 /* Do we have to open target directory for renaming? */
5048 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
5050 DPRINT("Opening target directory\n");
5052 /* If we have been asked for delete, try to purge first */
5053 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
))
5055 RxPurgeRelatedFobxs((PNET_ROOT
)Context
->Create
.pVNetRoot
->pNetRoot
, Context
,
5056 ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
5059 /* Create the FCB */
5060 Fcb
= RxCreateNetFcb(Context
, (PV_NET_ROOT
)Context
->Create
.pVNetRoot
, NetRootName
);
5063 return STATUS_INSUFFICIENT_RESOURCES
;
5066 /* Fake it: it will be used only renaming */
5067 NodeType(Fcb
) = RDBSS_NTC_OPENTARGETDIR_FCB
;
5068 Context
->Create
.FcbAcquired
= FALSE
;
5069 Context
->Create
.NetNamePrefixEntry
= NULL
;
5071 /* Assign it to the FO */
5072 FileObject
->FsContext
= Fcb
;
5074 /* If we have a FOBX already, check whether it's for DFS opening */
5075 if (Context
->pFobx
!= NULL
)
5077 /* If so, reflect this in the FOBX */
5078 if (FileObject
->FsContext2
== UIntToPtr(DFS_OPEN_CONTEXT
))
5080 SetFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
5084 ClearFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
5088 /* Acquire the FCB */
5089 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
5090 if (Status
!= STATUS_SUCCESS
)
5095 /* Reference the FCB and release */
5096 RxReferenceNetFcb(Fcb
);
5097 RxReleaseFcb(Context
, Fcb
);
5100 return STATUS_SUCCESS
;
5103 /* Try to find (or create) the FCB for the file */
5104 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
5105 Fcb
= (PFCB
)Context
->pFcb
;
5108 ASSERT(!NT_SUCCESS(Status
));
5110 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
5115 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
5117 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
5121 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
5124 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
5125 if (NT_SUCCESS(Status
))
5127 RxTransitionNetFcb(Fcb
, Condition_Good
);
5128 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
5130 RxSetupNetFileObject(Context
);
5131 return STATUS_SUCCESS
;
5135 /* Check SA for conflict */
5136 if (Fcb
->OpenCount
> 0)
5138 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5139 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
5140 if (!NT_SUCCESS(Status
))
5142 RxDereferenceNetFcb(Fcb
);
5147 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
5148 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
5155 /* Find a SRV_OPEN that suits the opening */
5156 Status
= RxCollapseOrCreateSrvOpen(Context
);
5157 if (Status
== STATUS_SUCCESS
)
5162 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
5163 Fobx
= (PFOBX
)Context
->pFobx
;
5164 /* There are already opens, check for conflict */
5165 if (Fcb
->OpenCount
!= 0)
5167 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
5168 FileObject
, &Fcb
->ShareAccess
,
5169 FALSE
, "second check per useropens",
5172 ++SrvOpen
->UncleanFobxCount
;
5173 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
5180 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
5182 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5183 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
5187 RxSetupNetFileObject(Context
);
5189 /* No conflict? Set up SA */
5190 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
5192 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
5195 ++Fcb
->UncleanCount
;
5196 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
5198 ++Fcb
->UncachedUncleanCount
;
5201 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
5202 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
5204 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
5207 /* No pending close, we're active */
5208 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
5211 ++SrvOpen
->UncleanFobxCount
;
5212 ++SrvOpen
->OpenCount
;
5213 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
5215 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
5217 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
5218 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
5220 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
5221 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
5223 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5226 /* Now, update SA for the SRV_OPEN */
5227 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
5229 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
5231 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
5234 /* Update the FOBX info */
5237 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5239 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
5242 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
5243 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5245 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
5247 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
5248 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
5250 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
5251 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
5252 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
5254 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
5255 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
5259 Status
= STATUS_SUCCESS
;
5264 if (Fcb
->OpenCount
== 0)
5266 if (Context
->Create
.FcbAcquired
)
5268 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
5272 if (!Context
->Create
.FcbAcquired
)
5274 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
5280 RxDereferenceNetFcb(Fcb
);
5292 RxCreateTreeConnect(
5293 IN PRX_CONTEXT RxContext
)
5296 PV_NET_ROOT VNetRoot
;
5297 PFILE_OBJECT FileObject
;
5298 PIO_STACK_LOCATION Stack
;
5299 NET_ROOT_TYPE NetRootType
;
5300 UNICODE_STRING CanonicalName
, RemainingName
;
5304 Stack
= RxContext
->CurrentIrpSp
;
5305 FileObject
= Stack
->FileObject
;
5307 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
5308 /* As long as we don't know connection type, mark it wild */
5309 NetRootType
= NET_ROOT_WILD
;
5310 /* Get the type by parsing the name */
5311 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
5312 if (!NT_SUCCESS(Status
))
5317 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
5318 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
5319 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
5320 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
5321 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
5322 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
5324 /* We don't handle EA - they come from DFS, don't care */
5325 if (Stack
->Parameters
.Create
.EaLength
> 0)
5330 /* Mount if required */
5331 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5332 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
5334 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
5335 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5338 if (!NT_SUCCESS(Status
))
5343 /* Validate the rest of the name with mini-rdr */
5344 if (RemainingName
.Length
> 0)
5346 MINIRDR_CALL(Status
, RxContext
,
5347 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5348 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
5351 if (!NT_SUCCESS(Status
))
5356 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5357 RxReferenceVNetRoot(VNetRoot
);
5358 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
5360 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
5363 FileObject
->FsContext
= &RxDeviceFCB
;
5364 FileObject
->FsContext2
= VNetRoot
;
5366 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
5367 ++VNetRoot
->NumberOfOpens
;
5369 /* Create is over - clear context */
5370 RxContext
->Create
.pSrvCall
= NULL
;
5371 RxContext
->Create
.pNetRoot
= NULL
;
5372 RxContext
->Create
.pVNetRoot
= NULL
;
5379 RxDebugControlCommand(
5380 _In_ PSTR ControlString
)
5388 IN PDRIVER_OBJECT DriverObject
,
5389 IN PUNICODE_STRING RegistryPath
)
5392 USHORT i
, State
= 0;
5394 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
5398 RxCheckFcbStructuresForAlignment();
5400 RtlZeroMemory(&RxData
, sizeof(RxData
));
5401 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
5402 RxData
.NodeByteSize
= sizeof(RxData
);
5403 RxData
.DriverObject
= DriverObject
;
5405 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
5406 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
5407 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5409 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5410 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5412 RxInitializeDebugSupport();
5414 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5415 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5420 RxGetRegistryParameters(RegistryPath
);
5421 RxReadRegistryParameters();
5423 Status
= RxInitializeRegistrationStructures();
5424 if (!NT_SUCCESS(Status
))
5430 RxInitializeDispatcher();
5432 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5434 InitializeListHead(&RxIrpsList
);
5435 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5437 InitializeListHead(&RxActiveContexts
);
5438 InitializeListHead(&RxSrvCalldownList
);
5440 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5441 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5442 KeInitializeMutex(&RxScavengerMutex
, 1);
5443 KeInitializeMutex(&RxSerializationMutex
, 1);
5445 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5447 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5448 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5449 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5452 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5454 RxInitializeDispatchVectors(DriverObject
);
5456 ExInitializeResourceLite(&RxData
.Resource
);
5457 RxData
.OurProcess
= IoGetCurrentProcess();
5459 RxInitializeRxTimer();
5463 if (!NT_SUCCESS(Status
))
5465 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5466 RxInitUnwind(DriverObject
, State
);
5470 /* There are still bits to init - be consider it's fine for now */
5473 return STATUS_NOT_IMPLEMENTED
;
5475 return STATUS_SUCCESS
;
5484 RxDumpCurrentAccess(
5487 _In_ PSZ wherelogtag
,
5488 _In_ PSHARE_ACCESS ShareAccess
)
5500 _In_ PSZ wherelogtag
,
5501 _In_ ACCESS_MASK DesiredAccess
,
5502 _In_ ULONG DesiredShareAccess
)
5513 RxFastIoCheckIfPossible(
5514 PFILE_OBJECT FileObject
,
5515 PLARGE_INTEGER FileOffset
,
5516 ULONG Length
, BOOLEAN Wait
,
5517 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5518 PIO_STATUS_BLOCK IoStatus
,
5519 PDEVICE_OBJECT DeviceObject
)
5523 LARGE_INTEGER LargeLength
;
5527 /* Get the FCB to validate it */
5528 Fcb
= FileObject
->FsContext
;
5529 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5531 DPRINT1("Not a file, FastIO not possible!\n");
5535 if (FileObject
->DeletePending
)
5537 DPRINT1("File delete pending\n");
5541 /* If there's a pending write operation, deny fast operation */
5542 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5544 DPRINT1("Write operations to be completed\n");
5548 /* Deny read on orphaned node */
5549 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5550 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5552 DPRINT1("SRV_OPEN orphaned\n");
5556 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5558 DPRINT1("FCB orphaned\n");
5562 /* If there's a buffering state change pending, deny fast operation (it might change
5565 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5567 DPRINT1("Buffering change pending\n");
5571 /* File got renamed/deleted, deny operation */
5572 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5573 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5575 DPRINT1("File renamed/deleted\n");
5579 /* Process pending change buffering state operations */
5580 FsRtlEnterFileSystem();
5581 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5582 FsRtlExitFileSystem();
5584 LargeLength
.QuadPart
= Length
;
5586 /* If operation to come is a read operation */
5587 if (CheckForReadOperation
)
5589 /* Check that read cache is enabled */
5590 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5592 DPRINT1("Read caching disabled\n");
5596 /* Check whether there's a lock conflict */
5597 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5602 PsGetCurrentProcess()))
5604 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5611 /* Check that write cache is enabled */
5612 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
))
5614 DPRINT1("Write caching disabled\n");
5618 /* Check whether there's a lock conflict */
5619 if (!FsRtlFastCheckLockForWrite(&Fcb
->Specific
.Fcb
.FileLock
,
5624 PsGetCurrentProcess()))
5626 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5635 RxFastIoDeviceControl(
5636 PFILE_OBJECT FileObject
,
5638 PVOID InputBuffer OPTIONAL
,
5639 ULONG InputBufferLength
,
5640 PVOID OutputBuffer OPTIONAL
,
5641 ULONG OutputBufferLength
,
5642 ULONG IoControlCode
,
5643 PIO_STATUS_BLOCK IoStatus
,
5644 PDEVICE_OBJECT DeviceObject
)
5646 /* Only supported IOCTL */
5647 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5664 PFILE_OBJECT FileObject
,
5665 PLARGE_INTEGER FileOffset
,
5670 PIO_STATUS_BLOCK IoStatus
,
5671 PDEVICE_OBJECT DeviceObject
)
5674 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5678 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5679 FileObject
->FsContext2
);
5680 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5682 /* Prepare a TLI context */
5683 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5684 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5685 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5687 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5688 IoStatus
, DeviceObject
, &TopLevelContext
);
5691 DPRINT("Read OK\n");
5695 DPRINT1("Read failed!\n");
5707 PFILE_OBJECT FileObject
,
5708 PLARGE_INTEGER FileOffset
,
5713 PIO_STATUS_BLOCK IoStatus
,
5714 PDEVICE_OBJECT DeviceObject
)
5718 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5722 Fobx
= (PFOBX
)FileObject
->FsContext2
;
5723 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_BAD_HANDLE
))
5728 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5729 FileObject
->FsContext2
);
5730 DPRINT("Writing %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5732 /* Prepare a TLI context */
5733 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5734 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5735 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5737 Ret
= FsRtlCopyWrite2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5738 IoStatus
, DeviceObject
, &TopLevelContext
);
5741 DPRINT("Write OK\n");
5745 DPRINT1("Write failed!\n");
5753 PRX_CONTEXT RxContext
,
5754 PUNICODE_STRING NetRootName
)
5760 PV_NET_ROOT VNetRoot
;
5761 BOOLEAN TableAcquired
, AcquiredExclusive
;
5765 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5766 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5767 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5769 Status
= STATUS_SUCCESS
;
5770 AcquiredExclusive
= FALSE
;
5772 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5773 TableAcquired
= TRUE
;
5774 Version
= NetRoot
->FcbTable
.Version
;
5776 /* Look for a cached FCB */
5777 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5780 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5784 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5785 /* If FCB was to be orphaned, consider it as not suitable */
5786 if (Fcb
->fShouldBeOrphaned
)
5788 RxDereferenceNetFcb(Fcb
);
5789 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5791 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5792 TableAcquired
= TRUE
;
5793 AcquiredExclusive
= TRUE
;
5795 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5796 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5798 RxOrphanThisFcb(Fcb
);
5799 RxDereferenceNetFcb(Fcb
);
5805 /* If FCB was not found or is not covering full path, prepare for more work */
5806 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5810 DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb
->FcbTableEntry
.Path
, NetRootName
);
5813 if (!AcquiredExclusive
)
5815 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5816 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5817 TableAcquired
= TRUE
;
5820 /* If FCB table was updated in between, re-attempt a lookup */
5821 if (NetRoot
->FcbTable
.Version
!= Version
)
5823 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5824 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5831 /* Allocate the FCB */
5836 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5839 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5843 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5844 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5850 if (_SEH2_AbnormalTermination())
5852 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5853 TableAcquired
= FALSE
;
5857 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5859 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5860 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5862 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5871 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5874 if (!NT_SUCCESS(Status
))
5879 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5880 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5882 if (!RxContext
->Create
.FcbAcquired
)
5884 RxWaitForStableNetFcb(Fcb
, RxContext
);
5885 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5886 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5893 RxFirstCanonicalize(
5894 PRX_CONTEXT RxContext
,
5895 PUNICODE_STRING FileName
,
5896 PUNICODE_STRING CanonicalName
,
5897 PNET_ROOT_TYPE NetRootType
)
5901 BOOLEAN UncName
, PrependString
, IsSpecial
;
5902 USHORT CanonicalLength
;
5903 UNICODE_STRING SessionIdString
;
5904 WCHAR SessionIdBuffer
[16];
5908 Type
= NET_ROOT_WILD
;
5909 PrependString
= FALSE
;
5912 Status
= STATUS_SUCCESS
;
5914 /* Name has to contain at least \\ */
5915 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5917 return STATUS_OBJECT_NAME_INVALID
;
5920 /* First easy check, is that a path with a name? */
5921 CanonicalLength
= FileName
->Length
;
5922 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5924 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5926 if (FileName
->Buffer
[3] == ':')
5928 Type
= NET_ROOT_DISK
;
5932 Type
= NET_ROOT_PRINT
;
5937 /* Nope, attempt deeper parsing */
5938 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5941 PWSTR FirstSlash
, EndOfString
;
5943 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5946 /* The lack of drive letter will be replaced by session ID */
5947 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5948 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5949 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5951 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5952 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5954 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5960 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5962 Status
= STATUS_OBJECT_NAME_INVALID
;
5967 DPRINT1("WARNING: Assuming not special + disk!\n");
5968 Type
= NET_ROOT_DISK
;
5969 Status
= STATUS_SUCCESS
;
5970 //Status = STATUS_NOT_IMPLEMENTED;
5971 /* Should be check against IPC, mailslot, and so on */
5975 /* Update net root type with our deduced one */
5976 *NetRootType
= Type
;
5977 DPRINT("Returning type: %x\n", Type
);
5979 if (!NT_SUCCESS(Status
))
5984 /* Do we have to prepend session ID? */
5989 PrependString
= TRUE
;
5990 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5994 /* If not UNC path, we should preprend stuff */
5995 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5997 return STATUS_OBJECT_PATH_INVALID
;
6000 /* Allocate the buffer */
6001 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
6002 if (!NT_SUCCESS(Status
))
6007 /* We don't support that case, we always return disk */
6010 ASSERT(CanonicalName
->Length
== CanonicalLength
);
6012 Status
= STATUS_NOT_IMPLEMENTED
;
6016 /* If we have to prepend, go ahead */
6019 CanonicalName
->Buffer
[0] = '\\';
6020 CanonicalName
->Buffer
[1] = ';';
6021 CanonicalName
->Buffer
[2] = ':';
6022 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
6023 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
6024 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
6026 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
6028 /* Otherwise, that's a simple copy */
6031 RtlCopyUnicodeString(CanonicalName
, FileName
);
6042 RxFreeCanonicalNameBuffer(
6043 PRX_CONTEXT Context
)
6045 /* These two buffers are always the same */
6046 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
6048 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
6050 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
6051 Context
->Create
.CanonicalNameBuffer
= NULL
;
6052 Context
->AlsoCanonicalNameBuffer
= NULL
;
6055 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
6059 RxFsdCommonDispatch(
6060 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
6061 UCHAR MajorFunction
,
6062 PIO_STACK_LOCATION Stack
,
6063 PFILE_OBJECT FileObject
,
6065 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
6069 PRX_CONTEXT Context
;
6070 UCHAR MinorFunction
;
6071 PFILE_OBJECT StackFileObject
;
6072 PRX_FSD_DISPATCH DispatchFunc
;
6073 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6074 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
6076 Status
= STATUS_SUCCESS
;
6078 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
6080 FsRtlEnterFileSystem();
6082 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
6088 PostRequest
= FALSE
;
6089 SetCancelRoutine
= TRUE
;
6090 MinorFunction
= Stack
->MinorFunction
;
6092 switch (MajorFunction
)
6094 case IRP_MJ_FILE_SYSTEM_CONTROL
:
6095 if (FileObject
!= NULL
)
6097 CanWait
= IoIsOperationSynchronous(Irp
);
6107 case IRP_MJ_QUERY_INFORMATION
:
6108 case IRP_MJ_SET_INFORMATION
:
6109 case IRP_MJ_QUERY_EA
:
6111 case IRP_MJ_FLUSH_BUFFERS
:
6112 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
6113 case IRP_MJ_SET_VOLUME_INFORMATION
:
6114 case IRP_MJ_DIRECTORY_CONTROL
:
6115 case IRP_MJ_DEVICE_CONTROL
:
6116 case IRP_MJ_LOCK_CONTROL
:
6117 case IRP_MJ_QUERY_SECURITY
:
6118 case IRP_MJ_SET_SECURITY
:
6119 CanWait
= IoIsOperationSynchronous(Irp
);
6123 case IRP_MJ_CLEANUP
:
6125 SetCancelRoutine
= FALSE
;
6132 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
6133 /* Should we stop it right now, or mini-rdr deserves to know? */
6134 PassToDriver
= TRUE
;
6135 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
6137 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
6139 PassToDriver
= FALSE
;
6140 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6141 DPRINT1("Not started!\n");
6146 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
6148 PassToDriver
= FALSE
;
6149 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6150 DPRINT1("Not started!\n");
6153 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
6155 StackFileObject
= Stack
->FileObject
;
6156 /* Make sure we don't deal with orphaned stuff */
6157 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
6159 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
6160 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
6161 StackFileObject
->FsContext
!= &RxDeviceFCB
)
6166 Fcb
= StackFileObject
->FsContext
;
6167 Fobx
= StackFileObject
->FsContext2
;
6169 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
6170 ((Fobx
!= NULL
) && BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
)))
6174 PassToDriver
= TRUE
;
6178 PassToDriver
= FALSE
;
6179 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
6180 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
6186 /* Did we receive a close request whereas we're stopping? */
6187 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
6191 Fcb
= StackFileObject
->FsContext
;
6193 DPRINT1("Close received after stop\n");
6194 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6195 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
6197 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
6200 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6201 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
6205 /* Should we stop the whole thing now? */
6208 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
6210 IoMarkIrpPending(Irp
);
6211 Irp
->IoStatus
.Status
= Status
;
6212 Irp
->IoStatus
.Information
= 0;
6213 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6214 Status
= STATUS_PENDING
;
6218 Irp
->IoStatus
.Status
= Status
;
6219 Irp
->IoStatus
.Information
= 0;
6220 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6226 /* No? Allocate a context to deal with the mini-rdr */
6227 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
6228 if (Context
== NULL
)
6230 Status
= STATUS_INSUFFICIENT_RESOURCES
;
6231 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
6235 /* Set cancel routine if required */
6236 if (SetCancelRoutine
)
6238 IoAcquireCancelSpinLock(&OldIrql
);
6239 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
6243 IoAcquireCancelSpinLock(&OldIrql
);
6244 IoSetCancelRoutine(Irp
, NULL
);
6246 IoReleaseCancelSpinLock(OldIrql
);
6248 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6250 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6251 Irp
->IoStatus
.Information
= 0;
6252 /* Get the dispatch routine */
6253 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
6255 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
6257 /* Handle the complete MDL case */
6258 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
6260 DispatchFunc
= RxCompleteMdl
;
6264 /* Do we have to post request? */
6265 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
6271 /* Our read function needs stack, make sure we won't overflow,
6272 * otherwise, post the request
6274 if (MajorFunction
== IRP_MJ_READ
)
6276 if (IoGetRemainingStackSize() < 0xE00)
6278 Context
->PendingReturned
= TRUE
;
6279 Status
= RxPostStackOverflowRead(Context
);
6280 if (Status
!= STATUS_PENDING
)
6282 Context
->PendingReturned
= FALSE
;
6283 RxCompleteAsynchronousRequest(Context
, Status
);
6293 Context
->ResumeRoutine
= DispatchFunc
;
6294 /* There's a dispatch routine? Time to dispatch! */
6295 if (DispatchFunc
!= NULL
)
6297 Context
->PendingReturned
= TRUE
;
6300 Status
= RxFsdPostRequest(Context
);
6304 /* Retry as long as we have */
6307 Status
= DispatchFunc(Context
);
6309 while (Status
== STATUS_RETRY
);
6311 if (Status
== STATUS_PENDING
)
6316 /* Sanity check: did someone mess with our context? */
6317 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
6318 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
6320 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
6321 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
6322 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
6323 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
6324 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
6326 Context
->PendingReturned
= FALSE
;
6327 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
6332 Status
= STATUS_NOT_IMPLEMENTED
;
6339 RxUnwindTopLevelIrp(&TopLevelContext
);
6342 FsRtlExitFileSystem();
6346 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
6356 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
6360 PIO_STACK_LOCATION Stack
;
6361 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
6365 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
6367 Stack
= IoGetCurrentIrpStackLocation(Irp
);
6369 /* Dispatch easy case */
6370 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
6372 return RxSystemControl(RxDeviceObject
, Irp
);
6375 /* Bail out broken cases */
6376 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
6377 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
6379 IoMarkIrpPending(Irp
);
6380 Irp
->IoStatus
.Information
= 0;
6381 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
6382 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6383 return STATUS_PENDING
;
6386 /* Immediately handle create */
6387 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
6389 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6392 /* If not a creation, we must have at least a FO with a FCB */
6393 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
6395 IoMarkIrpPending(Irp
);
6396 Irp
->IoStatus
.Information
= 0;
6397 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6398 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6399 return STATUS_PENDING
;
6402 /* Set the dispatch vector if required */
6403 Fcb
= Stack
->FileObject
->FsContext
;
6404 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
6406 DispatchVector
= &RxFsdDispatchVector
[0];
6410 DispatchVector
= Fcb
->PrivateDispatchVector
;
6413 /* Device cannot accept such requests */
6414 if (RxDeviceObject
== RxFileSystemDeviceObject
)
6416 IoMarkIrpPending(Irp
);
6417 Irp
->IoStatus
.Information
= 0;
6418 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6419 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6420 return STATUS_PENDING
;
6423 /* Dispatch for real! */
6424 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6432 IN PRX_CONTEXT RxContext
)
6434 /* Initialize posting if required */
6435 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
6437 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
6440 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6441 RxContext
->MinorFunction
, RxContext
,
6442 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6443 RxContext
->SerialNumber
);
6445 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
6446 return STATUS_PENDING
;
6458 WORK_QUEUE_TYPE Queue
;
6459 PRDBSS_DEVICE_OBJECT VolumeDO
;
6460 PRX_CONTEXT RxContext
, EntryContext
;
6464 RxContext
= Context
;
6465 EntryContext
= Context
;
6466 /* Save IRQL at entry for later checking */
6467 EntryIrql
= KeGetCurrentIrql();
6469 /* No FO, deal with device */
6470 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6472 VolumeDO
= RxFileSystemDeviceObject
;
6479 /* Which queue to used for delayed? */
6480 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6482 Queue
= DelayedWorkQueue
;
6486 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6487 Queue
= CriticalWorkQueue
;
6494 BOOLEAN RecursiveCall
;
6495 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6497 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6498 ASSERT(!RxContext
->PostRequest
);
6500 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6501 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6503 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext
->MinorFunction
,
6504 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6505 RxContext
->SerialNumber
);
6507 Irp
= RxContext
->CurrentIrp
;
6509 FsRtlEnterFileSystem();
6511 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6512 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6513 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6514 RxContext
->RxDeviceObject
, TRUE
);
6516 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6518 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6520 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6521 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6524 /* Call the resume routine */
6529 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6531 Status
= RxContext
->ResumeRoutine(RxContext
);
6532 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6534 if (Status
!= STATUS_RETRY
)
6536 Status
= RxCompleteRequest(RxContext
, Status
);
6540 while (Status
== STATUS_RETRY
);
6542 RxUnwindTopLevelIrp(&TopLevelContext
);
6543 FsRtlExitFileSystem();
6545 if (VolumeDO
!= NULL
)
6547 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6553 } while (RxContext
!= NULL
);
6555 /* Did we mess with IRQL? */
6556 if (KeGetCurrentIrql() >= APC_LEVEL
)
6558 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6566 RxGetNetworkProviderPriority(
6567 PUNICODE_STRING DeviceName
)
6578 RxGetRegistryParameters(
6579 IN PUNICODE_STRING RegistryPath
)
6583 UCHAR Buffer
[0x400];
6584 HANDLE DriverHandle
, KeyHandle
;
6585 UNICODE_STRING KeyName
, OutString
;
6586 OBJECT_ATTRIBUTES ObjectAttributes
;
6590 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6591 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6592 if (!NT_SUCCESS(Status
))
6597 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6598 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6599 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6600 if (NT_SUCCESS(Status
))
6602 /* The only parameter we deal with is InitialDebugString */
6603 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6604 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6609 Read
= OutString
.Buffer
;
6610 Write
= (PSTR
)OutString
.Buffer
;
6611 for (i
= 0; i
< OutString
.Length
; ++i
)
6619 /* Which is a string we'll just write out */
6620 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6621 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6627 ZwClose(DriverHandle
);
6635 IN PIO_STACK_LOCATION IrpSp
)
6638 PACCESS_TOKEN Token
;
6639 PIO_SECURITY_CONTEXT SecurityContext
;
6643 /* If that's not a prefix claim, not an open request, session id will be 0 */
6644 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6646 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6651 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6655 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6658 /* Query the session id */
6659 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6660 SeQuerySessionIdToken(Token
, &SessionId
);
6670 RxGetStringRegistryParameter(
6671 IN HANDLE KeyHandle
,
6673 OUT PUNICODE_STRING OutString
,
6675 IN ULONG BufferLength
,
6676 IN BOOLEAN LogFailure
)
6680 UNICODE_STRING KeyString
;
6684 RtlInitUnicodeString(&KeyString
, KeyName
);
6685 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6686 OutString
->Length
= 0;
6687 OutString
->Buffer
= 0;
6688 if (!NT_SUCCESS(Status
))
6692 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6698 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6699 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6700 OutString
->MaximumLength
= OutString
->Length
;
6702 return STATUS_SUCCESS
;
6708 PRDBSS_DEVICE_OBJECT
6709 RxGetTopDeviceObjectIfRdbssIrp(
6713 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6715 TopLevelIrp
= IoGetTopLevelIrp();
6716 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6718 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6728 RxGetTopIrpIfRdbssIrp(
6732 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6734 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6735 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6737 Irp
= TopLevel
->Irp
;
6748 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6751 PACCESS_TOKEN Token
;
6755 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6756 SeQueryAuthenticationIdToken(Token
, &Luid
);
6763 RxIndicateChangeOfBufferingStateForSrvOpen(
6764 PMRX_SRV_CALL SrvCall
,
6765 PMRX_SRV_OPEN SrvOpen
,
6777 RxInitializeDispatchVectors(
6778 PDRIVER_OBJECT DriverObject
)
6784 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6786 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6789 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6790 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6791 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6793 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6794 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6795 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6796 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6797 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6798 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6799 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6800 RxFastIoDispatch
.FastIoLock
= NULL
;
6801 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6802 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6803 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6804 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6805 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6806 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6807 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6808 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6810 RxInitializeTopLevelIrpPackage();
6812 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6813 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6814 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6815 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6817 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6818 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6819 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6820 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6829 return STATUS_NOT_IMPLEMENTED
;
6836 RxInitializeMinirdrDispatchTable(
6837 IN PDRIVER_OBJECT DriverObject
)
6847 RxInitializeRegistrationStructures(
6852 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6853 RxData
.NumberOfMinirdrsRegistered
= 0;
6854 RxData
.NumberOfMinirdrsStarted
= 0;
6855 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6857 return STATUS_SUCCESS
;
6865 RxInitializeTopLevelIrpPackage(
6868 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6869 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6875 PDRIVER_OBJECT DriverObject
,
6885 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6886 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6889 PLIST_ENTRY NextEntry
;
6890 BOOLEAN Found
= FALSE
;
6891 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6893 /* Browse all the allocated TLC to find ours */
6894 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6895 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6896 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6897 NextEntry
= NextEntry
->Flink
)
6899 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6900 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6901 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6904 if (ListContext
== TopLevelContext
)
6910 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6924 /* No associated SRV_OPEN, it's OK to purge */
6925 if (IsListEmpty(&Fcb
->SrvOpenList
))
6930 /* Only allow to purge if all the associated SRV_OPEN
6931 * - have no outstanding opens ongoing
6932 * - have only read attribute set
6934 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6935 Entry
!= &Fcb
->SrvOpenList
;
6936 Entry
= Entry
->Flink
)
6940 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6942 /* Failing previous needs, don't allow purge */
6943 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6944 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6950 /* All correct, allow purge */
6958 RxIsThisAnRdbssTopLevelContext(
6959 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6961 ULONG_PTR StackTop
, StackBottom
;
6963 /* Bail out for flags */
6964 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6969 /* Is our provided TLC allocated on stack? */
6970 IoGetStackLimits(&StackTop
, &StackBottom
);
6971 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6972 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6974 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6975 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6983 /* No, use the helper function */
6984 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6991 RxIsThisTheTopLevelIrp(
6996 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6997 TopLevelIrp
= IoGetTopLevelIrp();
6998 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
7000 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
7003 return (TopLevelIrp
== Irp
);
7008 RxLockOperationCompletion(
7013 return STATUS_NOT_IMPLEMENTED
;
7022 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
7023 IN PUNICODE_STRING OriginatorId
,
7028 PUNICODE_STRING Originator
= OriginatorId
;
7029 LARGE_INTEGER LargeLine
;
7031 /* Set optional parameters */
7032 LargeLine
.QuadPart
= Line
;
7033 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
7035 Originator
= (PUNICODE_STRING
)&unknownId
;
7039 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
7044 RxLogEventWithAnnotation(
7045 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
7048 IN PVOID DataBuffer
,
7049 IN USHORT DataBufferLength
,
7050 IN PUNICODE_STRING Annotation
,
7051 IN ULONG AnnotationCount
)
7059 PRX_CONTEXT RxContext
)
7062 return STATUS_NOT_IMPLEMENTED
;
7070 RxLowIoIoCtlShellCompletion(
7071 PRX_CONTEXT RxContext
)
7078 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
7080 Irp
= RxContext
->CurrentIrp
;
7081 Status
= RxContext
->IoStatusBlock
.Status
;
7083 /* Set information and status */
7084 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
7086 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7089 Irp
->IoStatus
.Status
= Status
;
7095 RxLowIoLockControlShell(
7096 IN PRX_CONTEXT RxContext
)
7099 return STATUS_NOT_IMPLEMENTED
;
7107 RxLowIoNotifyChangeDirectoryCompletion(
7108 PRX_CONTEXT RxContext
)
7112 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
7114 /* Just copy back the IO_STATUS to the IRP */
7115 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
7116 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
7118 return RxContext
->IoStatusBlock
.Status
;
7126 PRX_CONTEXT RxContext
)
7133 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
7135 Fcb
= (PFCB
)RxContext
->pFcb
;
7136 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7138 return STATUS_MORE_PROCESSING_REQUIRED
;
7141 /* Always update stats for disks */
7142 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7144 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7147 /* And forward the read to the mini-rdr */
7148 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
7149 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
7156 RxLowIoReadShellCompletion(
7157 PRX_CONTEXT RxContext
)
7162 BOOLEAN PagingIo
, IsPipe
;
7163 PIO_STACK_LOCATION Stack
;
7164 PLOWIO_CONTEXT LowIoContext
;
7168 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
7170 Status
= RxContext
->IoStatusBlock
.Status
;
7171 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7173 Irp
= RxContext
->CurrentIrp
;
7174 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7176 /* Set IRP information from the RX_CONTEXT status block */
7177 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7179 /* Fixup status for paging file if nothing was read */
7182 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
7184 Status
= STATUS_END_OF_FILE
;
7188 LowIoContext
= &RxContext
->LowIoContext
;
7189 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7191 /* Check broken cases that should never happen */
7192 Fcb
= (PFCB
)RxContext
->pFcb
;
7193 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
7195 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
7198 return STATUS_RETRY
;
7201 else if (Status
== STATUS_SUCCESS
)
7203 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
7205 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
7206 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
7212 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7218 /* Readahead should go through Cc and not finish here */
7219 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
7221 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7222 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7227 Stack
= RxContext
->CurrentIrpSp
;
7228 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
7229 /* Release lock if required */
7232 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7236 /* Set FastIo if read was a success */
7237 if (NT_SUCCESS(Status
) && !IsPipe
)
7239 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
7242 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7244 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
7248 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7257 /* Final sanity checks */
7258 ASSERT(Status
!= STATUS_RETRY
);
7259 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
7260 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
7270 IN PRX_CONTEXT RxContext
)
7277 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
7279 Fcb
= (PFCB
)RxContext
->pFcb
;
7281 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7282 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7284 /* Always update stats for disks */
7285 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7287 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7290 /* And forward the write to the mini-rdr */
7291 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
7292 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
7299 RxLowIoWriteShellCompletion(
7300 PRX_CONTEXT RxContext
)
7306 PLOWIO_CONTEXT LowIoContext
;
7310 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
7312 Status
= RxContext
->IoStatusBlock
.Status
;
7313 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7315 Irp
= RxContext
->CurrentIrp
;
7317 /* Set IRP information from the RX_CONTEXT status block */
7318 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7320 LowIoContext
= &RxContext
->LowIoContext
;
7321 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7323 /* Perform a few sanity checks */
7324 Fcb
= (PFCB
)RxContext
->pFcb
;
7325 if (Status
== STATUS_SUCCESS
)
7327 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
7329 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7330 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7333 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
7336 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7337 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
7339 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
7342 /* In case of async call, perform last bits not done in RxCommonWrite */
7343 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7345 PFILE_OBJECT FileObject
;
7346 PIO_STACK_LOCATION Stack
;
7348 /* We only succeed if we wrote what was asked for */
7349 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7351 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
7354 /* If write succeed, ,also update FILE_OBJECT flags */
7355 Stack
= RxContext
->CurrentIrpSp
;
7356 FileObject
= Stack
->FileObject
;
7359 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
7362 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
7364 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
7367 /* If VDL was extended, fix attributes */
7368 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
7370 LONGLONG LastOffset
, FileSize
;
7372 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
7373 Irp
->IoStatus
.Information
;
7374 RxGetFileSizeWithLock(Fcb
, &FileSize
);
7376 if (FileSize
< LastOffset
)
7378 LastOffset
= FileSize
;
7381 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
7384 /* One less outstanding write */
7385 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7387 PNON_PAGED_FCB NonPagedFcb
;
7389 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
7390 if (NonPagedFcb
!= NULL
)
7392 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
7393 -1, &RxStrucSupSpinLock
) == 1)
7395 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
7400 /* Release paging resource if acquired */
7401 if (RxContext
->FcbPagingIoResourceAcquired
)
7403 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7406 /* Resume blocked operations for pipes */
7407 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7409 RxResumeBlockedOperations_Serially(RxContext
,
7410 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
7414 /* And release FCB only for files */
7415 if (RxContext
->FcbResourceAcquired
)
7417 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7421 /* Final sanity checks */
7422 ASSERT(Status
!= STATUS_RETRY
);
7423 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
7424 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
7426 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7439 RxNotifyChangeDirectory(
7440 PRX_CONTEXT RxContext
)
7444 PIO_STACK_LOCATION Stack
;
7448 /* The IRP can abviously wait */
7449 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
7451 /* Initialize its lowio */
7452 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
7456 /* Lock user buffer */
7457 Stack
= RxContext
->CurrentIrpSp
;
7458 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
7460 /* Copy parameters from IO_STACK */
7461 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
7462 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7463 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7465 /* If we have an associated MDL */
7466 Irp
= RxContext
->CurrentIrp
;
7467 if (Irp
->MdlAddress
!= NULL
)
7469 /* Then, call mini-rdr */
7470 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7471 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7473 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7477 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7482 Status
= STATUS_INVALID_PARAMETER
;
7495 RxPostStackOverflowRead (
7496 IN PRX_CONTEXT RxContext
)
7501 return STATUS_NOT_IMPLEMENTED
;
7508 RxpPrepareCreateContextForReuse(
7509 PRX_CONTEXT RxContext
)
7511 /* Reuse can only happen for open operations (STATUS_RETRY) */
7512 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7514 /* Release the FCB if it was acquired */
7515 if (RxContext
->Create
.FcbAcquired
)
7517 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7518 RxContext
->Create
.FcbAcquired
= FALSE
;
7521 /* Free the canonical name */
7522 RxFreeCanonicalNameBuffer(RxContext
);
7524 /* If we have a VNetRoot associated */
7525 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7527 /* Remove our link and thus, dereference the VNetRoot */
7528 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7529 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7531 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7532 RxContext
->Create
.pVNetRoot
= NULL
;
7534 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7537 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7544 RxpQueryInfoMiniRdr(
7545 PRX_CONTEXT RxContext
,
7546 FILE_INFORMATION_CLASS FileInfoClass
,
7552 Fcb
= (PFCB
)RxContext
->pFcb
;
7554 /* Set the RX_CONTEXT */
7555 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7556 RxContext
->Info
.Buffer
= Buffer
;
7559 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7569 IN PRX_CONTEXT RxContext
)
7573 NET_ROOT_TYPE NetRootType
;
7574 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7578 Irp
= RxContext
->CurrentIrp
;
7580 /* This has to come from MUP */
7581 if (Irp
->RequestorMode
== UserMode
)
7583 return STATUS_INVALID_DEVICE_REQUEST
;
7586 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7588 PQUERY_PATH_REQUEST QueryRequest
;
7590 /* Get parameters */
7591 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7593 /* Don't overflow allocation */
7594 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7596 return STATUS_INVALID_DEVICE_REQUEST
;
7599 /* Forcefully rewrite IRP MJ */
7600 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7602 /* Fake canon name */
7603 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7604 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7606 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7610 /* Copy the prefix to look for */
7611 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7612 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7613 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7615 /* Zero the create parameters */
7616 RtlZeroMemory(&RxContext
->Create
,
7617 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7618 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7619 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7623 /* If not devcontrol, it comes from open, name was already copied */
7624 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7625 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7628 /* Canonilize name */
7629 NetRootType
= NET_ROOT_WILD
;
7630 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7631 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7632 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7633 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7634 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7635 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7636 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7637 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7638 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7639 if (NT_SUCCESS(Status
))
7641 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7643 if (Status
== STATUS_PENDING
)
7648 if (NT_SUCCESS(Status
))
7650 PQUERY_PATH_RESPONSE QueryResponse
;
7652 /* We accept the length that was canon (minus netroot) */
7653 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7654 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7658 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7659 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7661 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7663 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7666 RxpPrepareCreateContextForReuse(RxContext
);
7668 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7679 RxPrepareToReparseSymbolicLink(
7680 PRX_CONTEXT RxContext
,
7681 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7682 PUNICODE_STRING NewPath
,
7683 BOOLEAN NewPathIsAbsolute
,
7684 PBOOLEAN ReparseRequired
)
7688 PFILE_OBJECT FileObject
;
7690 /* Assume no reparse is required first */
7691 *ReparseRequired
= FALSE
;
7693 /* Only supported for IRP_MJ_CREATE */
7694 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
)
7696 return STATUS_INVALID_PARAMETER
;
7699 /* If symbolic link is not embedded, and DELETE is specified, fail */
7700 if (!SymbolicLinkEmbeddedInOldPath
)
7702 /* Excepted if DELETE is the only flag specified, then, open has to succeed
7703 * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7705 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
) &&
7706 BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, ~DELETE
))
7708 return STATUS_ACCESS_DENIED
;
7712 /* At that point, assume reparse will be required */
7713 *ReparseRequired
= TRUE
;
7715 /* If new path isn't absolute, it's up to us to make it absolute */
7716 if (!NewPathIsAbsolute
)
7718 /* The prefix will be \Device\Mup */
7719 NewLength
= NewPath
->Length
+ (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
));
7720 NewBuffer
= ExAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, NewLength
,
7722 if (NewBuffer
== NULL
)
7724 return STATUS_INSUFFICIENT_RESOURCES
;
7727 /* Copy data for the new path */
7728 RtlMoveMemory(NewBuffer
, L
"\\Device\\Mup", (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
)));
7729 RtlMoveMemory(Add2Ptr(NewBuffer
, (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
))),
7730 NewPath
->Buffer
, NewPath
->Length
);
7732 /* Otherwise, use caller path as it */
7735 NewLength
= NewPath
->Length
;
7736 NewBuffer
= NewPath
->Buffer
;
7739 /* Get the FILE_OBJECT we'll modify */
7740 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
7742 /* Free old path first */
7743 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
7744 /* And setup new one */
7745 FileObject
->FileName
.Length
= NewLength
;
7746 FileObject
->FileName
.MaximumLength
= NewLength
;
7747 FileObject
->FileName
.Buffer
= NewBuffer
;
7749 /* And set reparse flag */
7750 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
);
7753 return STATUS_SUCCESS
;
7764 LOCK_OPERATION Lock
;
7765 PIO_STACK_LOCATION Stack
;
7766 PRX_CONTEXT RxContext
= Context
;
7768 /* NULL IRP is no option */
7774 /* Check whether preparation was really needed */
7775 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7779 /* Mark the context as prepared */
7780 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7782 /* Just lock the user buffer, with the correct length, depending on the MJ */
7783 Lock
= IoReadAccess
;
7784 Stack
= RxContext
->CurrentIrpSp
;
7785 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7787 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7789 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7791 Lock
= IoWriteAccess
;
7793 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7798 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7799 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7801 Lock
= IoWriteAccess
;
7802 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7804 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7806 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7810 /* As it will be posted (async), mark the IRP pending */
7811 IoMarkIrpPending(Irp
);
7819 PRX_CONTEXT RxContext
,
7820 FILE_INFORMATION_CLASS Class
)
7825 /* Initialize parameters in RX_CONTEXT */
7826 RxContext
->Info
.FileInformationClass
= Class
;
7827 RxContext
->Info
.Buffer
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
7828 RxContext
->Info
.Length
= RxContext
->CurrentIrpSp
->Parameters
.SetFile
.Length
;
7830 /* And call mini-rdr */
7831 Fcb
= (PFCB
)RxContext
->pFcb
;
7832 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
7839 RxpUnregisterMinirdr(
7840 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7851 PRX_CONTEXT LocalContext
)
7858 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7860 /* And force close */
7861 RxReleaseFcb(NULL
, Fcb
);
7862 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7863 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7864 ASSERT(Status
== STATUS_SUCCESS
);
7868 RxQueryAlternateNameInfo(
7869 PRX_CONTEXT RxContext
,
7870 PFILE_NAME_INFORMATION AltNameInfo
)
7873 return STATUS_NOT_IMPLEMENTED
;
7881 PRX_CONTEXT RxContext
,
7882 PFILE_BASIC_INFORMATION BasicInfo
)
7886 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7888 /* Simply zero and forward to mini-rdr */
7889 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7890 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7894 RxQueryCompressedInfo(
7895 PRX_CONTEXT RxContext
,
7896 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7899 return STATUS_NOT_IMPLEMENTED
;
7907 PRX_CONTEXT RxContext
)
7914 BOOLEAN LockNotGranted
;
7915 ULONG Length
, FileIndex
;
7916 PUNICODE_STRING FileName
;
7917 PIO_STACK_LOCATION Stack
;
7918 FILE_INFORMATION_CLASS FileInfoClass
;
7922 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7924 /* Get parameters */
7925 Stack
= RxContext
->CurrentIrpSp
;
7926 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7927 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7928 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7929 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7930 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7931 FileName
, FileInfoClass
);
7933 Irp
= RxContext
->CurrentIrp
;
7934 Flags
= Stack
->Flags
;
7935 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7936 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7938 if (FileName
!= NULL
)
7940 DPRINT("FileName: %wZ\n", FileName
);
7943 /* No FOBX: not a standard file/directory */
7944 Fobx
= (PFOBX
)RxContext
->pFobx
;
7947 return STATUS_OBJECT_NAME_INVALID
;
7950 /* We can only deal with a disk */
7951 Fcb
= (PFCB
)RxContext
->pFcb
;
7952 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7954 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7955 return STATUS_INVALID_DEVICE_REQUEST
;
7958 /* Setup RX_CONTEXT related fields */
7959 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7960 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7961 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7962 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7963 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7965 /* We don't support (yet?) a specific index being set */
7966 if (RxContext
->QueryDirectory
.IndexSpecified
)
7968 return STATUS_NOT_IMPLEMENTED
;
7971 /* Try to lock FCB */
7972 LockNotGranted
= TRUE
;
7973 if (RxContext
->QueryDirectory
.InitialQuery
)
7975 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7976 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7978 if (!NT_SUCCESS(Status
))
7983 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7985 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7986 RxConvertToSharedFcb(RxContext
, Fcb
);
7989 LockNotGranted
= FALSE
;
7994 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7995 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7997 if (!NT_SUCCESS(Status
))
8002 LockNotGranted
= FALSE
;
8006 /* If it failed, post request */
8009 return RxFsdPostRequest(RxContext
);
8012 /* This cannot be done on a orphaned directory */
8013 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
8015 RxReleaseFcb(RxContext
, Fcb
);
8016 return STATUS_FILE_CLOSED
;
8022 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
8024 RxContext
->QueryDirectory
.FileIndex
= 0;
8027 /* Assume success */
8028 Status
= STATUS_SUCCESS
;
8029 /* If initial query, prepare FOBX */
8030 if (RxContext
->QueryDirectory
.InitialQuery
)
8032 /* We cannot have a template already! */
8033 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
8035 /* If we have a file name and a correct one, duplicate it in the FOBX */
8036 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
8037 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
8038 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
8039 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
8041 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
8043 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
8044 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
8046 /* UNICODE_STRING; length has to be even */
8047 if ((FileName
->Length
& 1) != 0)
8049 Status
= STATUS_INVALID_PARAMETER
;
8050 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
8054 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
8055 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
8056 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
8058 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
8063 Status
= STATUS_INSUFFICIENT_RESOURCES
;
8066 /* No name specified, or a match all wildcard? Match everything */
8069 Fobx
->ContainsWildCards
= TRUE
;
8071 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
8072 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
8073 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
8075 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
8078 /* No need for exclusive any longer */
8079 if (NT_SUCCESS(Status
))
8081 RxConvertToSharedFcb(RxContext
, Fcb
);
8085 /* Lock user buffer and forward to mini-rdr */
8086 if (NT_SUCCESS(Status
))
8088 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
8089 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
8090 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
8091 RxContext
->Info
.Length
= Length
;
8093 if (RxContext
->Info
.Buffer
!= NULL
)
8095 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
8098 /* Post if mini-rdr asks to */
8099 if (RxContext
->PostRequest
)
8101 RxFsdPostRequest(RxContext
);
8105 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
8111 RxReleaseFcb(RxContext
, Fcb
);
8120 PRX_CONTEXT RxContext
,
8121 PFILE_EA_INFORMATION EaInfo
)
8124 return STATUS_NOT_IMPLEMENTED
;
8128 RxQueryInternalInfo(
8129 PRX_CONTEXT RxContext
,
8130 PFILE_INTERNAL_INFORMATION InternalInfo
)
8133 return STATUS_NOT_IMPLEMENTED
;
8141 PRX_CONTEXT RxContext
,
8142 PFILE_NAME_INFORMATION NameInfo
)
8148 DPRINT("RxQueryNameInfo(%p, %p)\n", RxContext
, NameInfo
);
8150 /* Check we can at least copy name size */
8151 if (RxContext
->Info
.LengthRemaining
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
))
8153 DPRINT1("Buffer too small: %d\n", RxContext
->Info
.LengthRemaining
);
8154 RxContext
->Info
.Length
= 0;
8155 return STATUS_BUFFER_OVERFLOW
;
8158 RxContext
->Info
.LengthRemaining
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
8160 Fcb
= (PFCB
)RxContext
->pFcb
;
8161 Fobx
= (PFOBX
)RxContext
->pFobx
;
8162 /* Get the UNC name */
8163 RxConjureOriginalName(Fcb
, Fobx
, &NameInfo
->FileNameLength
, &NameInfo
->FileName
[0],
8164 &RxContext
->Info
.Length
, VNetRoot_As_UNC_Name
);
8166 /* If RxConjureOriginalName returned a negative len (-1) then output buffer
8167 * was too small, return the appropriate length & status.
8169 if (RxContext
->Info
.LengthRemaining
< 0)
8171 DPRINT1("Buffer too small!\n");
8172 RxContext
->Info
.Length
= 0;
8173 return STATUS_BUFFER_OVERFLOW
;
8177 return STATUS_SUCCESS
;
8182 PRX_CONTEXT RxContext
,
8183 PFILE_PIPE_INFORMATION PipeInfo
)
8186 return STATUS_NOT_IMPLEMENTED
;
8190 RxQueryPositionInfo(
8191 PRX_CONTEXT RxContext
,
8192 PFILE_POSITION_INFORMATION PositionInfo
)
8195 return STATUS_NOT_IMPLEMENTED
;
8202 RxQueryStandardInfo(
8203 PRX_CONTEXT RxContext
,
8204 PFILE_STANDARD_INFORMATION StandardInfo
)
8212 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
8214 /* Zero output buffer */
8215 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
8217 Fcb
= (PFCB
)RxContext
->pFcb
;
8218 Fobx
= (PFOBX
)RxContext
->pFobx
;
8219 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8220 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
8221 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8223 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8226 /* Otherwise, fill what we can already */
8227 Status
= STATUS_SUCCESS
;
8228 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
8229 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8230 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
8231 if (StandardInfo
->NumberOfLinks
== 0)
8233 StandardInfo
->NumberOfLinks
= 1;
8236 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
8238 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
8239 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
8242 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8243 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
8245 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8249 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
8260 RxReadRegistryParameters(
8267 UNICODE_STRING KeyName
, ParamName
;
8268 OBJECT_ATTRIBUTES ObjectAttributes
;
8269 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
8273 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8274 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
8275 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
8276 if (!NT_SUCCESS(Status
))
8281 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
8282 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
8283 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8284 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8286 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
8289 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
8290 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8291 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8293 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
8295 if (Granularity
> 16)
8300 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
8303 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
8304 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8305 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8307 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
8319 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
8320 IN OUT PDRIVER_OBJECT DriverObject
,
8321 IN PMINIRDR_DISPATCH MrdrDispatch
,
8323 IN PUNICODE_STRING DeviceName
,
8324 IN ULONG DeviceExtensionSize
,
8325 IN DEVICE_TYPE DeviceType
,
8326 IN ULONG DeviceCharacteristics
)
8329 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
8335 return STATUS_INVALID_PARAMETER
;
8338 /* Create device object with provided parameters */
8339 Status
= IoCreateDevice(DriverObject
,
8340 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
8343 DeviceCharacteristics
,
8345 (PDEVICE_OBJECT
*)&RDBSSDevice
);
8346 if (!NT_SUCCESS(Status
))
8351 if (!RxData
.DriverObject
)
8353 return STATUS_UNSUCCESSFUL
;
8356 /* Initialize our DO extension */
8357 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
8358 ++RxFileSystemDeviceObject
->ReferenceCount
;
8359 *DeviceObject
= RDBSSDevice
;
8360 RDBSSDevice
->RdbssExports
= &RxExports
;
8361 RDBSSDevice
->Dispatch
= MrdrDispatch
;
8362 RDBSSDevice
->RegistrationControls
= Controls
;
8363 RDBSSDevice
->DeviceName
= *DeviceName
;
8364 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
8365 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
8366 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
8367 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
8368 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
8369 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
8370 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
8372 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
8374 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
8375 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
8376 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
8378 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8379 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
8381 RxInitializeMinirdrDispatchTable(DriverObject
);
8384 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8385 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
8387 LARGE_INTEGER ScavengerTimeLimit
;
8389 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
8390 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
8391 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
8392 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
8393 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
8394 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
8397 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
8399 return STATUS_SUCCESS
;
8406 RxRemoveFromTopLevelIrpAllocatedContextsList(
8407 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8411 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8412 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8413 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8415 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
8416 RemoveEntryList(&TopLevelContext
->ListEntry
);
8417 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
8424 RxRemoveOverflowEntry(
8425 PRDBSS_DEVICE_OBJECT DeviceObject
,
8426 WORK_QUEUE_TYPE Queue
)
8429 PRX_CONTEXT Context
;
8431 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
8432 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
8434 /* No entries left, nothing to return */
8435 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
8442 /* Decrement count */
8443 --DeviceObject
->OverflowQueueCount
[Queue
];
8446 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
8447 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
8448 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
8449 Context
->OverflowListEntry
.Flink
= NULL
;
8451 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
8461 RxRemoveShareAccess(
8462 _Inout_ PFILE_OBJECT FileObject
,
8463 _Inout_ PSHARE_ACCESS ShareAccess
,
8465 _In_ PSZ wherelogtag
)
8469 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8470 IoRemoveShareAccess(FileObject
, ShareAccess
);
8471 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8479 RxRemoveShareAccessPerSrvOpens(
8480 IN OUT PSRV_OPEN SrvOpen
)
8482 ACCESS_MASK DesiredAccess
;
8484 BOOLEAN WriteAccess
;
8485 BOOLEAN DeleteAccess
;
8489 /* Get access that were granted to SRV_OPEN */
8490 DesiredAccess
= SrvOpen
->DesiredAccess
;
8491 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
8492 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
8493 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
8495 /* If any, drop them */
8496 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
8499 BOOLEAN SharedWrite
;
8500 BOOLEAN SharedDelete
;
8501 ULONG DesiredShareAccess
;
8502 PSHARE_ACCESS ShareAccess
;
8504 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
8505 DesiredShareAccess
= SrvOpen
->ShareAccess
;
8507 ShareAccess
->Readers
-= ReadAccess
;
8508 ShareAccess
->Writers
-= WriteAccess
;
8509 ShareAccess
->Deleters
-= DeleteAccess
;
8511 ShareAccess
->OpenCount
--;
8513 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
8514 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
8515 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
8516 ShareAccess
->SharedRead
-= SharedRead
;
8517 ShareAccess
->SharedWrite
-= SharedWrite
;
8518 ShareAccess
->SharedDelete
-= SharedDelete
;
8523 RxSearchForCollapsibleOpen(
8524 PRX_CONTEXT RxContext
,
8525 ACCESS_MASK DesiredAccess
,
8530 PLIST_ENTRY ListEntry
;
8531 BOOLEAN ShouldTry
, Purged
, Scavenged
;
8535 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext
, DesiredAccess
, ShareAccess
);
8537 Fcb
= (PFCB
)RxContext
->pFcb
;
8539 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8540 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8542 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8544 RxScavengeRelatedFobxs(Fcb
);
8545 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8547 return STATUS_NOT_FOUND
;
8550 /* If basic open, ask the mini-rdr if we should try to collapse */
8551 if (RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN
||
8552 RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN_IF
)
8556 if (Fcb
->MRxDispatch
!= NULL
)
8558 ASSERT(RxContext
->pRelevantSrvOpen
== NULL
);
8559 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8561 ShouldTry
= NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
));
8569 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
))
8574 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8577 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
)))
8579 return STATUS_NOT_FOUND
;
8582 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8584 RxScavengeRelatedFobxs(Fcb
);
8585 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8587 return STATUS_NOT_FOUND
;
8590 /* Only collapse for matching NET_ROOT & disks */
8591 if (Fcb
->pNetRoot
!= RxContext
->Create
.pNetRoot
||
8592 Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
8594 return STATUS_NOT_FOUND
;
8599 Status
= STATUS_NOT_FOUND
;
8601 /* Browse all our SRV_OPEN to find the matching one */
8602 for (ListEntry
= Fcb
->SrvOpenList
.Flink
;
8603 ListEntry
!= &Fcb
->SrvOpenList
;
8604 ListEntry
= ListEntry
->Flink
)
8608 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
8609 /* Not the same VNET_ROOT, move to the next one */
8610 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8612 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8616 /* Is there a sharing violation? */
8617 if (SrvOpen
->DesiredAccess
!= DesiredAccess
|| SrvOpen
->ShareAccess
!= ShareAccess
||
8618 BooleanFlagOn(SrvOpen
->Flags
, (SRVOPEN_FLAG_CLOSED
| SRVOPEN_FLAG_COLLAPSING_DISABLED
| SRVOPEN_FLAG_FILE_DELETED
| SRVOPEN_FLAG_FILE_RENAMED
)))
8620 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8622 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8626 /* Check against the SRV_OPEN */
8627 Status
= RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
);
8628 if (!NT_SUCCESS(Status
))
8635 /* Don't allow collaspse for reparse point opening */
8636 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
^ SrvOpen
->CreateOptions
, FILE_OPEN_REPARSE_POINT
))
8640 Status
= STATUS_NOT_FOUND
;
8644 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8645 if (DisableByteRangeLockingOnReadOnlyFiles
|| !BooleanFlagOn(SrvOpen
->pFcb
->Attributes
, FILE_ATTRIBUTE_READONLY
))
8647 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
8649 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8650 if (NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
)))
8652 /* Is close delayed - great reuse*/
8653 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
8655 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen
);
8656 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
8657 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
8660 return STATUS_SUCCESS
;
8663 Status
= STATUS_NOT_FOUND
;
8668 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8669 if (ListEntry
== &Fcb
->SrvOpenList
)
8671 Status
= STATUS_NOT_FOUND
;
8674 /* Only required access: read attributes? Don't reuse */
8675 if ((DesiredAccess
& 0xFFEFFFFF) == FILE_READ_ATTRIBUTES
)
8677 return STATUS_NOT_FOUND
;
8680 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8683 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8685 RxScavengeRelatedFobxs(Fcb
);
8689 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8690 if (!Purged
&& RxIsOkToPurgeFcb(Fcb
))
8692 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8697 /* If sharing violation, keep track of it */
8698 if (Status
== STATUS_SHARING_VIOLATION
)
8700 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8703 DPRINT("Status: %x\n", Status
);
8708 RxSetAllocationInfo(
8709 PRX_CONTEXT RxContext
)
8712 return STATUS_NOT_IMPLEMENTED
;
8720 PRX_CONTEXT RxContext
)
8726 #define FILE_ATTRIBUTE_VOLUME 0x8
8727 #define VALID_FILE_ATTRIBUTES ( \
8728 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8729 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8730 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8731 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8732 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8733 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8734 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8735 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8737 /* First of all, call the mini-rdr */
8738 Status
= RxpSetInfoMiniRdr(RxContext
, FileBasicInformation
);
8739 /* If it succeed, perform last bits */
8740 if (NT_SUCCESS(Status
))
8745 PFILE_OBJECT FileObject
;
8746 ULONG Attributes
, CleanAttr
;
8747 PFILE_BASIC_INFORMATION BasicInfo
;
8749 Fcb
= (PFCB
)RxContext
->pFcb
;
8750 Fobx
= (PFOBX
)RxContext
->pFobx
;
8751 Irp
= RxContext
->CurrentIrp
;
8752 BasicInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
8753 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8755 /* If caller provided flags, handle the change */
8756 Attributes
= BasicInfo
->FileAttributes
;
8757 if (Attributes
!= 0)
8759 /* Clean our flags first, with only stuff we support */
8760 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
8762 CleanAttr
= (Attributes
& VALID_DIR_ATTRIBUTES
) | FILE_ATTRIBUTE_DIRECTORY
;
8766 CleanAttr
= Attributes
& VALID_FILE_ATTRIBUTES
;
8769 /* Handle the temporary mark (set/unset depending on caller) */
8770 if (BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_TEMPORARY
))
8772 SetFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8773 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8777 ClearFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8778 ClearFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8781 /* And set new attributes */
8782 Fcb
->Attributes
= CleanAttr
;
8785 /* If caller provided a creation time, set it */
8786 if (BasicInfo
->CreationTime
.QuadPart
!= 0LL)
8788 Fcb
->CreationTime
.QuadPart
= BasicInfo
->CreationTime
.QuadPart
;
8789 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_CREATION
);
8792 /* If caller provided a last access time, set it */
8793 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0LL)
8795 Fcb
->LastAccessTime
.QuadPart
= BasicInfo
->LastAccessTime
.QuadPart
;
8796 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
);
8799 /* If caller provided a last write time, set it */
8800 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0LL)
8802 Fcb
->LastWriteTime
.QuadPart
= BasicInfo
->LastWriteTime
.QuadPart
;
8803 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
8806 /* If caller provided a last change time, set it */
8807 if (BasicInfo
->ChangeTime
.QuadPart
!= 0LL)
8809 Fcb
->LastChangeTime
.QuadPart
= BasicInfo
->ChangeTime
.QuadPart
;
8810 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
8822 RxSetDispositionInfo(
8823 PRX_CONTEXT RxContext
)
8829 /* First, make the mini-rdr work! */
8830 Status
= RxpSetInfoMiniRdr(RxContext
, FileDispositionInformation
);
8831 /* If it succeed, we'll keep track of the change */
8832 if (NT_SUCCESS(Status
))
8835 PFILE_OBJECT FileObject
;
8836 PFILE_DISPOSITION_INFORMATION FileDispo
;
8838 Fcb
= (PFCB
)RxContext
->pFcb
;
8839 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8840 FileDispo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8841 /* Caller asks for deletion: mark as delete on close */
8842 if (FileDispo
->DeleteFile
)
8844 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8845 FileObject
->DeletePending
= TRUE
;
8847 /* Otherwise, clear it */
8850 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8851 FileObject
->DeletePending
= FALSE
;
8854 /* Sanitize output */
8855 Status
= STATUS_SUCCESS
;
8863 PRX_CONTEXT RxContext
)
8866 return STATUS_NOT_IMPLEMENTED
;
8871 PRX_CONTEXT RxContext
)
8874 return STATUS_NOT_IMPLEMENTED
;
8879 PRX_CONTEXT RxContext
)
8882 return STATUS_NOT_IMPLEMENTED
;
8890 PRX_CONTEXT RxContext
)
8894 PFCB RenameFcb
, Fcb
;
8895 PIO_STACK_LOCATION Stack
;
8896 PFILE_RENAME_INFORMATION RenameInfo
, UserInfo
;
8900 DPRINT("RxSetRenameInfo(%p)\n", RxContext
);
8902 Stack
= RxContext
->CurrentIrpSp
;
8903 DPRINT("FO: %p, Replace: %d\n", Stack
->Parameters
.SetFile
.FileObject
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
8905 /* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
8906 RxContext
->Info
.ReplaceIfExists
= Stack
->Parameters
.SetFile
.ReplaceIfExists
;
8907 if (Stack
->Parameters
.SetFile
.FileObject
== NULL
)
8909 return RxpSetInfoMiniRdr(RxContext
, Stack
->Parameters
.SetFile
.FileInformationClass
);
8912 Fcb
= (PFCB
)RxContext
->pFcb
;
8913 RenameFcb
= Stack
->Parameters
.SetFile
.FileObject
->FsContext
;
8914 /* First, validate the received file object */
8915 ASSERT(NodeType(RenameFcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
);
8916 if (Fcb
->pNetRoot
!= RenameFcb
->pNetRoot
)
8918 DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb
, Fcb
->pNetRoot
, Fcb
->pNetRoot
->pNetRootName
, RenameFcb
, RenameFcb
->pNetRoot
, RenameFcb
->pNetRoot
->pNetRootName
);
8919 return STATUS_NOT_SAME_DEVICE
;
8922 /* We'll reallocate a safe buffer */
8923 Length
= Fcb
->pNetRoot
->DiskParameters
.RenameInfoOverallocationSize
+ RenameFcb
->FcbTableEntry
.Path
.Length
+ FIELD_OFFSET(FILE_RENAME_INFORMATION
, FileName
);
8924 RenameInfo
= RxAllocatePoolWithTag(PagedPool
, Length
, '??xR');
8925 if (RenameInfo
== NULL
)
8927 return STATUS_INSUFFICIENT_RESOURCES
;
8933 UserInfo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8934 RenameInfo
->ReplaceIfExists
= UserInfo
->ReplaceIfExists
;
8935 RenameInfo
->RootDirectory
= UserInfo
->RootDirectory
;
8936 RenameInfo
->FileNameLength
= RenameFcb
->FcbTableEntry
.Path
.Length
;
8937 RtlMoveMemory(&RenameInfo
->FileName
[0], RenameFcb
->FcbTableEntry
.Path
.Buffer
, RenameFcb
->FcbTableEntry
.Path
.Length
);
8939 /* Set them in the RX_CONTEXT */
8940 RxContext
->Info
.FileInformationClass
= Stack
->Parameters
.SetFile
.FileInformationClass
;
8941 RxContext
->Info
.Buffer
= RenameInfo
;
8942 RxContext
->Info
.Length
= Length
;
8944 /* And call the mini-rdr */
8945 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
8950 RxFreePoolWithTag(RenameInfo
, '??xR');
8964 _In_ ACCESS_MASK DesiredAccess
,
8965 _In_ ULONG DesiredShareAccess
,
8966 _Inout_ PFILE_OBJECT FileObject
,
8967 _Out_ PSHARE_ACCESS ShareAccess
,
8969 _In_ PSZ wherelogtag
)
8973 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8974 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8975 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8981 PRX_CONTEXT RxContext
)
8984 return STATUS_NOT_IMPLEMENTED
;
8991 RxSetupNetFileObject(
8992 PRX_CONTEXT RxContext
)
8996 PFILE_OBJECT FileObject
;
8997 PIO_STACK_LOCATION Stack
;
9001 /* Assert FOBX is FOBX or NULL */
9002 Fobx
= (PFOBX
)RxContext
->pFobx
;
9003 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
9005 Fcb
= (PFCB
)RxContext
->pFcb
;
9006 Stack
= RxContext
->CurrentIrpSp
;
9007 FileObject
= Stack
->FileObject
;
9008 /* If it's temporary mark FO as such */
9009 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
9010 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
9012 if (FileObject
== NULL
)
9017 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
9020 /* No FO, nothing to setup */
9021 if (FileObject
== NULL
)
9026 /* Assign FCB & CCB (FOBX) to FO */
9027 FileObject
->FsContext
= Fcb
;
9028 FileObject
->FsContext2
= Fobx
;
9031 ULONG_PTR StackTop
, StackBottom
;
9033 /* If FO is allocated on pool, keep track of it */
9034 IoGetStackLimits(&StackTop
, &StackBottom
);
9035 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
9037 Fobx
->AssociatedFileObject
= FileObject
;
9041 Fobx
->AssociatedFileObject
= NULL
;
9044 /* Make sure to mark FOBX if it's a DFS open */
9045 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
9047 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
9051 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
9055 /* Set Cc pointers */
9056 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
9058 /* Update access state */
9059 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
9061 PACCESS_STATE AccessState
;
9063 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
9064 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
9065 AccessState
->RemainingDesiredAccess
= 0;
9075 IN PRX_CONTEXT RxContext
,
9076 OUT PBOOLEAN PostToFsp
)
9079 BOOLEAN Wait
, AlreadyStarted
;
9080 PRDBSS_DEVICE_OBJECT DeviceObject
;
9082 /* If we've not been post, then, do it */
9083 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
9085 SECURITY_SUBJECT_CONTEXT SubjectContext
;
9087 SeCaptureSubjectContext(&SubjectContext
);
9088 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
9089 SeReleaseSubjectContext(&SubjectContext
);
9092 return STATUS_PENDING
;
9095 /* Acquire all the required locks */
9096 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
9097 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
9100 return STATUS_PENDING
;
9103 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
9105 ExReleaseResourceLite(&RxData
.Resource
);
9107 return STATUS_PENDING
;
9110 AlreadyStarted
= FALSE
;
9111 DeviceObject
= RxContext
->RxDeviceObject
;
9114 /* MUP handle set, means already registered */
9115 if (DeviceObject
->MupHandle
!= NULL
)
9117 AlreadyStarted
= TRUE
;
9118 Status
= STATUS_REDIRECTOR_STARTED
;
9122 /* If we're asked to register to MUP, then do it */
9123 Status
= STATUS_SUCCESS
;
9124 if (DeviceObject
->RegisterUncProvider
)
9126 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
9127 &DeviceObject
->DeviceName
,
9128 DeviceObject
->RegisterMailSlotProvider
);
9130 if (!NT_SUCCESS(Status
))
9132 DeviceObject
->MupHandle
= NULL
;
9136 /* Register as file system */
9137 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
9138 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
9140 /* Inform mini-rdr it has to start */
9141 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
9142 if (NT_SUCCESS(Status
))
9144 ++DeviceObject
->StartStopContext
.Version
;
9145 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
9146 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
9148 Status
= RxInitializeMRxDispatcher(DeviceObject
);
9153 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
9155 if (!AlreadyStarted
)
9157 RxUnstart(RxContext
, DeviceObject
);
9161 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
9162 ExReleaseResourceLite(&RxData
.Resource
);
9172 IN PRX_CONTEXT RxContext
,
9173 OUT PBOOLEAN PostToFsp
)
9176 return STATUS_NOT_IMPLEMENTED
;
9181 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9185 return STATUS_NOT_IMPLEMENTED
;
9192 RxTryToBecomeTheTopLevelIrp(
9193 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
9195 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9196 IN BOOLEAN ForceTopLevel
9199 BOOLEAN FromPool
= FALSE
;
9203 /* If not top level, and not have to be, quit */
9204 if (IoGetTopLevelIrp() && !ForceTopLevel
)
9209 /* If not TLC provider, allocate one */
9210 if (TopLevelContext
== NULL
)
9212 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
9213 if (TopLevelContext
== NULL
)
9222 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
9224 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9227 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9230 /* Make it top level IRP */
9231 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
9240 RxUpdateShareAccess(
9241 _Inout_ PFILE_OBJECT FileObject
,
9242 _Inout_ PSHARE_ACCESS ShareAccess
,
9244 _In_ PSZ wherelogtag
)
9248 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
9249 IoUpdateShareAccess(FileObject
, ShareAccess
);
9250 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
9258 RxUninitializeCacheMap(
9259 PRX_CONTEXT RxContext
,
9260 PFILE_OBJECT FileObject
,
9261 PLARGE_INTEGER TruncateSize
)
9265 CACHE_UNINITIALIZE_EVENT UninitEvent
;
9269 Fcb
= FileObject
->FsContext
;
9270 ASSERT(NodeTypeIsFcb(Fcb
));
9271 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
9273 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
9274 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
9276 /* Always release the FCB before waiting for the uninit event */
9277 RxReleaseFcb(RxContext
, Fcb
);
9279 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
9281 /* Re-acquire it afterwards */
9282 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
9283 ASSERT(NT_SUCCESS(Status
));
9289 IN PDRIVER_OBJECT DriverObject
)
9298 IN PFILE_LOCK_INFO LockInfo
)
9305 PRX_CONTEXT Context
,
9306 PRDBSS_DEVICE_OBJECT DeviceObject
)
9315 RxUnwindTopLevelIrp(
9316 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
9318 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
9320 /* No TLC provided? Ask the system for ours! */
9321 if (TopLevelContext
== NULL
)
9323 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
9324 if (TopLevelContext
== NULL
)
9329 /* In that case, just assert it's really ours */
9330 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
9331 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9334 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9335 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
9336 /* Restore the previous top level IRP */
9337 IoSetTopLevelIrp(TopLevelContext
->Previous
);
9338 /* If TLC was allocated from pool, remove it from list and release it */
9339 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
9341 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
9342 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
9350 RxUpdateShareAccessPerSrvOpens(
9351 IN PSRV_OPEN SrvOpen
)
9353 ACCESS_MASK DesiredAccess
;
9355 BOOLEAN WriteAccess
;
9356 BOOLEAN DeleteAccess
;
9360 /* If already updated, no need to continue */
9361 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
9366 /* Check if any access wanted */
9367 DesiredAccess
= SrvOpen
->DesiredAccess
;
9368 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
9369 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
9370 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
9372 /* In that case, update it */
9373 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
9376 BOOLEAN SharedWrite
;
9377 BOOLEAN SharedDelete
;
9378 ULONG DesiredShareAccess
;
9379 PSHARE_ACCESS ShareAccess
;
9381 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
9382 DesiredShareAccess
= SrvOpen
->ShareAccess
;
9384 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
9385 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
9386 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
9388 ShareAccess
->OpenCount
++;
9390 ShareAccess
->Readers
+= ReadAccess
;
9391 ShareAccess
->Writers
+= WriteAccess
;
9392 ShareAccess
->Deleters
+= DeleteAccess
;
9393 ShareAccess
->SharedRead
+= SharedRead
;
9394 ShareAccess
->SharedWrite
+= SharedWrite
;
9395 ShareAccess
->SharedDelete
+= SharedDelete
;
9398 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
9405 RxXXXControlFileCallthru(
9406 PRX_CONTEXT Context
)
9412 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
9414 /* No dispatch table? Nothing to dispatch */
9415 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
9417 Context
->pFobx
= NULL
;
9418 return STATUS_INVALID_DEVICE_REQUEST
;
9421 /* Init the lowio context */
9422 Status
= RxLowIoPopulateFsctlInfo(Context
);
9423 if (!NT_SUCCESS(Status
))
9428 /* Check whether we're consistent: a length means a buffer */
9429 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
9430 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
9432 return STATUS_INVALID_PARAMETER
;
9435 /* Forward the call to the mini-rdr */
9436 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
9437 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
9438 if (Status
!= STATUS_PENDING
)
9440 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
9443 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);