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
)
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
650 /* Are loud operations enabled? */
651 if (RxLoudLowIoOpsEnabled
)
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 Fcb
= (PFCB
)RxContext
->pFcb
;
657 if (RtlCompareMemory(Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, (Fcb
->PrivateAlreadyPrefixedName
.Length
- ALLSCR_LENGTH
)),
658 L
"all.scr", ALLSCR_LENGTH
) == ALLSCR_LENGTH
)
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
);
710 Fcb
= (PFCB
)RxContext
->pFcb
;
713 /* If FCB resource was acquired, release it */
714 if (RxContext
->FcbResourceAcquired
)
716 /* Taking care of owner */
717 if (ResourceOwnerSet
)
719 RxReleaseFcbForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
723 RxReleaseFcb(RxContext
, Fcb
);
726 RxContext
->FcbResourceAcquired
= FALSE
;
729 /* If FCB paging resource was acquired, release it */
730 if (RxContext
->FcbPagingIoResourceAcquired
)
732 /* Taking care of owner */
733 if (ResourceOwnerSet
)
735 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
739 RxReleasePagingIoResource(RxContext
, Fcb
);
742 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
750 RxAddToTopLevelIrpAllocatedContextsList(
751 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
755 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
757 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
758 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
760 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
761 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
762 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
771 IN PRX_CONTEXT RxContext
,
776 WORK_QUEUE_TYPE Queue
;
777 PIO_STACK_LOCATION Stack
;
779 Stack
= RxContext
->CurrentIrpSp
;
780 RxContext
->PostRequest
= FALSE
;
782 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
784 Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
786 Queue
= DelayedWorkQueue
;
787 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
791 Queue
= CriticalWorkQueue
;
792 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
795 /* Check for overflow */
796 if (Stack
->FileObject
!= NULL
)
798 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
800 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
801 /* In case of an overflow, add the new queued call to the overflow list */
804 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
805 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
806 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
808 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
812 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
815 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
816 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
823 RxAdjustFileTimesAndSize(
829 PFILE_OBJECT FileObject
;
830 LARGE_INTEGER CurrentTime
;
831 FILE_BASIC_INFORMATION FileBasicInfo
;
832 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
833 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
837 FileObject
= Context
->CurrentIrpSp
->FileObject
;
838 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839 if (FileObject
->PrivateCacheMap
== NULL
)
845 KeQuerySystemTime(&CurrentTime
);
847 Fobx
= (PFOBX
)Context
->pFobx
;
848 /* Was the file modified? */
849 FileModified
= BooleanFlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
);
850 /* We'll set last write if it was modified and user didn't update yet */
851 SetLastWrite
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
852 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853 SetLastAccess
= SetLastWrite
||
854 (BooleanFlagOn(FileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
855 !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
856 /* We'll set last change if it was modified and user didn't update yet */
857 SetLastChange
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
859 /* Nothing to update? Job done */
860 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
865 Fcb
= (PFCB
)Context
->pFcb
;
866 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
868 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
870 /* Update lastwrite time if required */
874 Fcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
875 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
878 /* Update lastaccess time if required */
882 Fcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
883 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
886 /* Update lastchange time if required */
890 Fcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
891 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
894 /* If one of the date was modified, issue a call to mini-rdr */
897 Context
->Info
.FileInformationClass
= FileBasicInformation
;
898 Context
->Info
.Buffer
= &FileBasicInfo
;
899 Context
->Info
.Length
= sizeof(FileBasicInfo
);
901 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
905 /* If the file was modified, update its EOF */
908 FileEOFInfo
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
910 Context
->Info
.FileInformationClass
= FileEndOfFileInformation
;
911 Context
->Info
.Buffer
= &FileEOFInfo
;
912 Context
->Info
.Length
= sizeof(FileEOFInfo
);
914 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
923 RxAllocateCanonicalNameBuffer(
924 PRX_CONTEXT RxContext
,
925 PUNICODE_STRING CanonicalName
,
926 USHORT CanonicalLength
)
930 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
932 /* Context must be free of any already allocated name */
933 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
935 /* Validate string length */
936 if (CanonicalLength
> USHRT_MAX
- 1)
938 CanonicalName
->Buffer
= NULL
;
939 return STATUS_OBJECT_PATH_INVALID
;
942 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
943 if (CanonicalName
->Buffer
== NULL
)
945 return STATUS_INSUFFICIENT_RESOURCES
;
948 CanonicalName
->Length
= 0;
949 CanonicalName
->MaximumLength
= CanonicalLength
;
951 /* Set the two places - they must always be identical */
952 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
953 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
955 return STATUS_SUCCESS
;
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
968 LIST_ENTRY ContextsToCancel
;
970 /* Init a list for the contexts to cancel */
971 InitializeListHead(&ContextsToCancel
);
973 /* Lock our list lock */
974 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
976 /* Now, browse all the active contexts, to find the associated ones */
977 Entry
= RxActiveContexts
.Flink
;
978 while (Entry
!= &RxActiveContexts
)
980 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
981 Entry
= Entry
->Flink
;
983 /* Not the IRP we're looking for, ignore */
984 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
985 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
990 /* Not the FOBX we're looking for, ignore */
991 if ((PFOBX
)Context
->pFobx
!= Fobx
)
996 /* No cancel routine (can't be cancel, then), ignore */
997 if (Context
->MRxCancelRoutine
== NULL
)
1002 /* Mark our context as cancelled */
1003 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1005 /* Move it to our list */
1006 RemoveEntryList(&Context
->ContextListEntry
);
1007 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1009 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1012 /* Done with the contexts */
1013 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1015 /* Now, handle all our "extracted" contexts */
1016 while (!IsListEmpty(&ContextsToCancel
))
1018 Entry
= RemoveHeadList(&ContextsToCancel
);
1019 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1021 /* If they had an associated IRP (should be always true) */
1022 if (Context
->CurrentIrp
!= NULL
)
1024 /* Then, call cancel routine */
1025 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1026 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1027 Context
->MRxCancelRoutine(Context
);
1030 /* And delete the context */
1031 RxDereferenceAndDeleteRxContext(Context
);
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040 PV_NET_ROOT VNetRoot
,
1041 BOOLEAN ForceFilesClosed
)
1046 PRX_CONTEXT Context
;
1047 LIST_ENTRY ContextsToCancel
;
1049 /* Init a list for the contexts to cancel */
1050 InitializeListHead(&ContextsToCancel
);
1052 /* Lock our list lock */
1053 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1055 /* Assume success */
1056 Status
= STATUS_SUCCESS
;
1058 /* Now, browse all the active contexts, to find the associated ones */
1059 Entry
= RxActiveContexts
.Flink
;
1060 while (Entry
!= &RxActiveContexts
)
1062 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1063 Entry
= Entry
->Flink
;
1065 /* Not the IRP we're looking for, ignore */
1066 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1067 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1072 /* Not the VNetRoot we're looking for, ignore */
1073 if (Context
->pFcb
== NULL
||
1074 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1079 /* No cancel routine (can't be cancel, then), ignore */
1080 if (Context
->MRxCancelRoutine
== NULL
)
1085 /* At that point, we found a matching context
1086 * If we're not asked to force close, then fail - it's still open
1088 if (!ForceFilesClosed
)
1090 Status
= STATUS_FILES_OPEN
;
1094 /* Mark our context as cancelled */
1095 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1097 /* Move it to our list */
1098 RemoveEntryList(&Context
->ContextListEntry
);
1099 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1101 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1104 /* Done with the contexts */
1105 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1107 if (Status
!= STATUS_SUCCESS
)
1112 /* Now, handle all our "extracted" contexts */
1113 while (!IsListEmpty(&ContextsToCancel
))
1115 Entry
= RemoveHeadList(&ContextsToCancel
);
1116 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1118 /* If they had an associated IRP (should be always true) */
1119 if (Context
->CurrentIrp
!= NULL
)
1121 /* Then, call cancel routine */
1122 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1123 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1124 Context
->MRxCancelRoutine(Context
);
1127 /* And delete the context */
1128 RxDereferenceAndDeleteRxContext(Context
);
1137 PDEVICE_OBJECT DeviceObject
,
1147 RxCanonicalizeFileNameByServerSpecs(
1148 PRX_CONTEXT RxContext
,
1149 PUNICODE_STRING NetRootName
)
1151 USHORT NextChar
, CurChar
;
1156 /* Validate file name is not empty */
1157 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1160 return STATUS_MORE_PROCESSING_REQUIRED
;
1163 /* Validate name is correct */
1164 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1168 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1170 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1177 if (CurChar
== NextChar
)
1179 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1186 if (CurChar
>= MaxChars
- 1)
1191 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1193 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1198 if (NetRootName
->Buffer
[1] != ':')
1200 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1206 if ((CurChar
- NextChar
) == 1)
1208 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1213 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1215 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1220 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1221 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1226 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1228 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1234 return STATUS_MORE_PROCESSING_REQUIRED
;
1238 RxCanonicalizeNameAndObtainNetRoot(
1239 PRX_CONTEXT RxContext
,
1240 PUNICODE_STRING FileName
,
1241 PUNICODE_STRING NetRootName
)
1244 NET_ROOT_TYPE NetRootType
;
1245 UNICODE_STRING CanonicalName
;
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 (RxContext
->CurrentIrpSp
->FileObject
->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
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1270 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1272 return STATUS_INVALID_PARAMETER
;
1275 if (!NodeTypeIsFcb(Fcb
))
1277 return STATUS_INVALID_PARAMETER
;
1283 /* Get/Create the associated VNetRoot for opening */
1284 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1285 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1286 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1288 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1290 RxFreeCanonicalNameBuffer(RxContext
);
1291 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1292 if (NT_SUCCESS(Status
))
1294 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1298 /* Filename cannot contain wildcards */
1299 if (FsRtlDoesNameContainWildCards(NetRootName
))
1301 Status
= STATUS_OBJECT_NAME_INVALID
;
1304 /* Make sure file name is correct */
1305 if (NT_SUCCESS(Status
))
1307 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1310 /* Give the mini-redirector a chance to prepare the name */
1311 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1313 if (RxContext
->Create
.pNetRoot
!= NULL
)
1315 NTSTATUS IgnoredStatus
;
1317 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1318 MRxPreparseName
, (RxContext
, NetRootName
));
1319 (void)IgnoredStatus
;
1328 RxCheckFcbStructuresForAlignment(
1337 _In_ ACCESS_MASK DesiredAccess
,
1338 _In_ ULONG DesiredShareAccess
,
1339 _Inout_ PFILE_OBJECT FileObject
,
1340 _Inout_ PSHARE_ACCESS ShareAccess
,
1341 _In_ BOOLEAN Update
,
1343 _In_ PSZ wherelogtag
)
1347 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1348 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1350 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1358 RxCheckShareAccessPerSrvOpens(
1360 IN ACCESS_MASK DesiredAccess
,
1361 IN ULONG DesiredShareAccess
)
1364 BOOLEAN WriteAccess
;
1365 BOOLEAN DeleteAccess
;
1366 PSHARE_ACCESS ShareAccess
;
1370 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1372 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1373 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1375 /* Check if any access wanted */
1376 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1377 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1378 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1380 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1382 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1383 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1384 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1386 /* Check whether there's a violation */
1388 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1390 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1392 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1393 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1394 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1395 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1397 return STATUS_SHARING_VIOLATION
;
1401 return STATUS_SUCCESS
;
1405 RxCleanupPipeQueues(
1406 PRX_CONTEXT Context
)
1415 RxCloseAssociatedSrvOpen(
1417 IN PRX_CONTEXT RxContext OPTIONAL
)
1422 BOOLEAN CloseSrvOpen
;
1423 PRX_CONTEXT LocalContext
;
1427 /* Assume SRV_OPEN is already closed */
1428 CloseSrvOpen
= FALSE
;
1429 /* If we have a FOBX, we'll have to close it */
1432 /* If the FOBX isn't closed yet */
1433 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1435 SrvOpen
= Fobx
->SrvOpen
;
1436 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1437 /* Check whether we've to close SRV_OPEN first */
1438 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1440 CloseSrvOpen
= TRUE
;
1444 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1446 /* Not much to do */
1447 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1449 if (SrvOpen
->OpenCount
> 0)
1451 --SrvOpen
->OpenCount
;
1456 /* No need to close SRV_OPEN, so close FOBX */
1459 RxMarkFobxOnClose(Fobx
);
1461 return STATUS_SUCCESS
;
1466 /* No FOBX? No RX_CONTEXT, ok, job done! */
1467 if (RxContext
== NULL
)
1469 return STATUS_SUCCESS
;
1472 /* Get the FCB from RX_CONTEXT */
1473 Fcb
= (PFCB
)RxContext
->pFcb
;
1477 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1478 if (RxContext
== NULL
)
1480 ASSERT(Fobx
!= NULL
);
1482 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1483 if (LocalContext
== NULL
)
1485 return STATUS_INSUFFICIENT_RESOURCES
;
1488 LocalContext
->MajorFunction
= 2;
1489 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1490 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1491 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1495 LocalContext
= RxContext
;
1498 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1500 /* Now, close the FOBX */
1503 RxMarkFobxOnClose(Fobx
);
1507 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1510 /* If not a "standard" file, SRV_OPEN can be null */
1511 if (SrvOpen
== NULL
)
1513 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1514 RxDereferenceNetFcb(Fcb
);
1516 if (LocalContext
!= RxContext
)
1518 RxDereferenceAndDeleteRxContext(LocalContext
);
1521 return STATUS_SUCCESS
;
1524 /* If SRV_OPEN isn't in a good condition, nothing to close */
1525 if (SrvOpen
->Condition
!= Condition_Good
)
1527 if (LocalContext
!= RxContext
)
1529 RxDereferenceAndDeleteRxContext(LocalContext
);
1532 return STATUS_SUCCESS
;
1535 /* Decrease open count */
1536 if (SrvOpen
->OpenCount
> 0)
1538 --SrvOpen
->OpenCount
;
1541 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1542 if (SrvOpen
->OpenCount
== 1)
1544 if (!IsListEmpty(&SrvOpen
->FobxList
))
1546 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1548 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1553 /* Nothing left, purge FCB */
1554 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1556 RxPurgeNetFcb(Fcb
, LocalContext
);
1559 /* Already closed? Job done! */
1560 SrvOpen
= Fobx
->SrvOpen
;
1561 if (SrvOpen
== NULL
||
1562 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1563 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1565 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1566 if (LocalContext
!= RxContext
)
1568 RxDereferenceAndDeleteRxContext(LocalContext
);
1571 return STATUS_SUCCESS
;
1574 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1576 /* Inform mini-rdr about closing */
1577 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1578 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1579 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1581 /* And mark as such */
1582 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1583 SrvOpen
->Key
= (PVOID
)-1;
1585 /* If we were delayed, we're not! */
1586 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1588 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1592 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1593 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1596 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1598 /* Mark the FOBX closed as well */
1599 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1601 if (LocalContext
!= RxContext
)
1603 RxDereferenceAndDeleteRxContext(LocalContext
);
1613 RxCollapseOrCreateSrvOpen(
1614 PRX_CONTEXT RxContext
)
1621 PIO_STACK_LOCATION Stack
;
1622 ACCESS_MASK DesiredAccess
;
1623 RX_BLOCK_CONDITION FcbCondition
;
1627 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1629 Fcb
= (PFCB
)RxContext
->pFcb
;
1630 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1631 ++Fcb
->UncleanCount
;
1633 Stack
= RxContext
->CurrentIrpSp
;
1634 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1635 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1637 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1639 /* Try to find a reusable SRV_OPEN */
1640 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1641 if (Status
== STATUS_NOT_FOUND
)
1643 /* If none found, create one */
1644 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1645 if (SrvOpen
== NULL
)
1647 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1651 SrvOpen
->DesiredAccess
= DesiredAccess
;
1652 SrvOpen
->ShareAccess
= ShareAccess
;
1653 Status
= STATUS_SUCCESS
;
1656 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1658 if (Status
!= STATUS_SUCCESS
)
1660 FcbCondition
= Condition_Bad
;
1664 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1666 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1667 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1668 /* Inform the mini-rdr we're handling a create */
1669 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1670 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1672 DPRINT("MRxCreate returned: %x\n", Status
);
1673 if (Status
== STATUS_SUCCESS
)
1675 /* In case of overwrite, reset file size */
1676 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1678 RxAcquirePagingIoResource(RxContext
, Fcb
);
1679 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1680 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1681 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1682 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1683 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1684 RxReleasePagingIoResource(RxContext
, Fcb
);
1688 /* Otherwise, adjust sizes */
1689 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1690 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1692 RxAdjustAllocationSizeforCC(Fcb
);
1694 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1698 /* Set the IoStatus with information returned by mini-rdr */
1699 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1701 SrvOpen
->OpenStatus
= Status
;
1702 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1703 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1705 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1707 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1709 if (Status
== STATUS_SUCCESS
)
1711 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1713 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1715 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1716 FcbCondition
= Condition_Good
;
1720 FcbCondition
= Condition_Bad
;
1721 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1722 RxContext
->pRelevantSrvOpen
= NULL
;
1724 if (RxContext
->pFobx
!= NULL
)
1726 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1727 RxContext
->pFobx
= NULL
;
1732 /* Set FCB state - good or bad - depending on whether create succeed */
1733 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1734 RxTransitionNetFcb(Fcb
, FcbCondition
);
1736 else if (Status
== STATUS_SUCCESS
)
1738 BOOLEAN IsGood
, ExtraOpen
;
1740 /* A reusable SRV_OPEN was found */
1741 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1744 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1746 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1747 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1748 if (!StableCondition(SrvOpen
->Condition
))
1750 RxReferenceSrvOpen(SrvOpen
);
1751 ++SrvOpen
->OpenCount
;
1754 RxReleaseFcb(RxContext
, Fcb
);
1755 RxContext
->Create
.FcbAcquired
= FALSE
;
1757 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1759 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1761 RxContext
->Create
.FcbAcquired
= TRUE
;
1764 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1767 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1770 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1772 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1776 Status
= SrvOpen
->OpenStatus
;
1781 --SrvOpen
->OpenCount
;
1782 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1786 --Fcb
->UncleanCount
;
1788 DPRINT("Status: %x\n", Status
);
1798 PRX_CONTEXT Context
)
1800 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1806 PFILE_OBJECT FileObject
;
1807 LARGE_INTEGER TruncateSize
;
1808 PLARGE_INTEGER TruncateSizePtr
;
1809 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1813 Fcb
= (PFCB
)Context
->pFcb
;
1814 Fobx
= (PFOBX
)Context
->pFobx
;
1815 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1817 /* File system closing, it's OK */
1820 if (Fcb
->UncleanCount
> 0)
1822 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1825 return STATUS_SUCCESS
;
1828 /* Check we have a correct FCB type */
1829 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1830 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1831 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1832 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1834 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1835 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1838 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1839 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1841 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1843 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1844 if (!NT_SUCCESS(Status
))
1851 Fobx
->AssociatedFileObject
= NULL
;
1853 /* In case it was already orphaned */
1854 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
1856 ASSERT(Fcb
->UncleanCount
!= 0);
1857 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1859 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1861 --Fcb
->UncachedUncleanCount
;
1864 /* Inform mini-rdr */
1865 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1867 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1868 --Fobx
->SrvOpen
->UncleanFobxCount
;
1870 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1872 RxReleaseFcb(Context
, Fcb
);
1874 return STATUS_SUCCESS
;
1877 /* Report the fact that file could be set as delete on close */
1878 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1880 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1883 /* Cancel any pending notification */
1884 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1886 /* Backup open count before we start playing with it */
1887 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1889 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1890 FcbTableAcquired
= FALSE
;
1891 LeftForDelete
= FALSE
;
1892 OneLeft
= (Fcb
->UncleanCount
== 1);
1896 /* Unclean count and delete on close? Verify whether we're the one */
1897 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1899 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1901 FcbTableAcquired
= TRUE
;
1905 RxReleaseFcb(Context
, Fcb
);
1907 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1909 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1910 if (Status
!= STATUS_SUCCESS
)
1912 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1916 FcbTableAcquired
= TRUE
;
1919 /* That means we'll perform the delete on close! */
1920 if (Fcb
->UncleanCount
== 1)
1922 LeftForDelete
= TRUE
;
1926 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1927 FcbTableAcquired
= FALSE
;
1932 TruncateSizePtr
= NULL
;
1933 /* Handle cleanup for pipes and printers */
1934 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1936 RxCleanupPipeQueues(Context
);
1938 /* Handle cleanup for files */
1939 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1941 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1942 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1945 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1947 /* If there are still locks to release, proceed */
1948 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1950 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1951 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1952 Status
= RxLowIoLockControlShell(Context
);
1955 /* Fix times and size */
1956 RxAdjustFileTimesAndSize(Context
);
1958 /* If we're the only one left... */
1961 /* And if we're supposed to delete on close */
1964 /* Update the sizes */
1965 RxAcquirePagingIoResource(Context
, Fcb
);
1966 Fcb
->Header
.FileSize
.QuadPart
= 0;
1967 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1968 RxReleasePagingIoResource(Context
, Fcb
);
1970 /* Otherwise, call the mini-rdr to adjust sizes */
1973 /* File got grown up, fill with zeroes */
1974 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1975 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1977 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1978 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1981 /* File was truncated, let mini-rdr proceed */
1982 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1984 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1985 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1987 /* Keep track of file change for Cc uninit */
1988 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1989 TruncateSizePtr
= &TruncateSize
;
1994 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2002 /* Otherwise, try to see whether we can purge */
2005 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2012 /* We have to still be there! */
2013 ASSERT(Fcb
->UncleanCount
!= 0);
2014 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2016 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2018 --Fcb
->UncachedUncleanCount
;
2021 /* Inform mini-rdr about ongoing cleanup */
2022 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2024 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2025 --Fobx
->SrvOpen
->UncleanFobxCount
;
2028 if (DisableFlushOnCleanup
)
2030 /* Only if we're the last standing */
2031 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2032 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2034 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2035 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2041 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2043 DPRINT("Flushing %p on cleanup\n", Context
);
2044 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2048 /* If only remaining uncached & unclean, then flush and purge */
2049 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2051 if (Fcb
->UncachedUncleanCount
!= 0)
2053 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2054 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2056 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2057 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2062 /* If purge required, and not about to delete, flush */
2063 if (!LeftForDelete
&& NeedPurge
)
2065 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2066 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2069 /* If it was a file, drop cache */
2072 DPRINT("Uninit cache map for file\n");
2073 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2076 /* If that's the one left for deletion, or if it needs purge, flush */
2077 if (LeftForDelete
|| NeedPurge
)
2079 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2080 /* If that's for deletion, also remove from FCB table */
2083 RxRemoveNameNetFcb(Fcb
);
2084 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2085 FcbTableAcquired
= FALSE
;
2089 /* Remove any share access */
2090 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2092 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2095 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2096 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2097 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2099 NTSTATUS InternalStatus
;
2100 PRX_CONTEXT InternalContext
;
2102 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2103 InternalStatus
= STATUS_UNSUCCESSFUL
;
2104 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2105 Fcb
->RxDeviceObject
,
2106 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2107 if (InternalContext
!= NULL
)
2109 FILE_END_OF_FILE_INFORMATION FileEOF
;
2111 InternalStatus
= STATUS_SUCCESS
;
2113 /* Initialize the context for file information set */
2114 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2115 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2116 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2118 /* Get EOF from the FCB */
2119 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2120 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2121 InternalContext
->Info
.Buffer
= &FileEOF
;
2122 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2124 /* Call the mini-rdr */
2125 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2128 RxDereferenceAndDeleteRxContext(InternalContext
);
2131 /* We tried, so, clean the FOBX flag */
2132 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2133 /* If it failed, then, disable collapsing on the FCB */
2134 if (!NT_SUCCESS(InternalStatus
))
2136 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2141 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2143 FcbAcquired
= FALSE
;
2144 RxReleaseFcb(Context
, Fcb
);
2150 RxReleaseFcb(Context
, Fcb
);
2153 if (FcbTableAcquired
)
2155 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2161 #undef BugCheckFileId
2167 PRX_CONTEXT Context
)
2169 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2173 PFILE_OBJECT FileObject
;
2174 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2178 Fcb
= (PFCB
)Context
->pFcb
;
2179 Fobx
= (PFOBX
)Context
->pFobx
;
2180 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2181 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2183 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2184 if (!NT_SUCCESS(Status
))
2194 /* Check our FCB type is expected */
2195 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2196 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2197 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2199 RxBugCheck(NodeType(Fcb
), 0, 0);
2202 RxReferenceNetFcb(Fcb
);
2204 DereferenceFobx
= FALSE
;
2205 /* If we're not closing FS */
2211 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2212 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2213 /* Handle delayed close */
2214 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2216 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2218 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2220 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2222 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2224 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2226 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2230 DereferenceFobx
= TRUE
;
2231 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2238 /* If we reach maximum of delayed close/or if there are no delayed close */
2239 if (!DereferenceFobx
)
2243 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2244 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2246 /* Delete if asked */
2247 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2249 RxScavengeRelatedFobxs(Fcb
);
2250 RxSynchronizeWithScavenger(Context
);
2252 RxReleaseFcb(Context
, Fcb
);
2254 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2255 RxOrphanThisFcb(Fcb
);
2256 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2258 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2259 ASSERT(NT_SUCCESS(Status
));
2264 RxMarkFobxOnClose(Fobx
);
2267 if (DereferenceFobx
)
2269 ASSERT(Fobx
!= NULL
);
2270 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2274 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2277 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2281 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2282 AcquiredFcb
= !Freed
;
2284 FileObject
->FsContext
= (PVOID
)-1;
2288 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2292 RxReleaseFcb(Context
, Fcb
);
2293 AcquiredFcb
= FALSE
;
2298 if (_SEH2_AbnormalTermination())
2302 RxReleaseFcb(Context
, Fcb
);
2307 ASSERT(!AcquiredFcb
);
2312 DPRINT("Status: %x\n", Status
);
2314 #undef BugCheckFileId
2323 PRX_CONTEXT Context
)
2327 PFILE_OBJECT FileObject
;
2328 PIO_STACK_LOCATION Stack
;
2332 DPRINT("RxCommonCreate(%p)\n", Context
);
2334 Irp
= Context
->CurrentIrp
;
2335 Stack
= Context
->CurrentIrpSp
;
2336 FileObject
= Stack
->FileObject
;
2338 /* Check whether that's a device opening */
2339 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2341 FileObject
->FsContext
= &RxDeviceFCB
;
2342 FileObject
->FsContext2
= NULL
;
2344 ++RxDeviceFCB
.NodeReferenceCount
;
2345 ++RxDeviceFCB
.OpenCount
;
2347 Irp
->IoStatus
.Information
= FILE_OPENED
;
2348 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2350 Status
= STATUS_SUCCESS
;
2354 PFCB RelatedFcb
= NULL
;
2356 /* Make sure caller is consistent */
2357 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2358 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2360 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2361 return STATUS_INVALID_PARAMETER
;
2364 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2365 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2366 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2367 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2369 if (FileObject
->RelatedFileObject
!= NULL
)
2371 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2372 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2375 /* Going to rename? */
2376 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2378 DPRINT("TargetDir!\n");
2381 /* Copy create parameters to the context */
2382 RxCopyCreateParameters(Context
);
2384 /* If the caller wants to establish a connection, go ahead */
2385 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2387 Status
= RxCreateTreeConnect(Context
);
2391 /* Validate file name */
2392 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2393 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2394 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2396 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2397 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2398 FileObject
->FileName
.Length
);
2400 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2401 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2402 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2404 return STATUS_OBJECT_NAME_INVALID
;
2408 /* Attempt to open the file */
2411 UNICODE_STRING NetRootName
;
2413 /* Strip last \ if required */
2414 if (FileObject
->FileName
.Length
!= 0 &&
2415 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2417 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2419 return STATUS_OBJECT_NAME_INVALID
;
2422 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2423 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2426 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2428 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2431 /* Get the associated net root to opening */
2432 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2433 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2438 /* And attempt to open */
2439 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2440 if (Status
== STATUS_SHARING_VIOLATION
)
2442 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2444 /* If that happens for file creation, fail for real */
2445 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2447 Status
= STATUS_OBJECT_NAME_COLLISION
;
2451 /* Otherwise, if possible, attempt to scavenger current FOBX
2452 * to check whether a dormant FOBX is the reason for sharing violation
2454 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2455 !Context
->Create
.ScavengingAlreadyTried
)
2457 /* Only doable with a VNetRoot */
2458 if (Context
->Create
.pVNetRoot
!= NULL
)
2460 PV_NET_ROOT VNetRoot
;
2461 NT_CREATE_PARAMETERS SavedParameters
;
2463 /* Save create parameters */
2464 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2466 /* Reference the VNetRoot for the scavenging time */
2467 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2468 RxReferenceVNetRoot(VNetRoot
);
2470 /* Prepare the RX_CONTEXT for reuse */
2471 RxpPrepareCreateContextForReuse(Context
);
2472 RxReinitializeContext(Context
);
2474 /* Copy what we saved */
2475 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2477 /* And recopy what can be */
2478 RxCopyCreateParameters(Context
);
2480 /* And start purging, then scavenging FOBX */
2481 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2482 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2483 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2486 /* Ask for a second round */
2487 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2489 /* Keep track we already scavenged */
2490 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2492 /* Reference our SRV_CALL for CBS handling */
2493 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2494 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2496 /* Drop our extra reference */
2497 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2502 else if (Status
== STATUS_REPARSE
)
2504 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2508 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2511 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2514 if (Status
== STATUS_RETRY
)
2516 RxpPrepareCreateContextForReuse(Context
);
2518 ASSERT(Status
!= STATUS_PENDING
);
2521 DPRINT("Status: %lx\n", Status
);
2530 RxCommonDevFCBCleanup(
2531 PRX_CONTEXT Context
)
2538 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2540 Fcb
= Context
->pFcb
;
2541 Status
= STATUS_SUCCESS
;
2542 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2544 /* Our FOBX if set, has to be a VNetRoot */
2545 if (Context
->pFobx
!= NULL
)
2547 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2548 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2550 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2552 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2556 --Fcb
->UncleanCount
;
2567 RxCommonDevFCBClose(
2568 PRX_CONTEXT Context
)
2572 PMRX_V_NET_ROOT NetRoot
;
2576 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2578 Fcb
= Context
->pFcb
;
2579 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2580 Status
= STATUS_SUCCESS
;
2581 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2583 /* Our FOBX if set, has to be a VNetRoot */
2584 if (NetRoot
!= NULL
)
2586 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2587 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2589 --NetRoot
->NumberOfOpens
;
2590 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2594 Status
= STATUS_NOT_IMPLEMENTED
;
2596 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2608 RxCommonDevFCBFsCtl(
2609 PRX_CONTEXT Context
)
2612 return STATUS_NOT_IMPLEMENTED
;
2620 RxCommonDevFCBIoCtl(
2621 PRX_CONTEXT Context
)
2627 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2629 if (Context
->pFobx
!= NULL
)
2631 return STATUS_INVALID_HANDLE
;
2634 /* Is that a prefix claim from MUP? */
2635 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2637 return RxPrefixClaim(Context
);
2640 /* Otherwise, pass through the mini-rdr */
2641 Status
= RxXXXControlFileCallthru(Context
);
2642 if (Status
!= STATUS_PENDING
)
2644 if (Context
->PostRequest
)
2646 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2647 Status
= RxFsdPostRequest(Context
);
2651 DPRINT("Status: %lx\n", Status
);
2657 RxCommonDevFCBQueryVolInfo(
2658 PRX_CONTEXT Context
)
2661 return STATUS_NOT_IMPLEMENTED
;
2669 RxCommonDeviceControl(
2670 PRX_CONTEXT Context
)
2676 /* Prefix claim is only allowed for device, not files */
2677 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2679 return STATUS_INVALID_DEVICE_REQUEST
;
2682 /* Submit to mini-rdr */
2683 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2684 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2685 if (Status
== STATUS_PENDING
)
2687 RxDereferenceAndDeleteRxContext_Real(Context
);
2698 RxCommonDirectoryControl(
2699 PRX_CONTEXT Context
)
2704 PIO_STACK_LOCATION Stack
;
2708 Fcb
= (PFCB
)Context
->pFcb
;
2709 Fobx
= (PFOBX
)Context
->pFobx
;
2710 Stack
= Context
->CurrentIrpSp
;
2711 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2713 /* Call the appropriate helper */
2714 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2716 Status
= RxQueryDirectory(Context
);
2718 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2720 Status
= RxNotifyChangeDirectory(Context
);
2721 if (Status
== STATUS_PENDING
)
2723 RxDereferenceAndDeleteRxContext_Real(Context
);
2728 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2736 RxCommonDispatchProblem(
2737 PRX_CONTEXT Context
)
2740 return STATUS_NOT_IMPLEMENTED
;
2745 RxCommonFileSystemControl(
2746 PRX_CONTEXT Context
)
2750 PIO_STACK_LOCATION Stack
;
2754 Irp
= Context
->CurrentIrp
;
2755 Stack
= Context
->CurrentIrpSp
;
2756 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2758 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2761 return STATUS_NOT_IMPLEMENTED
;
2766 RxCommonFlushBuffers(
2767 PRX_CONTEXT Context
)
2770 return STATUS_NOT_IMPLEMENTED
;
2775 RxCommonLockControl(
2776 PRX_CONTEXT Context
)
2779 return STATUS_NOT_IMPLEMENTED
;
2785 PRX_CONTEXT Context
)
2788 return STATUS_NOT_IMPLEMENTED
;
2796 RxCommonQueryInformation(
2797 PRX_CONTEXT Context
)
2799 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2800 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2801 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2808 PIO_STACK_LOCATION Stack
;
2809 FILE_INFORMATION_CLASS FileInfoClass
;
2813 Fcb
= (PFCB
)Context
->pFcb
;
2814 Fobx
= (PFOBX
)Context
->pFobx
;
2815 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2817 Irp
= Context
->CurrentIrp
;
2818 Stack
= Context
->CurrentIrpSp
;
2819 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2820 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2822 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2823 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2830 /* Get a writable buffer */
2831 Buffer
= RxMapSystemBuffer(Context
);
2834 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2838 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2840 /* Validate file type */
2841 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2843 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2845 Status
= STATUS_INVALID_PARAMETER
;
2848 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2850 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2852 Status
= STATUS_NOT_IMPLEMENTED
;
2856 Status
= STATUS_INVALID_PARAMETER
;
2863 /* Acquire the right lock */
2864 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2865 FileInfoClass
!= FileNameInformation
)
2867 if (FileInfoClass
== FileCompressionInformation
)
2869 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2873 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2876 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2878 Status
= STATUS_PENDING
;
2881 else if (!NT_SUCCESS(Status
))
2889 /* Dispatch to the right helper */
2890 switch (FileInfoClass
)
2892 case FileBasicInformation
:
2893 Status
= RxQueryBasicInfo(Context
, Buffer
);
2896 case FileStandardInformation
:
2897 Status
= RxQueryStandardInfo(Context
, Buffer
);
2900 case FileInternalInformation
:
2901 Status
= RxQueryInternalInfo(Context
, Buffer
);
2904 case FileEaInformation
:
2905 Status
= RxQueryEaInfo(Context
, Buffer
);
2908 case FileNameInformation
:
2909 Status
= RxQueryNameInfo(Context
, Buffer
);
2912 case FileAllInformation
:
2913 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2914 if (!NT_SUCCESS(Status
))
2919 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2920 if (!NT_SUCCESS(Status
))
2925 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2926 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2927 if (!NT_SUCCESS(Status
))
2932 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2933 sizeof(FILE_STANDARD_INFORMATION
) +
2934 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2935 if (!NT_SUCCESS(Status
))
2940 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2941 sizeof(FILE_STANDARD_INFORMATION
) +
2942 sizeof(FILE_INTERNAL_INFORMATION
) +
2943 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2944 if (!NT_SUCCESS(Status
))
2949 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2950 sizeof(FILE_STANDARD_INFORMATION
) +
2951 sizeof(FILE_INTERNAL_INFORMATION
) +
2952 sizeof(FILE_EA_INFORMATION
) +
2953 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2956 case FileAlternateNameInformation
:
2957 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2960 case FilePipeInformation
:
2961 case FilePipeLocalInformation
:
2962 case FilePipeRemoteInformation
:
2963 Status
= RxQueryPipeInfo(Context
, Buffer
);
2966 case FileCompressionInformation
:
2967 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2971 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2972 Status
= Context
->IoStatusBlock
.Status
;
2976 if (Context
->Info
.Length
< 0)
2978 Status
= STATUS_BUFFER_OVERFLOW
;
2979 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2982 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2988 RxReleaseFcb(Context
, Fcb
);
2993 DPRINT("Status: %x\n", Status
);
2996 #undef SET_SIZE_AND_QUERY
3001 RxCommonQueryQuotaInformation(
3002 PRX_CONTEXT Context
)
3005 return STATUS_NOT_IMPLEMENTED
;
3010 RxCommonQuerySecurity(
3011 PRX_CONTEXT Context
)
3014 return STATUS_NOT_IMPLEMENTED
;
3022 RxCommonQueryVolumeInformation(
3023 PRX_CONTEXT Context
)
3029 PIO_STACK_LOCATION Stack
;
3033 Fcb
= (PFCB
)Context
->pFcb
;
3034 Fobx
= (PFOBX
)Context
->pFobx
;
3036 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3038 Irp
= Context
->CurrentIrp
;
3039 Stack
= Context
->CurrentIrpSp
;
3040 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3041 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3043 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3044 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3045 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3047 /* Forward to mini-rdr */
3048 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3050 /* Post request if mini-rdr asked to */
3051 if (Context
->PostRequest
)
3053 Status
= RxFsdPostRequest(Context
);
3057 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3060 DPRINT("Status: %x\n", Status
);
3067 PRX_CONTEXT RxContext
)
3075 PFILE_OBJECT FileObject
;
3076 LARGE_INTEGER ByteOffset
;
3077 PIO_STACK_LOCATION Stack
;
3078 PLOWIO_CONTEXT LowIoContext
;
3079 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3080 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3081 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3085 Fcb
= (PFCB
)RxContext
->pFcb
;
3086 Fobx
= (PFOBX
)RxContext
->pFobx
;
3087 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3089 /* Get some parameters */
3090 Irp
= RxContext
->CurrentIrp
;
3091 Stack
= RxContext
->CurrentIrpSp
;
3092 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3093 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3094 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3095 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3096 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3097 ReadLength
= Stack
->Parameters
.Read
.Length
;
3098 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3099 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3100 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3102 RxItsTheSameContext();
3104 Irp
->IoStatus
.Information
= 0;
3106 /* Should the read be loud - so far, it's just ignored on ReactOS:
3107 * s/DPRINT/DPRINT1/g will make it loud
3109 LowIoContext
= &RxContext
->LowIoContext
;
3110 CheckForLoudOperations(RxContext
);
3111 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3113 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3114 ByteOffset
, ReadLength
,
3115 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3118 RxDeviceObject
= RxContext
->RxDeviceObject
;
3120 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3122 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3124 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3126 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3128 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3132 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3136 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3140 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3144 /* A pagefile cannot be a pipe */
3145 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3146 if (IsPipe
&& PagingIo
)
3148 return STATUS_INVALID_DEVICE_REQUEST
;
3151 /* Null-length read is no-op */
3152 if (ReadLength
== 0)
3154 return STATUS_SUCCESS
;
3157 /* Validate FCB type */
3158 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3160 return STATUS_INVALID_DEVICE_REQUEST
;
3163 /* Init the lowio context for possible forward */
3164 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3166 PostRequest
= FALSE
;
3167 ReadCachingDisabled
= FALSE
;
3169 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3170 FileObject
= Stack
->FileObject
;
3171 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3176 /* If no caching, make sure current Cc data have been flushed */
3177 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3179 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3180 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3185 else if (Status
!= STATUS_SUCCESS
)
3190 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3191 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3192 RxReleasePagingIoResource(RxContext
, Fcb
);
3194 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3196 Status
= Irp
->IoStatus
.Status
;
3200 RxAcquirePagingIoResource(RxContext
, Fcb
);
3201 RxReleasePagingIoResource(RxContext
, Fcb
);
3204 /* Acquire the appropriate lock */
3205 if (PagingIo
&& !ReadCachingEnabled
)
3209 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3217 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3222 if (!ReadCachingEnabled
)
3224 if (!CanWait
&& NoCache
)
3226 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3227 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3229 DPRINT1("RdAsyLNG %x\n", RxContext
);
3233 if (Status
!= STATUS_SUCCESS
)
3235 DPRINT1("RdAsyOthr %x\n", RxContext
);
3239 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3241 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3251 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3252 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3257 else if (Status
!= STATUS_SUCCESS
)
3265 RxItsTheSameContext();
3267 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3273 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3275 /* Make sure FLOCK doesn't conflict */
3278 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3280 Status
= STATUS_FILE_LOCK_CONFLICT
;
3285 /* Validate byteoffset vs length */
3286 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3288 if (ByteOffset
.QuadPart
>= FileSize
)
3290 Status
= STATUS_END_OF_FILE
;
3294 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3296 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3301 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3302 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3304 /* File was not cached yet, do it */
3305 if (FileObject
->PrivateCacheMap
== NULL
)
3307 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3309 Status
= STATUS_FILE_CLOSED
;
3313 RxAdjustAllocationSizeforCC(Fcb
);
3315 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3316 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3318 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3320 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3324 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3325 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3328 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3331 /* This should never happen - fix your RDR */
3332 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3337 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3338 Status
= Irp
->IoStatus
.Status
;
3339 ASSERT(NT_SUCCESS(Status
));
3344 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3345 if (SystemBuffer
== NULL
)
3347 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3351 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3353 RxItsTheSameContext();
3355 /* Perform the read */
3356 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3358 if (!ReadCachingEnabled
)
3360 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3363 RxItsTheSameContext();
3369 if (!ReadCachingEnabled
)
3371 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3374 Status
= Irp
->IoStatus
.Status
;
3375 ASSERT(NT_SUCCESS(Status
));
3380 /* Validate the reading */
3381 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3382 ByteOffset
.QuadPart
>= 4096)
3384 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3385 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3388 /* If it's consistent, forward to mini-rdr */
3389 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3390 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3392 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3393 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3395 RxItsTheSameContext();
3397 if (InFsp
&& ReadCachingDisabled
)
3399 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3400 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3404 Status
= RxLowIoReadShell(RxContext
);
3406 RxItsTheSameContext();
3410 if (ByteOffset
.QuadPart
> FileSize
)
3413 Irp
->IoStatus
.Information
= ReadLength
;
3417 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3419 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3422 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3423 RtlZeroMemory(SystemBuffer
, ReadLength
);
3424 Irp
->IoStatus
.Information
= ReadLength
;
3430 RxItsTheSameContext();
3432 /* Post if required */
3435 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3436 Status
= RxFsdPostRequest(RxContext
);
3440 /* Update FO in case of sync IO */
3441 if (!IsPipe
&& !PagingIo
)
3443 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3445 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3450 /* Set FastIo if read was a success */
3451 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3453 if (!IsPipe
&& !PagingIo
)
3455 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3459 /* In case we're done (not expected any further processing */
3460 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3462 /* Release everything that can be */
3463 if (ReadCachingDisabled
)
3469 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3473 RxReleasePagingIoResource(RxContext
, Fcb
);
3480 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3484 RxReleaseFcb(RxContext
, Fcb
);
3489 /* Dereference/Delete context */
3492 RxDereferenceAndDeleteRxContext(RxContext
);
3496 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3498 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3502 /* We cannot return more than asked */
3503 if (Status
== STATUS_SUCCESS
)
3505 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3512 RxDereferenceAndDeleteRxContext(RxContext
);
3523 PRX_CONTEXT Context
)
3526 return STATUS_NOT_IMPLEMENTED
;
3534 RxCommonSetInformation(
3535 PRX_CONTEXT Context
)
3542 PIO_STACK_LOCATION Stack
;
3543 FILE_INFORMATION_CLASS Class
;
3544 BOOLEAN CanWait
, FcbTableAcquired
, FcbAcquired
;
3548 Fcb
= (PFCB
)Context
->pFcb
;
3549 Fobx
= (PFOBX
)Context
->pFobx
;
3550 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3552 Irp
= Context
->CurrentIrp
;
3553 Stack
= Context
->CurrentIrpSp
;
3554 Class
= Stack
->Parameters
.SetFile
.FileInformationClass
;
3555 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3556 Irp
->AssociatedIrp
.SystemBuffer
, Stack
->Parameters
.SetFile
.Length
,
3557 Class
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
3559 Status
= STATUS_SUCCESS
;
3560 CanWait
= BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3561 FcbTableAcquired
= FALSE
;
3562 FcbAcquired
= FALSE
;
3563 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3565 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3569 /* Valide the node type first */
3570 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3571 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3573 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
3575 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3577 Status
= STATUS_SUCCESS
;
3580 else if (NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
3582 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
3584 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3588 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb
));
3589 _SEH2_TRY_RETURN(Status
= STATUS_INVALID_PARAMETER
);
3594 /* We don't autorize advance operation */
3595 if (Class
== FileEndOfFileInformation
&& Stack
->Parameters
.SetFile
.AdvanceOnly
)
3597 DPRINT1("Not allowed\n");
3599 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3602 /* For these to classes, we'll have to deal with the FCB table (removal)
3603 * We thus need the exclusive FCB table lock
3605 if (Class
== FileDispositionInformation
|| Class
== FileRenameInformation
)
3607 RxPurgeRelatedFobxs(NetRoot
, Context
, TRUE
, Fcb
);
3608 RxScavengeFobxsForNetRoot(NetRoot
, Fcb
, TRUE
);
3610 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, CanWait
))
3612 Context
->PostRequest
= TRUE
;
3613 _SEH2_TRY_RETURN(Status
= STATUS_PENDING
);
3616 FcbTableAcquired
= TRUE
;
3619 /* Finally, if not paging file, we need exclusive FCB lock */
3620 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3622 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
3623 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3625 Context
->PostRequest
= TRUE
;
3626 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3628 else if (Status
!= STATUS_SUCCESS
)
3636 Status
= STATUS_SUCCESS
;
3638 /* And now, perform the job! */
3641 case FileBasicInformation
:
3642 Status
= RxSetBasicInfo(Context
);
3645 case FileDispositionInformation
:
3647 PFILE_DISPOSITION_INFORMATION FDI
;
3649 /* Check whether user wants deletion */
3650 FDI
= Irp
->AssociatedIrp
.SystemBuffer
;
3651 if (FDI
->DeleteFile
)
3653 /* If so, check whether it's doable */
3654 if (!MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForDelete
))
3656 Status
= STATUS_CANNOT_DELETE
;
3659 /* And if doable, already remove from FCB table */
3660 if (Status
== STATUS_SUCCESS
)
3662 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3663 RxRemoveNameNetFcb(Fcb
);
3665 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3666 FcbTableAcquired
= FALSE
;
3670 /* If it succeed, perform the operation */
3671 if (Status
== STATUS_SUCCESS
)
3673 Status
= RxSetDispositionInfo(Context
);
3679 case FilePositionInformation
:
3680 Status
= RxSetPositionInfo(Context
);
3683 case FileAllocationInformation
:
3684 Status
= RxSetAllocationInfo(Context
);
3687 case FileEndOfFileInformation
:
3688 Status
= RxSetEndOfFileInfo(Context
);
3691 case FilePipeInformation
:
3692 case FilePipeLocalInformation
:
3693 case FilePipeRemoteInformation
:
3694 Status
= RxSetPipeInfo(Context
);
3697 case FileRenameInformation
:
3698 case FileLinkInformation
:
3699 case FileMoveClusterInformation
:
3700 /* If we can wait, try to perform the operation right now */
3703 /* Of course, collapsing is not doable anymore, file is
3704 * in an inbetween state
3706 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
3708 /* Set the information */
3709 Status
= RxSetRenameInfo(Context
);
3710 /* If it succeed, drop the current entry from FCB table */
3711 if (Status
== STATUS_SUCCESS
&& Class
== FileRenameInformation
)
3713 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3714 RxRemoveNameNetFcb(Fcb
);
3716 _SEH2_TRY_RETURN(Status
);
3718 /* Can't wait? Post for async retry */
3721 Status
= RxFsdPostRequest(Context
);
3722 _SEH2_TRY_RETURN(Status
);
3726 case FileValidDataLengthInformation
:
3727 if (!MmCanFileBeTruncated(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
))
3729 Status
= STATUS_USER_MAPPED_FILE
;
3733 case FileShortNameInformation
:
3734 Status
= RxSetSimpleInfo(Context
);
3738 DPRINT1("Insupported class: %x\n", Class
);
3739 Status
= STATUS_INVALID_PARAMETER
;
3745 /* If mini-rdr was OK and wants a re-post on this, do it */
3746 if (Status
== STATUS_SUCCESS
)
3748 if (Context
->PostRequest
)
3750 Status
= RxFsdPostRequest(Context
);
3756 /* Release any acquired lock */
3759 RxReleaseFcb(Context
, Fcb
);
3762 if (FcbTableAcquired
)
3764 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3769 #undef _SEH2_TRY_RETURN
3776 RxCommonSetQuotaInformation(
3777 PRX_CONTEXT Context
)
3780 return STATUS_NOT_IMPLEMENTED
;
3785 RxCommonSetSecurity(
3786 PRX_CONTEXT Context
)
3789 return STATUS_NOT_IMPLEMENTED
;
3794 RxCommonSetVolumeInformation(
3795 PRX_CONTEXT Context
)
3798 return STATUS_NOT_IMPLEMENTED
;
3803 RxCommonUnimplemented(
3804 PRX_CONTEXT Context
)
3807 return STATUS_NOT_IMPLEMENTED
;
3813 PRX_CONTEXT RxContext
)
3821 PFILE_OBJECT FileObject
;
3822 PIO_STACK_LOCATION Stack
;
3823 LARGE_INTEGER ByteOffset
;
3824 NODE_TYPE_CODE NodeTypeCode
;
3825 PLOWIO_CONTEXT LowIoContext
;
3826 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3827 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3828 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3829 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3833 Fcb
= (PFCB
)RxContext
->pFcb
;
3834 NodeTypeCode
= NodeType(Fcb
);
3835 /* Validate FCB type */
3836 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3837 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3839 return STATUS_INVALID_DEVICE_REQUEST
;
3842 /* We'll write to file, keep track of it */
3843 Fcb
->IsFileWritten
= TRUE
;
3845 Stack
= RxContext
->CurrentIrpSp
;
3846 /* Set write through if asked */
3847 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3849 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3852 Fobx
= (PFOBX
)RxContext
->pFobx
;
3853 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3855 /* Get some parameters */
3856 Irp
= RxContext
->CurrentIrp
;
3857 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3858 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3859 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3860 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3861 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3862 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3863 WriteLength
= Stack
->Parameters
.Write
.Length
;
3864 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3865 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3866 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3868 RxItsTheSameContext();
3870 RxContext
->FcbResourceAcquired
= FALSE
;
3871 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3873 LowIoContext
= &RxContext
->LowIoContext
;
3874 CheckForLoudOperations(RxContext
);
3875 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3877 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3878 ByteOffset
, WriteLength
,
3879 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3882 RxDeviceObject
= RxContext
->RxDeviceObject
;
3884 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3886 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3888 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3890 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3892 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3896 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3900 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3904 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3908 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3909 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3910 /* Keep track for normal writes */
3911 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3920 /* Zero-length write is immediate success */
3921 if (NormalFile
&& WriteLength
== 0)
3923 return STATUS_SUCCESS
;
3926 /* Check whether we have input data */
3927 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3929 return STATUS_INVALID_PARAMETER
;
3932 /* Are we writting to EOF? */
3933 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3934 /* FIXME: validate length/offset */
3936 /* Get our SRV_OPEN in case of normal write */
3939 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3946 FileObject
= Stack
->FileObject
;
3948 /* If we have caching enabled, check whether we have to defer write */
3951 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3953 if (!CcCanIWrite(FileObject
, WriteLength
,
3954 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3955 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
3959 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3961 RxPrePostIrp(RxContext
, Irp
);
3963 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3965 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
3967 return STATUS_PENDING
;
3972 /* Initialize the low IO context for write */
3973 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
3975 /* Initialize our (many) booleans */
3976 RecursiveWriteThrough
= FALSE
;
3977 CalledByLazyWriter
= FALSE
;
3978 SwitchBackToAsync
= FALSE
;
3979 ExtendingFile
= FALSE
;
3980 ExtendingValidData
= FALSE
;
3981 UnwindOutstandingAsync
= FALSE
;
3982 ResourceOwnerSet
= FALSE
;
3984 ContextReferenced
= FALSE
;
3986 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3990 /* No volume FCB here! */
3991 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
3992 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
3993 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
3995 /* Writing to EOF on a paging file is non sense */
3996 ASSERT(!(WriteToEof
&& PagingIo
));
3998 RxItsTheSameContext();
4000 /* Start locking stuff */
4001 if (!PagingIo
&& !NoPreposting
)
4003 /* If it's already acquired, all fine */
4004 if (RxContext
->FcbResourceAcquired
)
4010 /* Otherwise, try to acquire shared (excepted for pipes) */
4013 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4016 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
4018 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
4022 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
4025 /* We'll post IRP to retry */
4026 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4029 DPRINT1("Failed to acquire lock!\n");
4030 _SEH2_TRY_RETURN(Status
);
4033 /* We'll just fail */
4034 if (Status
!= STATUS_SUCCESS
)
4036 _SEH2_TRY_RETURN(Status
);
4039 /* Resource acquired */
4040 RxContext
->FcbResourceAcquired
= TRUE
;
4043 /* At that point, resource is acquired */
4046 ASSERT(RxContext
->FcbResourceAcquired
);
4052 /* Now, check whether we have to promote shared lock */
4053 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4055 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
4062 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4063 if (RxIsFcbAcquiredShared(Fcb
) &&
4064 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
4068 RxReleaseFcb(RxContext
, Fcb
);
4069 RxContext
->FcbResourceAcquired
= FALSE
;
4071 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4072 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4075 DPRINT1("Failed to acquire lock!\n");
4076 _SEH2_TRY_RETURN(Status
);
4079 if (Status
!= STATUS_SUCCESS
)
4081 _SEH2_TRY_RETURN(Status
);
4084 RxContext
->FcbResourceAcquired
= TRUE
;
4088 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4089 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
4092 if (RxIsFcbAcquiredExclusive(Fcb
))
4094 RxConvertToSharedFcb(RxContext
, Fcb
);
4099 /* We're extending file, disable collapsing */
4100 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
4102 DPRINT("Disabling collapsing\n");
4104 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4106 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
4110 ASSERT(RxContext
->FcbResourceAcquired
);
4113 /* Keep track of the acquired resource */
4114 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
4121 /* Lock the paging resource */
4122 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
4124 /* Keep track of the acquired resource */
4125 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
4131 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
4134 /* If it's a non cached write, or if caching is disallowed */
4135 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4137 /* If cache was previously enabled, we'll have to flush before writing */
4138 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
4140 LARGE_INTEGER FlushOffset
;
4143 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
4145 /* If shared, we'll have to relock exclusive */
4146 if (!RxIsFcbAcquiredExclusive(Fcb
))
4148 /* Release and retry exclusive */
4149 RxReleaseFcb(RxContext
, Fcb
);
4150 RxContext
->FcbResourceAcquired
= FALSE
;
4152 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4153 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4156 DPRINT1("Failed to acquire lock for flush!\n");
4157 _SEH2_TRY_RETURN(Status
);
4160 if (Status
!= STATUS_SUCCESS
)
4162 _SEH2_TRY_RETURN(Status
);
4165 RxContext
->FcbResourceAcquired
= TRUE
;
4168 /* Get the length to flush */
4171 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
4175 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
4178 /* Perform the flushing */
4179 RxAcquirePagingIoResource(RxContext
, Fcb
);
4180 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
4181 WriteLength
, &Irp
->IoStatus
);
4182 RxReleasePagingIoResource(RxContext
, Fcb
);
4184 /* Cannot continue if flushing failed */
4185 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
4187 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
4191 RxAcquirePagingIoResource(RxContext
, Fcb
);
4192 RxReleasePagingIoResource(RxContext
, Fcb
);
4195 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
4196 &FlushOffset
, WriteLength
, FALSE
);
4200 /* If not paging IO, check if write is allowed */
4203 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4205 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4209 /* Get file sizes */
4210 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4211 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4212 ASSERT(ValidDataLength
<= FileSize
);
4214 /* If paging IO, we cannot write past file size
4215 * so fix write length if needed
4219 if (ByteOffset
.QuadPart
>= FileSize
)
4221 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4224 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4226 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4230 /* If we're being called by the lazywrite */
4231 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4233 CalledByLazyWriter
= TRUE
;
4235 /* Fail if we're beyong VDL */
4236 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4238 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4239 (ByteOffset
.QuadPart
< FileSize
))
4241 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4243 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4249 /* If that's a recursive synchronous page write */
4250 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4251 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4255 /* Check the top level IRP on the FastIO path */
4256 TopIrp
= RxGetTopIrpIfRdbssIrp();
4257 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4259 PIO_STACK_LOCATION IrpStack
;
4261 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4263 /* If the top level IRP was a cached write for this file, keep track */
4264 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4265 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4266 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4268 RecursiveWriteThrough
= TRUE
;
4269 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4274 /* Now, deal with file size and VDL */
4275 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4276 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4278 /* Not sync? Let's make it sync, just the time we extended */
4282 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4283 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4286 /* Keep track we'll have to switch back to async */
4289 SwitchBackToAsync
= TRUE
;
4293 /* Release all the locks */
4294 RxWriteReleaseResources(RxContext
, 0);
4296 /* Acquire exclusive */
4297 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4298 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4301 DPRINT1("Failed to acquire lock for extension!\n");
4302 _SEH2_TRY_RETURN(Status
);
4305 if (Status
!= STATUS_SUCCESS
)
4307 _SEH2_TRY_RETURN(Status
);
4310 RxContext
->FcbResourceAcquired
= TRUE
;
4312 RxItsTheSameContext();
4314 /* Get the sizes again, to be sure they didn't change in the meantime */
4315 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4316 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4317 ASSERT(ValidDataLength
<= FileSize
);
4319 /* Check we can switch back to async? */
4320 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4321 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4323 SwitchBackToAsync
= FALSE
;
4326 /* If paging IO, check we don't try to extend the file */
4329 if (ByteOffset
.QuadPart
>= FileSize
)
4331 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4334 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4336 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4341 /* Save our initial sizes for potential rollback */
4342 InitialFileSize
= FileSize
;
4343 InitialValidDataLength
= ValidDataLength
;
4344 /* If writing to EOF, update byte offset with file size */
4347 ByteOffset
.QuadPart
= FileSize
;
4350 /* Check again whether we're allowed to write */
4353 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4355 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4358 /* Do we have to extend? */
4359 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4361 DPRINT("Need to extend file\n");
4362 ExtendingFile
= TRUE
;
4363 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4367 /* Let's start to extend */
4370 /* If we're past allocating, inform mini-rdr */
4371 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4372 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4374 LARGE_INTEGER NewAllocationSize
;
4376 DPRINT("Extending %p\n", RxContext
);
4380 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4381 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4382 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4386 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4387 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4388 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4391 if (!NT_SUCCESS(Status
))
4393 _SEH2_TRY_RETURN(Status
);
4396 if (FileSize
> NewAllocationSize
.QuadPart
)
4398 NewAllocationSize
.QuadPart
= FileSize
;
4401 /* And update FCB */
4402 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4405 /* Set the new sizes */
4406 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4407 RxAdjustAllocationSizeforCC(Fcb
);
4410 if (CcIsFileCached(FileObject
))
4412 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4416 /* Do we have to extend VDL? */
4417 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4419 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4421 ExtendingValidData
= TRUE
;
4422 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4426 /* If none cached write */
4427 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4429 /* Switch back to async, if asked to */
4430 if (SwitchBackToAsync
)
4435 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4436 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4439 /* If not synchronous, keep track of writes to be finished */
4442 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4444 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4445 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4446 NotificationEvent
, FALSE
);
4449 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4451 &RxStrucSupSpinLock
) == 0)
4453 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4456 UnwindOutstandingAsync
= TRUE
;
4457 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4460 /* Set our LOWIO_CONTEXT information */
4461 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4462 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4464 RxItsTheSameContext();
4466 /* We have to be locked */
4467 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4469 /* Update thread ID if we're in FSP */
4472 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4474 if (RxContext
->FcbResourceAcquired
)
4476 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4479 if (RxContext
->FcbPagingIoResourceAcquired
)
4481 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4484 ResourceOwnerSet
= TRUE
;
4487 /* And perform the write */
4488 Status
= RxLowIoWriteShell(RxContext
);
4490 RxItsTheSameContext();
4492 /* Not outstanding write anymore */
4493 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4495 UnwindOutstandingAsync
= FALSE
;
4501 /* If cache wasn't enabled yet, do it */
4502 if (FileObject
->PrivateCacheMap
== NULL
)
4504 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4506 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4509 RxAdjustAllocationSizeforCC(Fcb
);
4511 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4512 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4514 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4517 /* If that's a MDL backed write */
4518 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4520 /* Shouldn't happen */
4524 /* Perform it, though */
4525 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4526 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4528 Status
= Irp
->IoStatus
.Status
;
4533 ULONG BreakpointsSave
;
4535 /* Map the user buffer */
4536 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4537 if (SystemBuffer
== NULL
)
4539 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4542 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4544 RxItsTheSameContext();
4546 /* And deal with Cc */
4547 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4550 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4552 RxItsTheSameContext();
4554 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4555 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4561 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4562 Irp
->IoStatus
.Information
= WriteLength
;
4564 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4566 RxItsTheSameContext();
4568 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4569 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4576 /* If we've to post the IRP */
4579 /* Reset the file size if required */
4580 if (ExtendingFile
&& !IsPipe
)
4582 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4583 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4585 RxAcquirePagingIoResource(RxContext
, Fcb
);
4586 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4587 RxReleasePagingIoResource(RxContext
, Fcb
);
4589 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4591 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4595 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4596 ContextReferenced
= TRUE
;
4599 ASSERT(!ResourceOwnerSet
);
4600 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4602 #ifdef RDBSS_TRACKER
4603 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4606 /* And post the request */
4607 Status
= RxFsdPostRequest(RxContext
);
4613 /* Update FILE_OBJECT if synchronous write succeed */
4616 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4618 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4622 /* If write succeed, ,also update FILE_OBJECT flags */
4623 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4625 /* File was modified */
4628 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4631 /* If was even extended */
4634 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4637 /* If VDL was extended, update FCB and inform Cc */
4638 if (ExtendingValidData
)
4640 LONGLONG LastOffset
;
4642 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4643 if (FileSize
< LastOffset
)
4645 LastOffset
= FileSize
;
4648 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4650 if (NoCache
&& CcIsFileCached(FileObject
))
4652 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4661 /* Finally, if we failed while extension was required */
4662 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4667 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4669 RxAcquirePagingIoResource(RxContext
, Fcb
);
4670 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4671 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4672 RxReleasePagingIoResource(RxContext
, Fcb
);
4674 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4676 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4681 /* One async write less */
4682 if (UnwindOutstandingAsync
)
4686 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4687 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4690 /* And now, cleanup everything */
4691 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4693 /* If we didn't post, release every lock (for posting, it's already done) */
4696 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4699 /* If the context was referenced - posting, dereference it */
4700 if (ContextReferenced
)
4702 RxDereferenceAndDeleteRxContext(RxContext
);
4705 /* If that's a pipe operation, resume any blocked one */
4708 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4710 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4714 /* Sanity check for write */
4715 if (Status
== STATUS_SUCCESS
)
4717 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4720 /* Just dereference our context */
4724 RxDereferenceAndDeleteRxContext(RxContext
);
4729 #undef _SEH2_TRY_RETURN
4740 IN PRX_CONTEXT RxContext
)
4743 PFILE_OBJECT FileObject
;
4744 PIO_STACK_LOCATION Stack
;
4746 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4750 Irp
= RxContext
->CurrentIrp
;
4751 Stack
= RxContext
->CurrentIrpSp
;
4752 FileObject
= Stack
->FileObject
;
4754 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4755 switch (RxContext
->MajorFunction
)
4757 /* Call the Cc function */
4759 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4763 /* If here, we can wait */
4764 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4766 /* Call the Cc function */
4767 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4769 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4773 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4774 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4779 Irp
->MdlAddress
= NULL
;
4781 /* And complete the IRP */
4782 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4784 #undef BugCheckFileId
4786 return STATUS_SUCCESS
;
4793 RxCopyCreateParameters(
4794 IN PRX_CONTEXT RxContext
)
4798 PFILE_OBJECT FileObject
;
4799 PIO_STACK_LOCATION Stack
;
4800 PDFS_NAME_CONTEXT DfsNameContext
;
4801 PIO_SECURITY_CONTEXT SecurityContext
;
4803 Irp
= RxContext
->CurrentIrp
;
4804 Stack
= RxContext
->CurrentIrpSp
;
4805 FileObject
= Stack
->FileObject
;
4806 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4808 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4809 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4811 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4812 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4813 RxContext
->Create
.SdLength
);
4815 if (SecurityContext
->SecurityQos
!= NULL
)
4817 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4821 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4823 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4825 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4826 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4827 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4828 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4829 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4831 DfsContext
= FileObject
->FsContext2
;
4832 DfsNameContext
= FileObject
->FsContext
;
4833 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4834 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4835 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4836 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4837 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4838 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4839 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4840 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4841 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4842 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4843 FileObject
->FsContext2
= NULL
;
4844 FileObject
->FsContext
= NULL
;
4846 RxContext
->pFcb
= NULL
;
4847 RxContext
->Create
.ReturnedCreateInformation
= 0;
4849 /* if we stripped last \, it has to be a directory! */
4850 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4852 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4855 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4856 if (RxContext
->Create
.EaLength
== 0)
4858 RxContext
->Create
.EaBuffer
= NULL
;
4862 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4863 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4868 RxCreateFromNetRoot(
4869 PRX_CONTEXT Context
,
4870 PUNICODE_STRING NetRootName
)
4875 PFILE_OBJECT FileObject
;
4876 PIO_STACK_LOCATION Stack
;
4877 ACCESS_MASK DesiredAccess
;
4878 USHORT DesiredShareAccess
;
4882 /* Validate that the context is consistent */
4883 if (Context
->Create
.pNetRoot
== NULL
)
4885 return STATUS_BAD_NETWORK_PATH
;
4888 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
4889 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
4891 return STATUS_BAD_NETWORK_PATH
;
4894 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
4895 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
4897 return STATUS_DFS_UNAVAILABLE
;
4900 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
4901 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
4903 return STATUS_OBJECT_TYPE_MISMATCH
;
4906 Stack
= Context
->CurrentIrpSp
;
4907 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4908 if (NetRoot
->Type
== NET_ROOT_PRINT
)
4910 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
4913 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
4915 /* Get file object */
4916 FileObject
= Stack
->FileObject
;
4918 /* Do we have to open target directory for renaming? */
4919 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
4921 DPRINT("Opening target directory\n");
4923 /* If we have been asked for delete, try to purge first */
4924 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
))
4926 RxPurgeRelatedFobxs((PNET_ROOT
)Context
->Create
.pVNetRoot
->pNetRoot
, Context
,
4927 ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
4930 /* Create the FCB */
4931 Fcb
= RxCreateNetFcb(Context
, (PV_NET_ROOT
)Context
->Create
.pVNetRoot
, NetRootName
);
4934 return STATUS_INSUFFICIENT_RESOURCES
;
4937 /* Fake it: it will be used only renaming */
4938 NodeType(Fcb
) = RDBSS_NTC_OPENTARGETDIR_FCB
;
4939 Context
->Create
.FcbAcquired
= FALSE
;
4940 Context
->Create
.NetNamePrefixEntry
= NULL
;
4942 /* Assign it to the FO */
4943 FileObject
->FsContext
= Fcb
;
4945 /* If we have a FOBX already, check whether it's for DFS opening */
4946 if (Context
->pFobx
!= NULL
)
4948 /* If so, reflect this in the FOBX */
4949 if (FileObject
->FsContext2
== UIntToPtr(DFS_OPEN_CONTEXT
))
4951 SetFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
4955 ClearFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
4959 /* Acquire the FCB */
4960 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
4961 if (Status
!= STATUS_SUCCESS
)
4966 /* Reference the FCB and release */
4967 RxReferenceNetFcb(Fcb
);
4968 RxReleaseFcb(Context
, Fcb
);
4971 return STATUS_SUCCESS
;
4974 /* Try to find (or create) the FCB for the file */
4975 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
4976 Fcb
= (PFCB
)Context
->pFcb
;
4979 ASSERT(!NT_SUCCESS(Status
));
4981 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
4986 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
4988 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
4992 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
4995 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4996 if (NT_SUCCESS(Status
))
4998 RxTransitionNetFcb(Fcb
, Condition_Good
);
4999 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
5001 RxSetupNetFileObject(Context
);
5002 return STATUS_SUCCESS
;
5006 /* Check SA for conflict */
5007 if (Fcb
->OpenCount
> 0)
5009 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5010 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
5011 if (!NT_SUCCESS(Status
))
5013 RxDereferenceNetFcb(Fcb
);
5018 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
5019 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
5026 /* Find a SRV_OPEN that suits the opening */
5027 Status
= RxCollapseOrCreateSrvOpen(Context
);
5028 if (Status
== STATUS_SUCCESS
)
5033 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
5034 Fobx
= (PFOBX
)Context
->pFobx
;
5035 /* There are already opens, check for conflict */
5036 if (Fcb
->OpenCount
!= 0)
5038 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
5039 FileObject
, &Fcb
->ShareAccess
,
5040 FALSE
, "second check per useropens",
5043 ++SrvOpen
->UncleanFobxCount
;
5044 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
5051 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
5053 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5054 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
5058 RxSetupNetFileObject(Context
);
5060 /* No conflict? Set up SA */
5061 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
5063 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
5066 ++Fcb
->UncleanCount
;
5067 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
5069 ++Fcb
->UncachedUncleanCount
;
5072 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
5073 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
5075 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
5078 /* No pending close, we're active */
5079 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
5082 ++SrvOpen
->UncleanFobxCount
;
5083 ++SrvOpen
->OpenCount
;
5084 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
5086 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
5088 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
5089 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
5091 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
5092 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
5094 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5097 /* Now, update SA for the SRV_OPEN */
5098 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
5100 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
5102 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
5105 /* Update the FOBX info */
5108 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5110 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
5113 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
5114 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5116 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
5118 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
5119 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
5121 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
5122 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
5123 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
5125 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
5126 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
5130 Status
= STATUS_SUCCESS
;
5135 if (Fcb
->OpenCount
== 0)
5137 if (Context
->Create
.FcbAcquired
)
5139 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
5143 if (!Context
->Create
.FcbAcquired
)
5145 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
5151 RxDereferenceNetFcb(Fcb
);
5163 RxCreateTreeConnect(
5164 IN PRX_CONTEXT RxContext
)
5167 PV_NET_ROOT VNetRoot
;
5168 PFILE_OBJECT FileObject
;
5169 PIO_STACK_LOCATION Stack
;
5170 NET_ROOT_TYPE NetRootType
;
5171 UNICODE_STRING CanonicalName
, RemainingName
;
5175 Stack
= RxContext
->CurrentIrpSp
;
5176 FileObject
= Stack
->FileObject
;
5178 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
5179 /* As long as we don't know connection type, mark it wild */
5180 NetRootType
= NET_ROOT_WILD
;
5181 /* Get the type by parsing the name */
5182 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
5183 if (!NT_SUCCESS(Status
))
5188 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
5189 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
5190 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
5191 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
5192 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
5193 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
5195 /* We don't handle EA - they come from DFS, don't care */
5196 if (Stack
->Parameters
.Create
.EaLength
> 0)
5201 /* Mount if required */
5202 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5203 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
5205 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
5206 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5209 if (!NT_SUCCESS(Status
))
5214 /* Validate the rest of the name with mini-rdr */
5215 if (RemainingName
.Length
> 0)
5217 MINIRDR_CALL(Status
, RxContext
,
5218 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5219 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
5222 if (!NT_SUCCESS(Status
))
5227 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5228 RxReferenceVNetRoot(VNetRoot
);
5229 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
5231 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
5234 FileObject
->FsContext
= &RxDeviceFCB
;
5235 FileObject
->FsContext2
= VNetRoot
;
5237 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
5238 ++VNetRoot
->NumberOfOpens
;
5240 /* Create is over - clear context */
5241 RxContext
->Create
.pSrvCall
= NULL
;
5242 RxContext
->Create
.pNetRoot
= NULL
;
5243 RxContext
->Create
.pVNetRoot
= NULL
;
5250 RxDebugControlCommand(
5251 _In_ PSTR ControlString
)
5259 IN PDRIVER_OBJECT DriverObject
,
5260 IN PUNICODE_STRING RegistryPath
)
5263 USHORT i
, State
= 0;
5265 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
5269 RxCheckFcbStructuresForAlignment();
5271 RtlZeroMemory(&RxData
, sizeof(RxData
));
5272 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
5273 RxData
.NodeByteSize
= sizeof(RxData
);
5274 RxData
.DriverObject
= DriverObject
;
5276 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
5277 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
5278 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5280 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5281 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5283 RxInitializeDebugSupport();
5285 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5286 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5291 RxGetRegistryParameters(RegistryPath
);
5292 RxReadRegistryParameters();
5294 Status
= RxInitializeRegistrationStructures();
5295 if (!NT_SUCCESS(Status
))
5301 RxInitializeDispatcher();
5303 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5305 InitializeListHead(&RxIrpsList
);
5306 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5308 InitializeListHead(&RxActiveContexts
);
5309 InitializeListHead(&RxSrvCalldownList
);
5311 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5312 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5313 KeInitializeMutex(&RxScavengerMutex
, 1);
5314 KeInitializeMutex(&RxSerializationMutex
, 1);
5316 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5318 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5319 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5320 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5323 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5325 RxInitializeDispatchVectors(DriverObject
);
5327 ExInitializeResourceLite(&RxData
.Resource
);
5328 RxData
.OurProcess
= IoGetCurrentProcess();
5330 RxInitializeRxTimer();
5334 if (!NT_SUCCESS(Status
))
5336 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5337 RxInitUnwind(DriverObject
, State
);
5341 /* There are still bits to init - be consider it's fine for now */
5344 return STATUS_NOT_IMPLEMENTED
;
5346 return STATUS_SUCCESS
;
5355 RxDumpCurrentAccess(
5358 _In_ PSZ wherelogtag
,
5359 _In_ PSHARE_ACCESS ShareAccess
)
5371 _In_ PSZ wherelogtag
,
5372 _In_ ACCESS_MASK DesiredAccess
,
5373 _In_ ULONG DesiredShareAccess
)
5384 RxFastIoCheckIfPossible(
5385 PFILE_OBJECT FileObject
,
5386 PLARGE_INTEGER FileOffset
,
5387 ULONG Length
, BOOLEAN Wait
,
5388 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5389 PIO_STATUS_BLOCK IoStatus
,
5390 PDEVICE_OBJECT DeviceObject
)
5394 LARGE_INTEGER LargeLength
;
5398 /* Get the FCB to validate it */
5399 Fcb
= FileObject
->FsContext
;
5400 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5402 DPRINT1("Not a file, FastIO not possible!\n");
5406 if (FileObject
->DeletePending
)
5408 DPRINT1("File delete pending\n");
5412 /* If there's a pending write operation, deny fast operation */
5413 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5415 DPRINT1("Write operations to be completed\n");
5419 /* Deny read on orphaned node */
5420 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5421 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5423 DPRINT1("SRV_OPEN orphaned\n");
5427 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5429 DPRINT1("FCB orphaned\n");
5433 /* If there's a buffering state change pending, deny fast operation (it might change
5436 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5438 DPRINT1("Buffering change pending\n");
5442 /* File got renamed/deleted, deny operation */
5443 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5444 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5446 DPRINT1("File renamed/deleted\n");
5450 /* Process pending change buffering state operations */
5451 FsRtlEnterFileSystem();
5452 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5453 FsRtlExitFileSystem();
5455 LargeLength
.QuadPart
= Length
;
5457 /* If operation to come is a read operation */
5458 if (CheckForReadOperation
)
5460 /* Check that read cache is enabled */
5461 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5463 DPRINT1("Read caching disabled\n");
5467 /* Check whether there's a lock conflict */
5468 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5473 PsGetCurrentProcess()))
5475 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5482 /* Check that write cache is enabled */
5483 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
))
5485 DPRINT1("Write caching disabled\n");
5489 /* Check whether there's a lock conflict */
5490 if (!FsRtlFastCheckLockForWrite(&Fcb
->Specific
.Fcb
.FileLock
,
5495 PsGetCurrentProcess()))
5497 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5506 RxFastIoDeviceControl(
5507 PFILE_OBJECT FileObject
,
5509 PVOID InputBuffer OPTIONAL
,
5510 ULONG InputBufferLength
,
5511 PVOID OutputBuffer OPTIONAL
,
5512 ULONG OutputBufferLength
,
5513 ULONG IoControlCode
,
5514 PIO_STATUS_BLOCK IoStatus
,
5515 PDEVICE_OBJECT DeviceObject
)
5517 /* Only supported IOCTL */
5518 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5535 PFILE_OBJECT FileObject
,
5536 PLARGE_INTEGER FileOffset
,
5541 PIO_STATUS_BLOCK IoStatus
,
5542 PDEVICE_OBJECT DeviceObject
)
5545 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5549 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5550 FileObject
->FsContext2
);
5551 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5553 /* Prepare a TLI context */
5554 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5555 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5556 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5558 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5559 IoStatus
, DeviceObject
, &TopLevelContext
);
5562 DPRINT("Read OK\n");
5566 DPRINT1("Read failed!\n");
5578 PFILE_OBJECT FileObject
,
5579 PLARGE_INTEGER FileOffset
,
5584 PIO_STATUS_BLOCK IoStatus
,
5585 PDEVICE_OBJECT DeviceObject
)
5589 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5593 Fobx
= (PFOBX
)FileObject
->FsContext2
;
5594 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_BAD_HANDLE
))
5599 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5600 FileObject
->FsContext2
);
5601 DPRINT("Writing %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5603 /* Prepare a TLI context */
5604 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5605 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5606 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5608 Ret
= FsRtlCopyWrite2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5609 IoStatus
, DeviceObject
, &TopLevelContext
);
5612 DPRINT("Write OK\n");
5616 DPRINT1("Write failed!\n");
5624 PRX_CONTEXT RxContext
,
5625 PUNICODE_STRING NetRootName
)
5631 PV_NET_ROOT VNetRoot
;
5632 BOOLEAN TableAcquired
, AcquiredExclusive
;
5636 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5637 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5638 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5640 Status
= STATUS_SUCCESS
;
5641 AcquiredExclusive
= FALSE
;
5643 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5644 TableAcquired
= TRUE
;
5645 Version
= NetRoot
->FcbTable
.Version
;
5647 /* Look for a cached FCB */
5648 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5651 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5655 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5656 /* If FCB was to be orphaned, consider it as not suitable */
5657 if (Fcb
->fShouldBeOrphaned
)
5659 RxDereferenceNetFcb(Fcb
);
5660 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5662 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5663 TableAcquired
= TRUE
;
5664 AcquiredExclusive
= TRUE
;
5666 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5667 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5669 RxOrphanThisFcb(Fcb
);
5670 RxDereferenceNetFcb(Fcb
);
5676 /* If FCB was not found or is not covering full path, prepare for more work */
5677 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5681 DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb
->FcbTableEntry
.Path
, NetRootName
);
5684 if (!AcquiredExclusive
)
5686 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5687 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5688 TableAcquired
= TRUE
;
5691 /* If FCB table was updated in between, re-attempt a lookup */
5692 if (NetRoot
->FcbTable
.Version
!= Version
)
5694 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5695 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5702 /* Allocate the FCB */
5707 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5710 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5714 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5715 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5721 if (_SEH2_AbnormalTermination())
5723 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5724 TableAcquired
= FALSE
;
5728 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5730 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5731 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5733 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5742 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5745 if (!NT_SUCCESS(Status
))
5750 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5751 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5753 if (!RxContext
->Create
.FcbAcquired
)
5755 RxWaitForStableNetFcb(Fcb
, RxContext
);
5756 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5757 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5764 RxFirstCanonicalize(
5765 PRX_CONTEXT RxContext
,
5766 PUNICODE_STRING FileName
,
5767 PUNICODE_STRING CanonicalName
,
5768 PNET_ROOT_TYPE NetRootType
)
5772 BOOLEAN UncName
, PrependString
, IsSpecial
;
5773 USHORT CanonicalLength
;
5774 UNICODE_STRING SessionIdString
;
5775 WCHAR SessionIdBuffer
[16];
5779 Type
= NET_ROOT_WILD
;
5780 PrependString
= FALSE
;
5783 Status
= STATUS_SUCCESS
;
5785 /* Name has to contain at least \\ */
5786 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5788 return STATUS_OBJECT_NAME_INVALID
;
5791 /* First easy check, is that a path with a name? */
5792 CanonicalLength
= FileName
->Length
;
5793 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5795 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5797 if (FileName
->Buffer
[3] == ':')
5799 Type
= NET_ROOT_DISK
;
5803 Type
= NET_ROOT_PRINT
;
5808 /* Nope, attempt deeper parsing */
5809 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5812 PWSTR FirstSlash
, EndOfString
;
5814 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5817 /* The lack of drive letter will be replaced by session ID */
5818 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5819 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5820 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5822 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5823 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5825 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5831 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5833 Status
= STATUS_OBJECT_NAME_INVALID
;
5838 DPRINT1("WARNING: Assuming not special + disk!\n");
5839 Type
= NET_ROOT_DISK
;
5840 Status
= STATUS_SUCCESS
;
5841 //Status = STATUS_NOT_IMPLEMENTED;
5842 /* Should be check against IPC, mailslot, and so on */
5846 /* Update net root type with our deduced one */
5847 *NetRootType
= Type
;
5848 DPRINT("Returning type: %x\n", Type
);
5850 if (!NT_SUCCESS(Status
))
5855 /* Do we have to prepend session ID? */
5860 PrependString
= TRUE
;
5861 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5865 /* If not UNC path, we should preprend stuff */
5866 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5868 return STATUS_OBJECT_PATH_INVALID
;
5871 /* Allocate the buffer */
5872 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
5873 if (!NT_SUCCESS(Status
))
5878 /* We don't support that case, we always return disk */
5881 ASSERT(CanonicalName
->Length
== CanonicalLength
);
5883 Status
= STATUS_NOT_IMPLEMENTED
;
5887 /* If we have to prepend, go ahead */
5890 CanonicalName
->Buffer
[0] = '\\';
5891 CanonicalName
->Buffer
[1] = ';';
5892 CanonicalName
->Buffer
[2] = ':';
5893 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
5894 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
5895 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
5897 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
5899 /* Otherwise, that's a simple copy */
5902 RtlCopyUnicodeString(CanonicalName
, FileName
);
5913 RxFreeCanonicalNameBuffer(
5914 PRX_CONTEXT Context
)
5916 /* These two buffers are always the same */
5917 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
5919 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
5921 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
5922 Context
->Create
.CanonicalNameBuffer
= NULL
;
5923 Context
->AlsoCanonicalNameBuffer
= NULL
;
5926 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
5930 RxFsdCommonDispatch(
5931 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
5932 UCHAR MajorFunction
,
5933 PIO_STACK_LOCATION Stack
,
5934 PFILE_OBJECT FileObject
,
5936 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
5940 PRX_CONTEXT Context
;
5941 UCHAR MinorFunction
;
5942 PFILE_OBJECT StackFileObject
;
5943 PRX_FSD_DISPATCH DispatchFunc
;
5944 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5945 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
5947 Status
= STATUS_SUCCESS
;
5949 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
5951 FsRtlEnterFileSystem();
5953 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
5959 PostRequest
= FALSE
;
5960 SetCancelRoutine
= TRUE
;
5961 MinorFunction
= Stack
->MinorFunction
;
5963 switch (MajorFunction
)
5965 case IRP_MJ_FILE_SYSTEM_CONTROL
:
5966 if (FileObject
!= NULL
)
5968 CanWait
= IoIsOperationSynchronous(Irp
);
5978 case IRP_MJ_QUERY_INFORMATION
:
5979 case IRP_MJ_SET_INFORMATION
:
5980 case IRP_MJ_QUERY_EA
:
5982 case IRP_MJ_FLUSH_BUFFERS
:
5983 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
5984 case IRP_MJ_SET_VOLUME_INFORMATION
:
5985 case IRP_MJ_DIRECTORY_CONTROL
:
5986 case IRP_MJ_DEVICE_CONTROL
:
5987 case IRP_MJ_LOCK_CONTROL
:
5988 case IRP_MJ_QUERY_SECURITY
:
5989 case IRP_MJ_SET_SECURITY
:
5990 CanWait
= IoIsOperationSynchronous(Irp
);
5994 case IRP_MJ_CLEANUP
:
5996 SetCancelRoutine
= FALSE
;
6003 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
6004 /* Should we stop it right now, or mini-rdr deserves to know? */
6005 PassToDriver
= TRUE
;
6006 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
6008 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
6010 PassToDriver
= FALSE
;
6011 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6012 DPRINT1("Not started!\n");
6017 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
6019 PassToDriver
= FALSE
;
6020 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6021 DPRINT1("Not started!\n");
6024 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
6026 StackFileObject
= Stack
->FileObject
;
6027 /* Make sure we don't deal with orphaned stuff */
6028 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
6030 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
6031 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
6032 StackFileObject
->FsContext
!= &RxDeviceFCB
)
6037 Fcb
= StackFileObject
->FsContext
;
6038 Fobx
= StackFileObject
->FsContext2
;
6040 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
6041 ((Fobx
!= NULL
) && BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
)))
6045 PassToDriver
= TRUE
;
6049 PassToDriver
= FALSE
;
6050 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
6051 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
6057 /* Did we receive a close request whereas we're stopping? */
6058 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
6062 Fcb
= StackFileObject
->FsContext
;
6064 DPRINT1("Close received after stop\n");
6065 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6066 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
6068 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
6071 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6072 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
6076 /* Should we stop the whole thing now? */
6079 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
6081 IoMarkIrpPending(Irp
);
6082 Irp
->IoStatus
.Status
= Status
;
6083 Irp
->IoStatus
.Information
= 0;
6084 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6085 Status
= STATUS_PENDING
;
6089 Irp
->IoStatus
.Status
= Status
;
6090 Irp
->IoStatus
.Information
= 0;
6091 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6097 /* No? Allocate a context to deal with the mini-rdr */
6098 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
6099 if (Context
== NULL
)
6101 Status
= STATUS_INSUFFICIENT_RESOURCES
;
6102 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
6106 /* Set cancel routine if required */
6107 if (SetCancelRoutine
)
6109 IoAcquireCancelSpinLock(&OldIrql
);
6110 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
6114 IoAcquireCancelSpinLock(&OldIrql
);
6115 IoSetCancelRoutine(Irp
, NULL
);
6117 IoReleaseCancelSpinLock(OldIrql
);
6119 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6121 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6122 Irp
->IoStatus
.Information
= 0;
6123 /* Get the dispatch routine */
6124 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
6126 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
6128 /* Handle the complete MDL case */
6129 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
6131 DispatchFunc
= RxCompleteMdl
;
6135 /* Do we have to post request? */
6136 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
6142 /* Our read function needs stack, make sure we won't overflow,
6143 * otherwise, post the request
6145 if (MajorFunction
== IRP_MJ_READ
)
6147 if (IoGetRemainingStackSize() < 0xE00)
6149 Context
->PendingReturned
= TRUE
;
6150 Status
= RxPostStackOverflowRead(Context
);
6151 if (Status
!= STATUS_PENDING
)
6153 Context
->PendingReturned
= FALSE
;
6154 RxCompleteAsynchronousRequest(Context
, Status
);
6164 Context
->ResumeRoutine
= DispatchFunc
;
6165 /* There's a dispatch routine? Time to dispatch! */
6166 if (DispatchFunc
!= NULL
)
6168 Context
->PendingReturned
= TRUE
;
6171 Status
= RxFsdPostRequest(Context
);
6175 /* Retry as long as we have */
6178 Status
= DispatchFunc(Context
);
6180 while (Status
== STATUS_RETRY
);
6182 if (Status
== STATUS_PENDING
)
6187 /* Sanity check: did someone mess with our context? */
6188 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
6189 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
6191 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
6192 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
6193 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
6194 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
6195 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
6197 Context
->PendingReturned
= FALSE
;
6198 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
6203 Status
= STATUS_NOT_IMPLEMENTED
;
6210 RxUnwindTopLevelIrp(&TopLevelContext
);
6213 FsRtlExitFileSystem();
6217 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
6227 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
6231 PIO_STACK_LOCATION Stack
;
6232 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
6236 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
6238 Stack
= IoGetCurrentIrpStackLocation(Irp
);
6240 /* Dispatch easy case */
6241 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
6243 return RxSystemControl(RxDeviceObject
, Irp
);
6246 /* Bail out broken cases */
6247 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
6248 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
6250 IoMarkIrpPending(Irp
);
6251 Irp
->IoStatus
.Information
= 0;
6252 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
6253 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6254 return STATUS_PENDING
;
6257 /* Immediately handle create */
6258 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
6260 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6263 /* If not a creation, we must have at least a FO with a FCB */
6264 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
6266 IoMarkIrpPending(Irp
);
6267 Irp
->IoStatus
.Information
= 0;
6268 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6269 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6270 return STATUS_PENDING
;
6273 /* Set the dispatch vector if required */
6274 Fcb
= Stack
->FileObject
->FsContext
;
6275 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
6277 DispatchVector
= &RxFsdDispatchVector
[0];
6281 DispatchVector
= Fcb
->PrivateDispatchVector
;
6284 /* Device cannot accept such requests */
6285 if (RxDeviceObject
== RxFileSystemDeviceObject
)
6287 IoMarkIrpPending(Irp
);
6288 Irp
->IoStatus
.Information
= 0;
6289 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6290 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6291 return STATUS_PENDING
;
6294 /* Dispatch for real! */
6295 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6303 IN PRX_CONTEXT RxContext
)
6305 /* Initialize posting if required */
6306 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
6308 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
6311 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6312 RxContext
->MinorFunction
, RxContext
,
6313 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6314 RxContext
->SerialNumber
);
6316 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
6317 return STATUS_PENDING
;
6329 WORK_QUEUE_TYPE Queue
;
6330 PRDBSS_DEVICE_OBJECT VolumeDO
;
6331 PRX_CONTEXT RxContext
, EntryContext
;
6335 RxContext
= Context
;
6336 EntryContext
= Context
;
6337 /* Save IRQL at entry for later checking */
6338 EntryIrql
= KeGetCurrentIrql();
6340 /* No FO, deal with device */
6341 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6343 VolumeDO
= RxFileSystemDeviceObject
;
6350 /* Which queue to used for delayed? */
6351 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6353 Queue
= DelayedWorkQueue
;
6357 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6358 Queue
= CriticalWorkQueue
;
6365 BOOLEAN RecursiveCall
;
6366 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6368 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6369 ASSERT(!RxContext
->PostRequest
);
6371 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6372 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6374 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext
->MinorFunction
,
6375 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6376 RxContext
->SerialNumber
);
6378 Irp
= RxContext
->CurrentIrp
;
6380 FsRtlEnterFileSystem();
6382 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6383 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6384 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6385 RxContext
->RxDeviceObject
, TRUE
);
6387 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6389 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6391 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6392 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6395 /* Call the resume routine */
6400 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6402 Status
= RxContext
->ResumeRoutine(RxContext
);
6403 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6405 if (Status
!= STATUS_RETRY
)
6407 Status
= RxCompleteRequest(RxContext
, Status
);
6411 while (Status
== STATUS_RETRY
);
6413 RxUnwindTopLevelIrp(&TopLevelContext
);
6414 FsRtlExitFileSystem();
6416 if (VolumeDO
!= NULL
)
6418 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6424 } while (RxContext
!= NULL
);
6426 /* Did we mess with IRQL? */
6427 if (KeGetCurrentIrql() >= APC_LEVEL
)
6429 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6437 RxGetNetworkProviderPriority(
6438 PUNICODE_STRING DeviceName
)
6449 RxGetRegistryParameters(
6450 IN PUNICODE_STRING RegistryPath
)
6454 UCHAR Buffer
[0x400];
6455 HANDLE DriverHandle
, KeyHandle
;
6456 UNICODE_STRING KeyName
, OutString
;
6457 OBJECT_ATTRIBUTES ObjectAttributes
;
6461 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6462 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6463 if (!NT_SUCCESS(Status
))
6468 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6469 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6470 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6471 if (NT_SUCCESS(Status
))
6473 /* The only parameter we deal with is InitialDebugString */
6474 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6475 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6480 Read
= OutString
.Buffer
;
6481 Write
= (PSTR
)OutString
.Buffer
;
6482 for (i
= 0; i
< OutString
.Length
; ++i
)
6490 /* Which is a string we'll just write out */
6491 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6492 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6498 ZwClose(DriverHandle
);
6506 IN PIO_STACK_LOCATION IrpSp
)
6509 PACCESS_TOKEN Token
;
6510 PIO_SECURITY_CONTEXT SecurityContext
;
6514 /* If that's not a prefix claim, not an open request, session id will be 0 */
6515 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6517 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6522 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6526 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6529 /* Query the session id */
6530 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6531 SeQuerySessionIdToken(Token
, &SessionId
);
6541 RxGetStringRegistryParameter(
6542 IN HANDLE KeyHandle
,
6544 OUT PUNICODE_STRING OutString
,
6546 IN ULONG BufferLength
,
6547 IN BOOLEAN LogFailure
)
6551 UNICODE_STRING KeyString
;
6555 RtlInitUnicodeString(&KeyString
, KeyName
);
6556 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6557 OutString
->Length
= 0;
6558 OutString
->Buffer
= 0;
6559 if (!NT_SUCCESS(Status
))
6563 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6569 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6570 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6571 OutString
->MaximumLength
= OutString
->Length
;
6573 return STATUS_SUCCESS
;
6579 PRDBSS_DEVICE_OBJECT
6580 RxGetTopDeviceObjectIfRdbssIrp(
6584 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6586 TopLevelIrp
= IoGetTopLevelIrp();
6587 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6589 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6599 RxGetTopIrpIfRdbssIrp(
6603 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6605 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6606 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6608 Irp
= TopLevel
->Irp
;
6619 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6622 PACCESS_TOKEN Token
;
6626 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6627 SeQueryAuthenticationIdToken(Token
, &Luid
);
6634 RxIndicateChangeOfBufferingStateForSrvOpen(
6635 PMRX_SRV_CALL SrvCall
,
6636 PMRX_SRV_OPEN SrvOpen
,
6645 RxInitializeDebugSupport(
6656 RxInitializeDispatchVectors(
6657 PDRIVER_OBJECT DriverObject
)
6663 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6665 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6668 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6669 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6670 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6672 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6673 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6674 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6675 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6676 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6677 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6678 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6679 RxFastIoDispatch
.FastIoLock
= NULL
;
6680 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6681 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6682 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6683 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6684 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6685 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6686 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6687 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6689 RxInitializeTopLevelIrpPackage();
6691 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6692 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6693 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6694 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6696 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6697 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6698 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6699 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6708 return STATUS_NOT_IMPLEMENTED
;
6715 RxInitializeMinirdrDispatchTable(
6716 IN PDRIVER_OBJECT DriverObject
)
6726 RxInitializeRegistrationStructures(
6731 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6732 RxData
.NumberOfMinirdrsRegistered
= 0;
6733 RxData
.NumberOfMinirdrsStarted
= 0;
6734 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6736 return STATUS_SUCCESS
;
6744 RxInitializeTopLevelIrpPackage(
6747 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6748 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6754 PDRIVER_OBJECT DriverObject
,
6764 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6765 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6768 PLIST_ENTRY NextEntry
;
6769 BOOLEAN Found
= FALSE
;
6770 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6772 /* Browse all the allocated TLC to find ours */
6773 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6774 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6775 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6776 NextEntry
= NextEntry
->Flink
)
6778 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6779 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6780 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6783 if (ListContext
== TopLevelContext
)
6789 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6803 /* No associated SRV_OPEN, it's OK to purge */
6804 if (IsListEmpty(&Fcb
->SrvOpenList
))
6809 /* Only allow to purge if all the associated SRV_OPEN
6810 * - have no outstanding opens ongoing
6811 * - have only read attribute set
6813 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6814 Entry
!= &Fcb
->SrvOpenList
;
6815 Entry
= Entry
->Flink
)
6819 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6821 /* Failing previous needs, don't allow purge */
6822 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6823 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6829 /* All correct, allow purge */
6837 RxIsThisAnRdbssTopLevelContext(
6838 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6840 ULONG_PTR StackTop
, StackBottom
;
6842 /* Bail out for flags */
6843 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6848 /* Is our provided TLC allocated on stack? */
6849 IoGetStackLimits(&StackTop
, &StackBottom
);
6850 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6851 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6853 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6854 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6862 /* No, use the helper function */
6863 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6870 RxIsThisTheTopLevelIrp(
6875 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6876 TopLevelIrp
= IoGetTopLevelIrp();
6877 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6879 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
6882 return (TopLevelIrp
== Irp
);
6887 RxLockOperationCompletion(
6892 return STATUS_NOT_IMPLEMENTED
;
6901 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6902 IN PUNICODE_STRING OriginatorId
,
6907 PUNICODE_STRING Originator
= OriginatorId
;
6908 LARGE_INTEGER LargeLine
;
6910 /* Set optional parameters */
6911 LargeLine
.QuadPart
= Line
;
6912 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
6914 Originator
= (PUNICODE_STRING
)&unknownId
;
6918 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
6923 RxLogEventWithAnnotation(
6924 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6927 IN PVOID DataBuffer
,
6928 IN USHORT DataBufferLength
,
6929 IN PUNICODE_STRING Annotation
,
6930 IN ULONG AnnotationCount
)
6938 PRX_CONTEXT RxContext
)
6941 return STATUS_NOT_IMPLEMENTED
;
6949 RxLowIoIoCtlShellCompletion(
6950 PRX_CONTEXT RxContext
)
6957 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
6959 Irp
= RxContext
->CurrentIrp
;
6960 Status
= RxContext
->IoStatusBlock
.Status
;
6962 /* Set information and status */
6963 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
6965 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6968 Irp
->IoStatus
.Status
= Status
;
6974 RxLowIoLockControlShell(
6975 IN PRX_CONTEXT RxContext
)
6978 return STATUS_NOT_IMPLEMENTED
;
6986 RxLowIoNotifyChangeDirectoryCompletion(
6987 PRX_CONTEXT RxContext
)
6991 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
6993 /* Just copy back the IO_STATUS to the IRP */
6994 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
6995 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
6997 return RxContext
->IoStatusBlock
.Status
;
7005 PRX_CONTEXT RxContext
)
7012 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
7014 Fcb
= (PFCB
)RxContext
->pFcb
;
7015 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7017 return STATUS_MORE_PROCESSING_REQUIRED
;
7020 /* Always update stats for disks */
7021 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7023 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7026 /* And forward the read to the mini-rdr */
7027 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
7028 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
7035 RxLowIoReadShellCompletion(
7036 PRX_CONTEXT RxContext
)
7041 BOOLEAN PagingIo
, IsPipe
;
7042 PIO_STACK_LOCATION Stack
;
7043 PLOWIO_CONTEXT LowIoContext
;
7047 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
7049 Status
= RxContext
->IoStatusBlock
.Status
;
7050 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7052 Irp
= RxContext
->CurrentIrp
;
7053 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7055 /* Set IRP information from the RX_CONTEXT status block */
7056 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7058 /* Fixup status for paging file if nothing was read */
7061 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
7063 Status
= STATUS_END_OF_FILE
;
7067 LowIoContext
= &RxContext
->LowIoContext
;
7068 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7070 /* Check broken cases that should never happen */
7071 Fcb
= (PFCB
)RxContext
->pFcb
;
7072 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
7074 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
7077 return STATUS_RETRY
;
7080 else if (Status
== STATUS_SUCCESS
)
7082 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
7084 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
7085 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
7091 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7097 /* Readahead should go through Cc and not finish here */
7098 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
7100 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7101 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7106 Stack
= RxContext
->CurrentIrpSp
;
7107 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
7108 /* Release lock if required */
7111 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7115 /* Set FastIo if read was a success */
7116 if (NT_SUCCESS(Status
) && !IsPipe
)
7118 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
7121 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7123 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
7127 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7136 /* Final sanity checks */
7137 ASSERT(Status
!= STATUS_RETRY
);
7138 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
7139 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
7149 IN PRX_CONTEXT RxContext
)
7156 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
7158 Fcb
= (PFCB
)RxContext
->pFcb
;
7160 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7161 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7163 /* Always update stats for disks */
7164 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7166 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7169 /* And forward the write to the mini-rdr */
7170 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
7171 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
7178 RxLowIoWriteShellCompletion(
7179 PRX_CONTEXT RxContext
)
7185 PLOWIO_CONTEXT LowIoContext
;
7189 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
7191 Status
= RxContext
->IoStatusBlock
.Status
;
7192 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7194 Irp
= RxContext
->CurrentIrp
;
7196 /* Set IRP information from the RX_CONTEXT status block */
7197 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7199 LowIoContext
= &RxContext
->LowIoContext
;
7200 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7202 /* Perform a few sanity checks */
7203 Fcb
= (PFCB
)RxContext
->pFcb
;
7204 if (Status
== STATUS_SUCCESS
)
7206 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
7208 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7209 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7212 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
7215 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7216 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
7218 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
7221 /* In case of async call, perform last bits not done in RxCommonWrite */
7222 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7224 PFILE_OBJECT FileObject
;
7225 PIO_STACK_LOCATION Stack
;
7227 /* We only succeed if we wrote what was asked for */
7228 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7230 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
7233 /* If write succeed, ,also update FILE_OBJECT flags */
7234 Stack
= RxContext
->CurrentIrpSp
;
7235 FileObject
= Stack
->FileObject
;
7238 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
7241 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
7243 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
7246 /* If VDL was extended, fix attributes */
7247 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
7249 LONGLONG LastOffset
, FileSize
;
7251 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
7252 Irp
->IoStatus
.Information
;
7253 RxGetFileSizeWithLock(Fcb
, &FileSize
);
7255 if (FileSize
< LastOffset
)
7257 LastOffset
= FileSize
;
7260 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
7263 /* One less outstanding write */
7264 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7266 PNON_PAGED_FCB NonPagedFcb
;
7268 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
7269 if (NonPagedFcb
!= NULL
)
7271 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
7272 -1, &RxStrucSupSpinLock
) == 1)
7274 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
7279 /* Release paging resource if acquired */
7280 if (RxContext
->FcbPagingIoResourceAcquired
)
7282 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7285 /* Resume blocked operations for pipes */
7286 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7288 RxResumeBlockedOperations_Serially(RxContext
,
7289 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
7293 /* And release FCB only for files */
7294 if (RxContext
->FcbResourceAcquired
)
7296 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7300 /* Final sanity checks */
7301 ASSERT(Status
!= STATUS_RETRY
);
7302 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
7303 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
7305 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7318 RxNotifyChangeDirectory(
7319 PRX_CONTEXT RxContext
)
7323 PIO_STACK_LOCATION Stack
;
7327 /* The IRP can abviously wait */
7328 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
7330 /* Initialize its lowio */
7331 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
7335 /* Lock user buffer */
7336 Stack
= RxContext
->CurrentIrpSp
;
7337 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
7339 /* Copy parameters from IO_STACK */
7340 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
7341 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7342 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7344 /* If we have an associated MDL */
7345 Irp
= RxContext
->CurrentIrp
;
7346 if (Irp
->MdlAddress
!= NULL
)
7348 /* Then, call mini-rdr */
7349 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7350 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7352 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7356 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7361 Status
= STATUS_INVALID_PARAMETER
;
7374 RxPostStackOverflowRead (
7375 IN PRX_CONTEXT RxContext
)
7380 return STATUS_NOT_IMPLEMENTED
;
7387 RxpPrepareCreateContextForReuse(
7388 PRX_CONTEXT RxContext
)
7390 /* Reuse can only happen for open operations (STATUS_RETRY) */
7391 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7393 /* Release the FCB if it was acquired */
7394 if (RxContext
->Create
.FcbAcquired
)
7396 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7397 RxContext
->Create
.FcbAcquired
= FALSE
;
7400 /* Free the canonical name */
7401 RxFreeCanonicalNameBuffer(RxContext
);
7403 /* If we have a VNetRoot associated */
7404 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7406 /* Remove our link and thus, dereference the VNetRoot */
7407 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7408 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7410 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7411 RxContext
->Create
.pVNetRoot
= NULL
;
7413 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7416 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7423 RxpQueryInfoMiniRdr(
7424 PRX_CONTEXT RxContext
,
7425 FILE_INFORMATION_CLASS FileInfoClass
,
7431 Fcb
= (PFCB
)RxContext
->pFcb
;
7433 /* Set the RX_CONTEXT */
7434 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7435 RxContext
->Info
.Buffer
= Buffer
;
7438 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7448 IN PRX_CONTEXT RxContext
)
7452 NET_ROOT_TYPE NetRootType
;
7453 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7457 Irp
= RxContext
->CurrentIrp
;
7459 /* This has to come from MUP */
7460 if (Irp
->RequestorMode
== UserMode
)
7462 return STATUS_INVALID_DEVICE_REQUEST
;
7465 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7467 PQUERY_PATH_REQUEST QueryRequest
;
7469 /* Get parameters */
7470 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7472 /* Don't overflow allocation */
7473 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7475 return STATUS_INVALID_DEVICE_REQUEST
;
7478 /* Forcefully rewrite IRP MJ */
7479 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7481 /* Fake canon name */
7482 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7483 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7485 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7489 /* Copy the prefix to look for */
7490 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7491 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7492 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7494 /* Zero the create parameters */
7495 RtlZeroMemory(&RxContext
->Create
.NtCreateParameters
,
7496 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7497 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7498 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7502 /* If not devcontrol, it comes from open, name was already copied */
7503 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7504 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7507 /* Canonilize name */
7508 NetRootType
= NET_ROOT_WILD
;
7509 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7510 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7511 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7512 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7513 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7514 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7515 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7516 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7517 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7518 if (NT_SUCCESS(Status
))
7520 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7522 if (Status
== STATUS_PENDING
)
7527 if (NT_SUCCESS(Status
))
7529 PQUERY_PATH_RESPONSE QueryResponse
;
7531 /* We accept the length that was canon (minus netroot) */
7532 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7533 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7537 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7538 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7540 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7542 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7545 RxpPrepareCreateContextForReuse(RxContext
);
7547 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7558 RxPrepareToReparseSymbolicLink(
7559 PRX_CONTEXT RxContext
,
7560 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7561 PUNICODE_STRING NewPath
,
7562 BOOLEAN NewPathIsAbsolute
,
7563 PBOOLEAN ReparseRequired
)
7567 PFILE_OBJECT FileObject
;
7569 /* Assume no reparse is required first */
7570 *ReparseRequired
= FALSE
;
7572 /* Only supported for IRP_MJ_CREATE */
7573 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
)
7575 return STATUS_INVALID_PARAMETER
;
7578 /* If symbolic link is not embedded, and DELETE is specified, fail */
7579 if (!SymbolicLinkEmbeddedInOldPath
)
7581 /* Excepted if DELETE is the only flag specified, then, open has to succeed
7582 * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7584 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
) &&
7585 BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, ~DELETE
))
7587 return STATUS_ACCESS_DENIED
;
7591 /* At that point, assume reparse will be required */
7592 *ReparseRequired
= TRUE
;
7594 /* If new path isn't absolute, it's up to us to make it absolute */
7595 if (!NewPathIsAbsolute
)
7597 /* The prefix will be \Device\Mup */
7598 NewLength
= NewPath
->Length
+ (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
));
7599 NewBuffer
= ExAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, NewLength
,
7601 if (NewBuffer
== NULL
)
7603 return STATUS_INSUFFICIENT_RESOURCES
;
7606 /* Copy data for the new path */
7607 RtlMoveMemory(NewBuffer
, L
"\\Device\\Mup", (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
)));
7608 RtlMoveMemory(Add2Ptr(NewBuffer
, (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
))),
7609 NewPath
->Buffer
, NewPath
->Length
);
7611 /* Otherwise, use caller path as it */
7614 NewLength
= NewPath
->Length
;
7615 NewBuffer
= NewPath
->Buffer
;
7618 /* Get the FILE_OBJECT we'll modify */
7619 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
7621 /* Free old path first */
7622 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
7623 /* And setup new one */
7624 FileObject
->FileName
.Length
= NewLength
;
7625 FileObject
->FileName
.MaximumLength
= NewLength
;
7626 FileObject
->FileName
.Buffer
= NewBuffer
;
7628 /* And set reparse flag */
7629 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
);
7632 return STATUS_SUCCESS
;
7643 LOCK_OPERATION Lock
;
7644 PIO_STACK_LOCATION Stack
;
7645 PRX_CONTEXT RxContext
= Context
;
7647 /* NULL IRP is no option */
7653 /* Check whether preparation was really needed */
7654 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7658 /* Mark the context as prepared */
7659 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7661 /* Just lock the user buffer, with the correct length, depending on the MJ */
7662 Lock
= IoReadAccess
;
7663 Stack
= RxContext
->CurrentIrpSp
;
7664 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7666 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7668 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7670 Lock
= IoWriteAccess
;
7672 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7677 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7678 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7680 Lock
= IoWriteAccess
;
7681 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7683 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7685 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7689 /* As it will be posted (async), mark the IRP pending */
7690 IoMarkIrpPending(Irp
);
7698 PRX_CONTEXT RxContext
,
7699 FILE_INFORMATION_CLASS Class
)
7704 /* Initialize parameters in RX_CONTEXT */
7705 RxContext
->Info
.FileInformationClass
= Class
;
7706 RxContext
->Info
.Buffer
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
7707 RxContext
->Info
.Length
= RxContext
->CurrentIrpSp
->Parameters
.SetFile
.Length
;
7709 /* And call mini-rdr */
7710 Fcb
= (PFCB
)RxContext
->pFcb
;
7711 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
7718 RxpUnregisterMinirdr(
7719 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7730 PRX_CONTEXT LocalContext
)
7737 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7739 /* And force close */
7740 RxReleaseFcb(NULL
, Fcb
);
7741 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7742 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7743 ASSERT(Status
== STATUS_SUCCESS
);
7747 RxQueryAlternateNameInfo(
7748 PRX_CONTEXT RxContext
,
7749 PFILE_NAME_INFORMATION AltNameInfo
)
7752 return STATUS_NOT_IMPLEMENTED
;
7760 PRX_CONTEXT RxContext
,
7761 PFILE_BASIC_INFORMATION BasicInfo
)
7765 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7767 /* Simply zero and forward to mini-rdr */
7768 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7769 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7773 RxQueryCompressedInfo(
7774 PRX_CONTEXT RxContext
,
7775 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7778 return STATUS_NOT_IMPLEMENTED
;
7786 PRX_CONTEXT RxContext
)
7793 BOOLEAN LockNotGranted
;
7794 ULONG Length
, FileIndex
;
7795 PUNICODE_STRING FileName
;
7796 PIO_STACK_LOCATION Stack
;
7797 FILE_INFORMATION_CLASS FileInfoClass
;
7801 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7803 /* Get parameters */
7804 Stack
= RxContext
->CurrentIrpSp
;
7805 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7806 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7807 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7808 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7809 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7810 FileName
, FileInfoClass
);
7812 Irp
= RxContext
->CurrentIrp
;
7813 Flags
= Stack
->Flags
;
7814 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7815 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7817 if (FileName
!= NULL
)
7819 DPRINT("FileName: %wZ\n", FileName
);
7822 /* No FOBX: not a standard file/directory */
7823 Fobx
= (PFOBX
)RxContext
->pFobx
;
7826 return STATUS_OBJECT_NAME_INVALID
;
7829 /* We can only deal with a disk */
7830 Fcb
= (PFCB
)RxContext
->pFcb
;
7831 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7833 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7834 return STATUS_INVALID_DEVICE_REQUEST
;
7837 /* Setup RX_CONTEXT related fields */
7838 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7839 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7840 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7841 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7842 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7844 /* We don't support (yet?) a specific index being set */
7845 if (RxContext
->QueryDirectory
.IndexSpecified
)
7847 return STATUS_NOT_IMPLEMENTED
;
7850 /* Try to lock FCB */
7851 LockNotGranted
= TRUE
;
7852 if (RxContext
->QueryDirectory
.InitialQuery
)
7854 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7855 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7857 if (!NT_SUCCESS(Status
))
7862 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7864 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7865 RxConvertToSharedFcb(RxContext
, Fcb
);
7868 LockNotGranted
= FALSE
;
7873 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7874 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7876 if (!NT_SUCCESS(Status
))
7881 LockNotGranted
= FALSE
;
7885 /* If it failed, post request */
7888 return RxFsdPostRequest(RxContext
);
7891 /* This cannot be done on a orphaned directory */
7892 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
7894 RxReleaseFcb(RxContext
, Fcb
);
7895 return STATUS_FILE_CLOSED
;
7901 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
7903 RxContext
->QueryDirectory
.FileIndex
= 0;
7906 /* Assume success */
7907 Status
= STATUS_SUCCESS
;
7908 /* If initial query, prepare FOBX */
7909 if (RxContext
->QueryDirectory
.InitialQuery
)
7911 /* We cannot have a template already! */
7912 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
7914 /* If we have a file name and a correct one, duplicate it in the FOBX */
7915 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
7916 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
7917 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
7918 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
7920 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
7922 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
7923 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7925 /* UNICODE_STRING; length has to be even */
7926 if ((FileName
->Length
& 1) != 0)
7928 Status
= STATUS_INVALID_PARAMETER
;
7929 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
7933 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
7934 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
7935 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
7937 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
7942 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7945 /* No name specified, or a match all wildcard? Match everything */
7948 Fobx
->ContainsWildCards
= TRUE
;
7950 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
7951 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
7952 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
7954 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7957 /* No need for exclusive any longer */
7958 if (NT_SUCCESS(Status
))
7960 RxConvertToSharedFcb(RxContext
, Fcb
);
7964 /* Lock user buffer and forward to mini-rdr */
7965 if (NT_SUCCESS(Status
))
7967 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
7968 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7969 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
7970 RxContext
->Info
.Length
= Length
;
7972 if (RxContext
->Info
.Buffer
!= NULL
)
7974 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
7977 /* Post if mini-rdr asks to */
7978 if (RxContext
->PostRequest
)
7980 RxFsdPostRequest(RxContext
);
7984 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
7990 RxReleaseFcb(RxContext
, Fcb
);
7999 PRX_CONTEXT RxContext
,
8000 PFILE_EA_INFORMATION EaInfo
)
8003 return STATUS_NOT_IMPLEMENTED
;
8007 RxQueryInternalInfo(
8008 PRX_CONTEXT RxContext
,
8009 PFILE_INTERNAL_INFORMATION InternalInfo
)
8012 return STATUS_NOT_IMPLEMENTED
;
8017 PRX_CONTEXT RxContext
,
8018 PFILE_NAME_INFORMATION NameInfo
)
8021 return STATUS_NOT_IMPLEMENTED
;
8026 PRX_CONTEXT RxContext
,
8027 PFILE_PIPE_INFORMATION PipeInfo
)
8030 return STATUS_NOT_IMPLEMENTED
;
8034 RxQueryPositionInfo(
8035 PRX_CONTEXT RxContext
,
8036 PFILE_POSITION_INFORMATION PositionInfo
)
8039 return STATUS_NOT_IMPLEMENTED
;
8046 RxQueryStandardInfo(
8047 PRX_CONTEXT RxContext
,
8048 PFILE_STANDARD_INFORMATION StandardInfo
)
8056 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
8058 /* Zero output buffer */
8059 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
8061 Fcb
= (PFCB
)RxContext
->pFcb
;
8062 Fobx
= (PFOBX
)RxContext
->pFobx
;
8063 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8064 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
8065 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8067 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8070 /* Otherwise, fill what we can already */
8071 Status
= STATUS_SUCCESS
;
8072 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
8073 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8074 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
8075 if (StandardInfo
->NumberOfLinks
== 0)
8077 StandardInfo
->NumberOfLinks
= 1;
8080 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
8082 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
8083 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
8086 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8087 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
8089 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8093 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
8104 RxReadRegistryParameters(
8111 UNICODE_STRING KeyName
, ParamName
;
8112 OBJECT_ATTRIBUTES ObjectAttributes
;
8113 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
8117 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8118 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
8119 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
8120 if (!NT_SUCCESS(Status
))
8125 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
8126 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
8127 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8128 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8130 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
8133 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
8134 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8135 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8137 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
8139 if (Granularity
> 16)
8144 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
8147 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
8148 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8149 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8151 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
8163 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
8164 IN OUT PDRIVER_OBJECT DriverObject
,
8165 IN PMINIRDR_DISPATCH MrdrDispatch
,
8167 IN PUNICODE_STRING DeviceName
,
8168 IN ULONG DeviceExtensionSize
,
8169 IN DEVICE_TYPE DeviceType
,
8170 IN ULONG DeviceCharacteristics
)
8173 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
8179 return STATUS_INVALID_PARAMETER
;
8182 /* Create device object with provided parameters */
8183 Status
= IoCreateDevice(DriverObject
,
8184 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
8187 DeviceCharacteristics
,
8189 (PDEVICE_OBJECT
*)&RDBSSDevice
);
8190 if (!NT_SUCCESS(Status
))
8195 if (!RxData
.DriverObject
)
8197 return STATUS_UNSUCCESSFUL
;
8200 /* Initialize our DO extension */
8201 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
8202 ++RxFileSystemDeviceObject
->ReferenceCount
;
8203 *DeviceObject
= RDBSSDevice
;
8204 RDBSSDevice
->RdbssExports
= &RxExports
;
8205 RDBSSDevice
->Dispatch
= MrdrDispatch
;
8206 RDBSSDevice
->RegistrationControls
= Controls
;
8207 RDBSSDevice
->DeviceName
= *DeviceName
;
8208 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
8209 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
8210 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
8211 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
8212 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
8213 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
8214 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
8216 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
8218 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
8219 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
8220 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
8222 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8223 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
8225 RxInitializeMinirdrDispatchTable(DriverObject
);
8228 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8229 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
8231 LARGE_INTEGER ScavengerTimeLimit
;
8233 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
8234 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
8235 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
8236 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
8237 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
8238 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
8241 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
8243 return STATUS_SUCCESS
;
8250 RxRemoveFromTopLevelIrpAllocatedContextsList(
8251 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8255 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8256 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8257 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8259 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
8260 RemoveEntryList(&TopLevelContext
->ListEntry
);
8261 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
8268 RxRemoveOverflowEntry(
8269 PRDBSS_DEVICE_OBJECT DeviceObject
,
8270 WORK_QUEUE_TYPE Queue
)
8273 PRX_CONTEXT Context
;
8275 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
8276 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
8278 /* No entries left, nothing to return */
8279 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
8286 /* Decrement count */
8287 --DeviceObject
->OverflowQueueCount
[Queue
];
8290 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
8291 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
8292 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
8293 Context
->OverflowListEntry
.Flink
= NULL
;
8295 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
8305 RxRemoveShareAccess(
8306 _Inout_ PFILE_OBJECT FileObject
,
8307 _Inout_ PSHARE_ACCESS ShareAccess
,
8309 _In_ PSZ wherelogtag
)
8313 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8314 IoRemoveShareAccess(FileObject
, ShareAccess
);
8315 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8323 RxRemoveShareAccessPerSrvOpens(
8324 IN OUT PSRV_OPEN SrvOpen
)
8326 ACCESS_MASK DesiredAccess
;
8328 BOOLEAN WriteAccess
;
8329 BOOLEAN DeleteAccess
;
8333 /* Get access that were granted to SRV_OPEN */
8334 DesiredAccess
= SrvOpen
->DesiredAccess
;
8335 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
8336 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
8337 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
8339 /* If any, drop them */
8340 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
8343 BOOLEAN SharedWrite
;
8344 BOOLEAN SharedDelete
;
8345 ULONG DesiredShareAccess
;
8346 PSHARE_ACCESS ShareAccess
;
8348 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
8349 DesiredShareAccess
= SrvOpen
->ShareAccess
;
8351 ShareAccess
->Readers
-= ReadAccess
;
8352 ShareAccess
->Writers
-= WriteAccess
;
8353 ShareAccess
->Deleters
-= DeleteAccess
;
8355 ShareAccess
->OpenCount
--;
8357 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
8358 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
8359 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
8360 ShareAccess
->SharedRead
-= SharedRead
;
8361 ShareAccess
->SharedWrite
-= SharedWrite
;
8362 ShareAccess
->SharedDelete
-= SharedDelete
;
8367 RxSearchForCollapsibleOpen(
8368 PRX_CONTEXT RxContext
,
8369 ACCESS_MASK DesiredAccess
,
8374 PLIST_ENTRY ListEntry
;
8375 BOOLEAN ShouldTry
, Purged
, Scavenged
;
8379 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext
, DesiredAccess
, ShareAccess
);
8381 Fcb
= (PFCB
)RxContext
->pFcb
;
8383 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8384 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8386 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8388 RxScavengeRelatedFobxs(Fcb
);
8389 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8391 return STATUS_NOT_FOUND
;
8394 /* If basic open, ask the mini-rdr if we should try to collapse */
8395 if (RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN
||
8396 RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN_IF
)
8400 if (Fcb
->MRxDispatch
!= NULL
)
8402 ASSERT(RxContext
->pRelevantSrvOpen
== NULL
);
8403 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8405 ShouldTry
= NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
));
8413 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
))
8418 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8421 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
)))
8423 return STATUS_NOT_FOUND
;
8426 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8428 RxScavengeRelatedFobxs(Fcb
);
8429 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8431 return STATUS_NOT_FOUND
;
8434 /* Only collapse for matching NET_ROOT & disks */
8435 if (Fcb
->pNetRoot
!= RxContext
->Create
.pNetRoot
||
8436 Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
8438 return STATUS_NOT_FOUND
;
8443 Status
= STATUS_NOT_FOUND
;
8445 /* Browse all our SRV_OPEN to find the matching one */
8446 for (ListEntry
= Fcb
->SrvOpenList
.Flink
;
8447 ListEntry
!= &Fcb
->SrvOpenList
;
8448 ListEntry
= ListEntry
->Flink
)
8452 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
8453 /* Not the same VNET_ROOT, move to the next one */
8454 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8456 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8460 /* Is there a sharing violation? */
8461 if (SrvOpen
->DesiredAccess
!= DesiredAccess
|| SrvOpen
->ShareAccess
!= ShareAccess
||
8462 BooleanFlagOn(SrvOpen
->Flags
, (SRVOPEN_FLAG_CLOSED
| SRVOPEN_FLAG_COLLAPSING_DISABLED
| SRVOPEN_FLAG_FILE_DELETED
| SRVOPEN_FLAG_FILE_RENAMED
)))
8464 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8466 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8470 /* Check against the SRV_OPEN */
8471 Status
= RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
);
8472 if (!NT_SUCCESS(Status
))
8479 /* Don't allow collaspse for reparse point opening */
8480 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
^ SrvOpen
->CreateOptions
, FILE_OPEN_REPARSE_POINT
))
8484 Status
= STATUS_NOT_FOUND
;
8488 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8489 if (DisableByteRangeLockingOnReadOnlyFiles
|| !BooleanFlagOn(SrvOpen
->pFcb
->Attributes
, FILE_ATTRIBUTE_READONLY
))
8491 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
8493 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8494 if (NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
)))
8496 /* Is close delayed - great reuse*/
8497 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
8499 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen
);
8500 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
8501 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
8504 return STATUS_SUCCESS
;
8507 Status
= STATUS_NOT_FOUND
;
8512 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8513 if (ListEntry
== &Fcb
->SrvOpenList
)
8515 Status
= STATUS_NOT_FOUND
;
8518 /* Only required access: read attributes? Don't reuse */
8519 if ((DesiredAccess
& 0xFFEFFFFF) == FILE_READ_ATTRIBUTES
)
8521 return STATUS_NOT_FOUND
;
8524 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8527 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8529 RxScavengeRelatedFobxs(Fcb
);
8533 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8534 if (!Purged
&& RxIsOkToPurgeFcb(Fcb
))
8536 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8541 /* If sharing violation, keep track of it */
8542 if (Status
== STATUS_SHARING_VIOLATION
)
8544 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8547 DPRINT("Status: %x\n", Status
);
8552 RxSetAllocationInfo(
8553 PRX_CONTEXT RxContext
)
8556 return STATUS_NOT_IMPLEMENTED
;
8564 PRX_CONTEXT RxContext
)
8570 #define FILE_ATTRIBUTE_VOLUME 0x8
8571 #define VALID_FILE_ATTRIBUTES ( \
8572 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8573 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8574 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8575 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8576 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8577 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8578 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8579 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8581 /* First of all, call the mini-rdr */
8582 Status
= RxpSetInfoMiniRdr(RxContext
, FileBasicInformation
);
8583 /* If it succeed, perform last bits */
8584 if (NT_SUCCESS(Status
))
8589 PFILE_OBJECT FileObject
;
8590 ULONG Attributes
, CleanAttr
;
8591 PFILE_BASIC_INFORMATION BasicInfo
;
8593 Fcb
= (PFCB
)RxContext
->pFcb
;
8594 Fobx
= (PFOBX
)RxContext
->pFobx
;
8595 Irp
= RxContext
->CurrentIrp
;
8596 BasicInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
8597 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8599 /* If caller provided flags, handle the change */
8600 Attributes
= BasicInfo
->FileAttributes
;
8601 if (Attributes
!= 0)
8603 /* Clean our flags first, with only stuff we support */
8604 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
8606 CleanAttr
= (Attributes
& VALID_DIR_ATTRIBUTES
) | FILE_ATTRIBUTE_DIRECTORY
;
8610 CleanAttr
= Attributes
& VALID_FILE_ATTRIBUTES
;
8613 /* Handle the temporary mark (set/unset depending on caller) */
8614 if (BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_TEMPORARY
))
8616 SetFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8617 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8621 ClearFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8622 ClearFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8625 /* And set new attributes */
8626 Fcb
->Attributes
= CleanAttr
;
8629 /* If caller provided a creation time, set it */
8630 if (BasicInfo
->CreationTime
.QuadPart
!= 0LL)
8632 Fcb
->CreationTime
.QuadPart
= BasicInfo
->CreationTime
.QuadPart
;
8633 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_CREATION
);
8636 /* If caller provided a last access time, set it */
8637 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0LL)
8639 Fcb
->LastAccessTime
.QuadPart
= BasicInfo
->LastAccessTime
.QuadPart
;
8640 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
);
8643 /* If caller provided a last write time, set it */
8644 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0LL)
8646 Fcb
->LastWriteTime
.QuadPart
= BasicInfo
->LastWriteTime
.QuadPart
;
8647 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
8650 /* If caller provided a last change time, set it */
8651 if (BasicInfo
->ChangeTime
.QuadPart
!= 0LL)
8653 Fcb
->LastChangeTime
.QuadPart
= BasicInfo
->ChangeTime
.QuadPart
;
8654 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
8666 RxSetDispositionInfo(
8667 PRX_CONTEXT RxContext
)
8673 /* First, make the mini-rdr work! */
8674 Status
= RxpSetInfoMiniRdr(RxContext
, FileDispositionInformation
);
8675 /* If it succeed, we'll keep track of the change */
8676 if (NT_SUCCESS(Status
))
8679 PFILE_OBJECT FileObject
;
8680 PFILE_DISPOSITION_INFORMATION FileDispo
;
8682 Fcb
= (PFCB
)RxContext
->pFcb
;
8683 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8684 FileDispo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8685 /* Caller asks for deletion: mark as delete on close */
8686 if (FileDispo
->DeleteFile
)
8688 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8689 FileObject
->DeletePending
= TRUE
;
8691 /* Otherwise, clear it */
8694 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8695 FileObject
->DeletePending
= FALSE
;
8698 /* Sanitize output */
8699 Status
= STATUS_SUCCESS
;
8707 PRX_CONTEXT RxContext
)
8710 return STATUS_NOT_IMPLEMENTED
;
8715 PRX_CONTEXT RxContext
)
8718 return STATUS_NOT_IMPLEMENTED
;
8723 PRX_CONTEXT RxContext
)
8726 return STATUS_NOT_IMPLEMENTED
;
8734 PRX_CONTEXT RxContext
)
8738 PFCB RenameFcb
, Fcb
;
8739 PIO_STACK_LOCATION Stack
;
8740 PFILE_RENAME_INFORMATION RenameInfo
, UserInfo
;
8744 DPRINT("RxSetRenameInfo(%p)\n", RxContext
);
8746 Stack
= RxContext
->CurrentIrpSp
;
8747 DPRINT("FO: %p, Replace: %d\n", Stack
->Parameters
.SetFile
.FileObject
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
8749 /* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
8750 RxContext
->Info
.ReplaceIfExists
= Stack
->Parameters
.SetFile
.ReplaceIfExists
;
8751 if (Stack
->Parameters
.SetFile
.FileObject
== NULL
)
8753 return RxpSetInfoMiniRdr(RxContext
, Stack
->Parameters
.SetFile
.FileInformationClass
);
8756 Fcb
= (PFCB
)RxContext
->pFcb
;
8757 RenameFcb
= Stack
->Parameters
.SetFile
.FileObject
->FsContext
;
8758 /* First, validate the received file object */
8759 ASSERT(NodeType(RenameFcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
);
8760 if (Fcb
->pNetRoot
!= RenameFcb
->pNetRoot
)
8762 DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb
, Fcb
->pNetRoot
, Fcb
->pNetRoot
->pNetRootName
, RenameFcb
, RenameFcb
->pNetRoot
, RenameFcb
->pNetRoot
->pNetRootName
);
8763 return STATUS_NOT_SAME_DEVICE
;
8766 /* We'll reallocate a safe buffer */
8767 Length
= Fcb
->pNetRoot
->DiskParameters
.RenameInfoOverallocationSize
+ RenameFcb
->FcbTableEntry
.Path
.Length
+ FIELD_OFFSET(FILE_RENAME_INFORMATION
, FileName
);
8768 RenameInfo
= RxAllocatePoolWithTag(PagedPool
, Length
, '??xR');
8769 if (RenameInfo
== NULL
)
8771 return STATUS_INSUFFICIENT_RESOURCES
;
8777 UserInfo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8778 RenameInfo
->ReplaceIfExists
= UserInfo
->ReplaceIfExists
;
8779 RenameInfo
->RootDirectory
= UserInfo
->RootDirectory
;
8780 RenameInfo
->FileNameLength
= RenameFcb
->FcbTableEntry
.Path
.Length
;
8781 RtlMoveMemory(&RenameInfo
->FileName
[0], RenameFcb
->FcbTableEntry
.Path
.Buffer
, RenameFcb
->FcbTableEntry
.Path
.Length
);
8783 /* Set them in the RX_CONTEXT */
8784 RxContext
->Info
.FileInformationClass
= Stack
->Parameters
.SetFile
.FileInformationClass
;
8785 RxContext
->Info
.Buffer
= RenameInfo
;
8786 RxContext
->Info
.Length
= Length
;
8788 /* And call the mini-rdr */
8789 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
8794 RxFreePoolWithTag(RenameInfo
, '??xR');
8808 _In_ ACCESS_MASK DesiredAccess
,
8809 _In_ ULONG DesiredShareAccess
,
8810 _Inout_ PFILE_OBJECT FileObject
,
8811 _Out_ PSHARE_ACCESS ShareAccess
,
8813 _In_ PSZ wherelogtag
)
8817 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8818 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8819 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8825 PRX_CONTEXT RxContext
)
8828 return STATUS_NOT_IMPLEMENTED
;
8835 RxSetupNetFileObject(
8836 PRX_CONTEXT RxContext
)
8840 PFILE_OBJECT FileObject
;
8841 PIO_STACK_LOCATION Stack
;
8845 /* Assert FOBX is FOBX or NULL */
8846 Fobx
= (PFOBX
)RxContext
->pFobx
;
8847 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
8849 Fcb
= (PFCB
)RxContext
->pFcb
;
8850 Stack
= RxContext
->CurrentIrpSp
;
8851 FileObject
= Stack
->FileObject
;
8852 /* If it's temporary mark FO as such */
8853 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
8854 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
8856 if (FileObject
== NULL
)
8861 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
8864 /* No FO, nothing to setup */
8865 if (FileObject
== NULL
)
8870 /* Assign FCB & CCB (FOBX) to FO */
8871 FileObject
->FsContext
= Fcb
;
8872 FileObject
->FsContext2
= Fobx
;
8875 ULONG_PTR StackTop
, StackBottom
;
8877 /* If FO is allocated on pool, keep track of it */
8878 IoGetStackLimits(&StackTop
, &StackBottom
);
8879 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
8881 Fobx
->AssociatedFileObject
= FileObject
;
8885 Fobx
->AssociatedFileObject
= NULL
;
8888 /* Make sure to mark FOBX if it's a DFS open */
8889 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
8891 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8895 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8899 /* Set Cc pointers */
8900 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
8902 /* Update access state */
8903 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
8905 PACCESS_STATE AccessState
;
8907 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
8908 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
8909 AccessState
->RemainingDesiredAccess
= 0;
8919 IN PRX_CONTEXT RxContext
,
8920 OUT PBOOLEAN PostToFsp
)
8923 BOOLEAN Wait
, AlreadyStarted
;
8924 PRDBSS_DEVICE_OBJECT DeviceObject
;
8926 /* If we've not been post, then, do it */
8927 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
8929 SECURITY_SUBJECT_CONTEXT SubjectContext
;
8931 SeCaptureSubjectContext(&SubjectContext
);
8932 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
8933 SeReleaseSubjectContext(&SubjectContext
);
8936 return STATUS_PENDING
;
8939 /* Acquire all the required locks */
8940 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8941 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
8944 return STATUS_PENDING
;
8947 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
8949 ExReleaseResourceLite(&RxData
.Resource
);
8951 return STATUS_PENDING
;
8954 AlreadyStarted
= FALSE
;
8955 DeviceObject
= RxContext
->RxDeviceObject
;
8958 /* MUP handle set, means already registered */
8959 if (DeviceObject
->MupHandle
!= NULL
)
8961 AlreadyStarted
= TRUE
;
8962 Status
= STATUS_REDIRECTOR_STARTED
;
8966 /* If we're asked to register to MUP, then do it */
8967 Status
= STATUS_SUCCESS
;
8968 if (DeviceObject
->RegisterUncProvider
)
8970 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
8971 &DeviceObject
->DeviceName
,
8972 DeviceObject
->RegisterMailSlotProvider
);
8974 if (!NT_SUCCESS(Status
))
8976 DeviceObject
->MupHandle
= NULL
;
8980 /* Register as file system */
8981 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
8982 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
8984 /* Inform mini-rdr it has to start */
8985 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
8986 if (NT_SUCCESS(Status
))
8988 ++DeviceObject
->StartStopContext
.Version
;
8989 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
8990 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
8992 Status
= RxInitializeMRxDispatcher(DeviceObject
);
8997 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
8999 if (!AlreadyStarted
)
9001 RxUnstart(RxContext
, DeviceObject
);
9005 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
9006 ExReleaseResourceLite(&RxData
.Resource
);
9016 IN PRX_CONTEXT RxContext
,
9017 OUT PBOOLEAN PostToFsp
)
9020 return STATUS_NOT_IMPLEMENTED
;
9025 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9029 return STATUS_NOT_IMPLEMENTED
;
9036 RxTryToBecomeTheTopLevelIrp(
9037 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
9039 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9040 IN BOOLEAN ForceTopLevel
9043 BOOLEAN FromPool
= FALSE
;
9047 /* If not top level, and not have to be, quit */
9048 if (IoGetTopLevelIrp() && !ForceTopLevel
)
9053 /* If not TLC provider, allocate one */
9054 if (TopLevelContext
== NULL
)
9056 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
9057 if (TopLevelContext
== NULL
)
9066 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
9068 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9071 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9074 /* Make it top level IRP */
9075 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
9084 RxUpdateShareAccess(
9085 _Inout_ PFILE_OBJECT FileObject
,
9086 _Inout_ PSHARE_ACCESS ShareAccess
,
9088 _In_ PSZ wherelogtag
)
9092 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
9093 IoUpdateShareAccess(FileObject
, ShareAccess
);
9094 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
9102 RxUninitializeCacheMap(
9103 PRX_CONTEXT RxContext
,
9104 PFILE_OBJECT FileObject
,
9105 PLARGE_INTEGER TruncateSize
)
9109 CACHE_UNINITIALIZE_EVENT UninitEvent
;
9113 Fcb
= FileObject
->FsContext
;
9114 ASSERT(NodeTypeIsFcb(Fcb
));
9115 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
9117 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
9118 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
9120 /* Always release the FCB before waiting for the uninit event */
9121 RxReleaseFcb(RxContext
, Fcb
);
9123 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
9125 /* Re-acquire it afterwards */
9126 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
9127 ASSERT(NT_SUCCESS(Status
));
9133 IN PDRIVER_OBJECT DriverObject
)
9142 IN PFILE_LOCK_INFO LockInfo
)
9149 PRX_CONTEXT Context
,
9150 PRDBSS_DEVICE_OBJECT DeviceObject
)
9159 RxUnwindTopLevelIrp(
9160 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
9162 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
9164 /* No TLC provided? Ask the system for ours! */
9165 if (TopLevelContext
== NULL
)
9167 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
9168 if (TopLevelContext
== NULL
)
9173 /* In that case, just assert it's really ours */
9174 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
9175 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9178 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9179 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
9180 /* Restore the previous top level IRP */
9181 IoSetTopLevelIrp(TopLevelContext
->Previous
);
9182 /* If TLC was allocated from pool, remove it from list and release it */
9183 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
9185 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
9186 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
9194 RxUpdateShareAccessPerSrvOpens(
9195 IN PSRV_OPEN SrvOpen
)
9197 ACCESS_MASK DesiredAccess
;
9199 BOOLEAN WriteAccess
;
9200 BOOLEAN DeleteAccess
;
9204 /* If already updated, no need to continue */
9205 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
9210 /* Check if any access wanted */
9211 DesiredAccess
= SrvOpen
->DesiredAccess
;
9212 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
9213 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
9214 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
9216 /* In that case, update it */
9217 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
9220 BOOLEAN SharedWrite
;
9221 BOOLEAN SharedDelete
;
9222 ULONG DesiredShareAccess
;
9223 PSHARE_ACCESS ShareAccess
;
9225 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
9226 DesiredShareAccess
= SrvOpen
->ShareAccess
;
9228 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
9229 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
9230 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
9232 ShareAccess
->OpenCount
++;
9234 ShareAccess
->Readers
+= ReadAccess
;
9235 ShareAccess
->Writers
+= WriteAccess
;
9236 ShareAccess
->Deleters
+= DeleteAccess
;
9237 ShareAccess
->SharedRead
+= SharedRead
;
9238 ShareAccess
->SharedWrite
+= SharedWrite
;
9239 ShareAccess
->SharedDelete
+= SharedDelete
;
9242 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
9249 RxXXXControlFileCallthru(
9250 PRX_CONTEXT Context
)
9256 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
9258 /* No dispatch table? Nothing to dispatch */
9259 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
9261 Context
->pFobx
= NULL
;
9262 return STATUS_INVALID_DEVICE_REQUEST
;
9265 /* Init the lowio context */
9266 Status
= RxLowIoPopulateFsctlInfo(Context
);
9267 if (!NT_SUCCESS(Status
))
9272 /* Check whether we're consistent: a length means a buffer */
9273 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
9274 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
9276 return STATUS_INVALID_PARAMETER
;
9279 /* Forward the call to the mini-rdr */
9280 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
9281 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
9282 if (Status
!= STATUS_PENDING
)
9284 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
9287 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);