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 /* Now, browse all the active contexts, to find the associated ones */
1056 Entry
= RxActiveContexts
.Flink
;
1057 while (Entry
!= &RxActiveContexts
)
1059 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1060 Entry
= Entry
->Flink
;
1062 /* Not the IRP we're looking for, ignore */
1063 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1064 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1069 /* Not the VNetRoot we're looking for, ignore */
1070 if (Context
->pFcb
== NULL
||
1071 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1076 /* No cancel routine (can't be cancel, then), ignore */
1077 if (Context
->MRxCancelRoutine
== NULL
)
1082 /* At that point, we found a matching context
1083 * If we're not asked to force close, then fail - it's still open
1085 if (!ForceFilesClosed
)
1087 Status
= STATUS_FILES_OPEN
;
1091 /* Mark our context as cancelled */
1092 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1094 /* Move it to our list */
1095 RemoveEntryList(&Context
->ContextListEntry
);
1096 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1098 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1101 /* Done with the contexts */
1102 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1104 if (Status
!= STATUS_SUCCESS
)
1109 /* Now, handle all our "extracted" contexts */
1110 while (!IsListEmpty(&ContextsToCancel
))
1112 Entry
= RemoveHeadList(&ContextsToCancel
);
1113 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1115 /* If they had an associated IRP (should be always true) */
1116 if (Context
->CurrentIrp
!= NULL
)
1118 /* Then, call cancel routine */
1119 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1120 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1121 Context
->MRxCancelRoutine(Context
);
1124 /* And delete the context */
1125 RxDereferenceAndDeleteRxContext(Context
);
1134 PDEVICE_OBJECT DeviceObject
,
1144 RxCanonicalizeFileNameByServerSpecs(
1145 PRX_CONTEXT RxContext
,
1146 PUNICODE_STRING NetRootName
)
1148 USHORT NextChar
, CurChar
;
1153 /* Validate file name is not empty */
1154 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1157 return STATUS_MORE_PROCESSING_REQUIRED
;
1160 /* Validate name is correct */
1161 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1165 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1167 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1174 if (CurChar
== NextChar
)
1176 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1183 if (CurChar
>= MaxChars
- 1)
1188 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1190 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1195 if (NetRootName
->Buffer
[1] != ':')
1197 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1203 if ((CurChar
- NextChar
) == 1)
1205 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1210 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1212 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1217 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1218 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1223 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1225 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1231 return STATUS_MORE_PROCESSING_REQUIRED
;
1235 RxCanonicalizeNameAndObtainNetRoot(
1236 PRX_CONTEXT RxContext
,
1237 PUNICODE_STRING FileName
,
1238 PUNICODE_STRING NetRootName
)
1241 NET_ROOT_TYPE NetRootType
;
1242 UNICODE_STRING CanonicalName
;
1246 NetRootType
= NET_ROOT_WILD
;
1248 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1249 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1251 /* if not relative opening, just handle the passed name */
1252 if (RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
== NULL
)
1254 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1255 if (!NT_SUCCESS(Status
))
1264 /* Make sure we have a valid FCB and a FOBX */
1265 Fcb
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1267 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1269 return STATUS_INVALID_PARAMETER
;
1272 if (!NodeTypeIsFcb(Fcb
))
1274 return STATUS_INVALID_PARAMETER
;
1280 /* Get/Create the associated VNetRoot for opening */
1281 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1282 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1283 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1285 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1287 RxFreeCanonicalNameBuffer(RxContext
);
1288 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1289 if (NT_SUCCESS(Status
))
1291 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1295 /* Filename cannot contain wildcards */
1296 if (FsRtlDoesNameContainWildCards(NetRootName
))
1298 Status
= STATUS_OBJECT_NAME_INVALID
;
1301 /* Make sure file name is correct */
1302 if (NT_SUCCESS(Status
))
1304 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1307 /* Give the mini-redirector a chance to prepare the name */
1308 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1310 if (RxContext
->Create
.pNetRoot
!= NULL
)
1312 NTSTATUS IgnoredStatus
;
1314 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1315 MRxPreparseName
, (RxContext
, NetRootName
));
1316 (void)IgnoredStatus
;
1325 RxCheckFcbStructuresForAlignment(
1334 _In_ ACCESS_MASK DesiredAccess
,
1335 _In_ ULONG DesiredShareAccess
,
1336 _Inout_ PFILE_OBJECT FileObject
,
1337 _Inout_ PSHARE_ACCESS ShareAccess
,
1338 _In_ BOOLEAN Update
,
1340 _In_ PSZ wherelogtag
)
1344 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1345 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1347 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1355 RxCheckShareAccessPerSrvOpens(
1357 IN ACCESS_MASK DesiredAccess
,
1358 IN ULONG DesiredShareAccess
)
1361 BOOLEAN WriteAccess
;
1362 BOOLEAN DeleteAccess
;
1363 PSHARE_ACCESS ShareAccess
;
1367 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1369 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1370 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1372 /* Check if any access wanted */
1373 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1374 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1375 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1377 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1379 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1380 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1381 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1383 /* Check whether there's a violation */
1385 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1387 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1389 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1390 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1391 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1392 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1394 return STATUS_SHARING_VIOLATION
;
1398 return STATUS_SUCCESS
;
1402 RxCleanupPipeQueues(
1403 PRX_CONTEXT Context
)
1412 RxCloseAssociatedSrvOpen(
1414 IN PRX_CONTEXT RxContext OPTIONAL
)
1419 BOOLEAN CloseSrvOpen
;
1420 PRX_CONTEXT LocalContext
;
1424 /* Assume SRV_OPEN is already closed */
1425 CloseSrvOpen
= FALSE
;
1426 /* If we have a FOBX, we'll have to close it */
1429 /* If the FOBX isn't closed yet */
1430 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1432 SrvOpen
= Fobx
->SrvOpen
;
1433 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1434 /* Check whether we've to close SRV_OPEN first */
1435 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1437 CloseSrvOpen
= TRUE
;
1441 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1443 /* Not much to do */
1444 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1446 if (SrvOpen
->OpenCount
> 0)
1448 --SrvOpen
->OpenCount
;
1453 /* No need to close SRV_OPEN, so close FOBX */
1456 RxMarkFobxOnClose(Fobx
);
1458 return STATUS_SUCCESS
;
1463 /* No FOBX? No RX_CONTEXT, ok, job done! */
1464 if (RxContext
== NULL
)
1466 return STATUS_SUCCESS
;
1469 /* Get the FCB from RX_CONTEXT */
1470 Fcb
= (PFCB
)RxContext
->pFcb
;
1474 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1475 if (RxContext
== NULL
)
1477 ASSERT(Fobx
!= NULL
);
1479 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1480 if (LocalContext
== NULL
)
1482 return STATUS_INSUFFICIENT_RESOURCES
;
1485 LocalContext
->MajorFunction
= 2;
1486 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1487 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1488 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1492 LocalContext
= RxContext
;
1495 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1497 /* Now, close the FOBX */
1500 RxMarkFobxOnClose(Fobx
);
1504 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1507 /* If not a "standard" file, SRV_OPEN can be null */
1508 if (SrvOpen
== NULL
)
1510 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1511 RxDereferenceNetFcb(Fcb
);
1513 if (LocalContext
!= RxContext
)
1515 RxDereferenceAndDeleteRxContext(LocalContext
);
1518 return STATUS_SUCCESS
;
1521 /* If SRV_OPEN isn't in a good condition, nothing to close */
1522 if (SrvOpen
->Condition
!= Condition_Good
)
1524 if (LocalContext
!= RxContext
)
1526 RxDereferenceAndDeleteRxContext(LocalContext
);
1529 return STATUS_SUCCESS
;
1532 /* Decrease open count */
1533 if (SrvOpen
->OpenCount
> 0)
1535 --SrvOpen
->OpenCount
;
1538 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1539 if (SrvOpen
->OpenCount
== 1)
1541 if (!IsListEmpty(&SrvOpen
->FobxList
))
1543 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1545 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1550 /* Nothing left, purge FCB */
1551 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1553 RxPurgeNetFcb(Fcb
, LocalContext
);
1556 /* Already closed? Job done! */
1557 SrvOpen
= Fobx
->SrvOpen
;
1558 if (SrvOpen
== NULL
||
1559 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1560 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1562 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1563 if (LocalContext
!= RxContext
)
1565 RxDereferenceAndDeleteRxContext(LocalContext
);
1568 return STATUS_SUCCESS
;
1571 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1573 /* Inform mini-rdr about closing */
1574 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1575 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1576 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1578 /* And mark as such */
1579 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1580 SrvOpen
->Key
= (PVOID
)-1;
1582 /* If we were delayed, we're not! */
1583 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1585 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1589 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1590 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1593 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1595 /* Mark the FOBX closed as well */
1596 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1598 if (LocalContext
!= RxContext
)
1600 RxDereferenceAndDeleteRxContext(LocalContext
);
1610 RxCollapseOrCreateSrvOpen(
1611 PRX_CONTEXT RxContext
)
1618 PIO_STACK_LOCATION Stack
;
1619 ACCESS_MASK DesiredAccess
;
1620 RX_BLOCK_CONDITION FcbCondition
;
1624 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1626 Fcb
= (PFCB
)RxContext
->pFcb
;
1627 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1628 ++Fcb
->UncleanCount
;
1630 Stack
= RxContext
->CurrentIrpSp
;
1631 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1632 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1634 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1636 /* Try to find a reusable SRV_OPEN */
1637 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1638 if (Status
== STATUS_NOT_FOUND
)
1640 /* If none found, create one */
1641 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1642 if (SrvOpen
== NULL
)
1644 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1648 SrvOpen
->DesiredAccess
= DesiredAccess
;
1649 SrvOpen
->ShareAccess
= ShareAccess
;
1650 Status
= STATUS_SUCCESS
;
1653 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1655 if (Status
!= STATUS_SUCCESS
)
1657 FcbCondition
= Condition_Bad
;
1661 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1663 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1664 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1665 /* Inform the mini-rdr we're handling a create */
1666 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1667 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1669 DPRINT("MRxCreate returned: %x\n", Status
);
1670 if (Status
== STATUS_SUCCESS
)
1672 /* In case of overwrite, reset file size */
1673 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1675 RxAcquirePagingIoResource(RxContext
, Fcb
);
1676 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1677 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1678 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1679 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1680 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1681 RxReleasePagingIoResource(RxContext
, Fcb
);
1685 /* Otherwise, adjust sizes */
1686 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1687 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1689 RxAdjustAllocationSizeforCC(Fcb
);
1691 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1695 /* Set the IoStatus with information returned by mini-rdr */
1696 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1698 SrvOpen
->OpenStatus
= Status
;
1699 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1700 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1702 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1704 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1706 if (Status
== STATUS_SUCCESS
)
1708 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1710 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1712 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1713 FcbCondition
= Condition_Good
;
1717 FcbCondition
= Condition_Bad
;
1718 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1719 RxContext
->pRelevantSrvOpen
= NULL
;
1721 if (RxContext
->pFobx
!= NULL
)
1723 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1724 RxContext
->pFobx
= NULL
;
1729 /* Set FCB state - good or bad - depending on whether create succeed */
1730 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1731 RxTransitionNetFcb(Fcb
, FcbCondition
);
1733 else if (Status
== STATUS_SUCCESS
)
1735 BOOLEAN IsGood
, ExtraOpen
;
1737 /* A reusable SRV_OPEN was found */
1738 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1741 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1743 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1744 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1745 if (!StableCondition(SrvOpen
->Condition
))
1747 RxReferenceSrvOpen(SrvOpen
);
1748 ++SrvOpen
->OpenCount
;
1751 RxReleaseFcb(RxContext
, Fcb
);
1752 RxContext
->Create
.FcbAcquired
= FALSE
;
1754 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1756 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1758 RxContext
->Create
.FcbAcquired
= TRUE
;
1761 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1764 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1767 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1769 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1773 Status
= SrvOpen
->OpenStatus
;
1778 --SrvOpen
->OpenCount
;
1779 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1783 --Fcb
->UncleanCount
;
1785 DPRINT("Status: %x\n", Status
);
1795 PRX_CONTEXT Context
)
1797 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1803 PFILE_OBJECT FileObject
;
1804 LARGE_INTEGER TruncateSize
;
1805 PLARGE_INTEGER TruncateSizePtr
;
1806 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1810 Fcb
= (PFCB
)Context
->pFcb
;
1811 Fobx
= (PFOBX
)Context
->pFobx
;
1812 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1814 /* File system closing, it's OK */
1817 if (Fcb
->UncleanCount
> 0)
1819 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1822 return STATUS_SUCCESS
;
1825 /* Check we have a correct FCB type */
1826 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1827 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1828 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1829 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1831 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1832 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1835 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1836 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1838 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1840 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1841 if (!NT_SUCCESS(Status
))
1848 Fobx
->AssociatedFileObject
= NULL
;
1850 /* In case SRV_OPEN used is part of FCB */
1851 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
))
1853 ASSERT(Fcb
->UncleanCount
!= 0);
1854 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1856 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1858 --Fcb
->UncachedUncleanCount
;
1861 /* Inform mini-rdr */
1862 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1864 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1865 --Fobx
->SrvOpen
->UncleanFobxCount
;
1867 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1869 RxReleaseFcb(Context
, Fcb
);
1871 return STATUS_SUCCESS
;
1874 /* Report the fact that file could be set as delete on close */
1875 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1877 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1880 /* Cancel any pending notification */
1881 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1883 /* Backup open count before we start playing with it */
1884 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1886 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1887 FcbTableAcquired
= FALSE
;
1888 LeftForDelete
= FALSE
;
1889 OneLeft
= (Fcb
->UncleanCount
== 1);
1893 /* Unclean count and delete on close? Verify whether we're the one */
1894 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1896 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1898 FcbTableAcquired
= TRUE
;
1902 RxReleaseFcb(Context
, Fcb
);
1904 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1906 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1907 if (Status
!= STATUS_SUCCESS
)
1909 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1913 FcbTableAcquired
= TRUE
;
1916 /* That means we'll perform the delete on close! */
1917 if (Fcb
->UncleanCount
== 1)
1919 LeftForDelete
= TRUE
;
1923 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1924 FcbTableAcquired
= FALSE
;
1929 TruncateSizePtr
= NULL
;
1930 /* Handle cleanup for pipes and printers */
1931 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1933 RxCleanupPipeQueues(Context
);
1935 /* Handle cleanup for files */
1936 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1938 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1939 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1942 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1944 /* If there are still locks to release, proceed */
1945 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1947 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1948 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1949 Status
= RxLowIoLockControlShell(Context
);
1952 /* Fix times and size */
1953 RxAdjustFileTimesAndSize(Context
);
1955 /* If we're the only one left... */
1958 /* And if we're supposed to delete on close */
1961 /* Update the sizes */
1962 RxAcquirePagingIoResource(Context
, Fcb
);
1963 Fcb
->Header
.FileSize
.QuadPart
= 0;
1964 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1965 RxReleasePagingIoResource(Context
, Fcb
);
1967 /* Otherwise, call the mini-rdr to adjust sizes */
1970 /* File got grown up, fill with zeroes */
1971 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1972 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1974 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1975 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1978 /* File was truncated, let mini-rdr proceed */
1979 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1981 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1982 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1984 /* Keep track of file change for Cc uninit */
1985 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1986 TruncateSizePtr
= &TruncateSize
;
1991 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1999 /* Otherwise, try to see whether we can purge */
2002 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2009 /* We have to still be there! */
2010 ASSERT(Fcb
->UncleanCount
!= 0);
2011 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2013 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2015 --Fcb
->UncachedUncleanCount
;
2018 /* Inform mini-rdr about ongoing cleanup */
2019 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2021 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2022 --Fobx
->SrvOpen
->UncleanFobxCount
;
2025 if (DisableFlushOnCleanup
)
2027 /* Only if we're the last standing */
2028 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2029 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2031 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2032 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2038 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2040 DPRINT("Flushing %p on cleanup\n", Context
);
2041 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2045 /* If only remaining uncached & unclean, then flush and purge */
2046 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2048 if (Fcb
->UncachedUncleanCount
!= 0)
2050 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2051 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2053 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2054 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2059 /* If purge required, and not about to delete, flush */
2060 if (!LeftForDelete
&& NeedPurge
)
2062 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2063 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2066 /* If it was a file, drop cache */
2069 DPRINT("Uninit cache map for file\n");
2070 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2073 /* If that's the one left for deletion, or if it needs purge, flush */
2074 if (LeftForDelete
|| NeedPurge
)
2076 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2077 /* If that's for deletion, also remove from FCB table */
2080 RxRemoveNameNetFcb(Fcb
);
2081 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2082 FcbTableAcquired
= FALSE
;
2086 /* Remove any share access */
2087 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2089 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2092 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2093 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2094 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2096 NTSTATUS InternalStatus
;
2097 PRX_CONTEXT InternalContext
;
2099 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2100 InternalStatus
= STATUS_UNSUCCESSFUL
;
2101 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2102 Fcb
->RxDeviceObject
,
2103 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2104 if (InternalContext
!= NULL
)
2106 FILE_END_OF_FILE_INFORMATION FileEOF
;
2108 InternalStatus
= STATUS_SUCCESS
;
2110 /* Initialize the context for file information set */
2111 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2112 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2113 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2115 /* Get EOF from the FCB */
2116 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2117 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2118 InternalContext
->Info
.Buffer
= &FileEOF
;
2119 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2121 /* Call the mini-rdr */
2122 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2125 RxDereferenceAndDeleteRxContext(InternalContext
);
2128 /* We tried, so, clean the FOBX flag */
2129 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2130 /* If it failed, then, disable collapsing on the FCB */
2131 if (!NT_SUCCESS(InternalStatus
))
2133 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2138 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2140 FcbAcquired
= FALSE
;
2141 RxReleaseFcb(Context
, Fcb
);
2147 RxReleaseFcb(Context
, Fcb
);
2150 if (FcbTableAcquired
)
2152 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2158 #undef BugCheckFileId
2164 PRX_CONTEXT Context
)
2166 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2170 PFILE_OBJECT FileObject
;
2171 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2175 Fcb
= (PFCB
)Context
->pFcb
;
2176 Fobx
= (PFOBX
)Context
->pFobx
;
2177 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2178 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2180 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2181 if (!NT_SUCCESS(Status
))
2191 /* Check our FCB type is expected */
2192 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2193 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2194 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2196 RxBugCheck(NodeType(Fcb
), 0, 0);
2199 RxReferenceNetFcb(Fcb
);
2201 DereferenceFobx
= FALSE
;
2202 /* If we're not closing FS */
2208 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2209 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2210 /* Handle delayed close */
2211 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2213 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2215 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2217 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2219 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2221 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2223 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2227 DereferenceFobx
= TRUE
;
2228 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2235 /* If we reach maximum of delayed close/or if there are no delayed close */
2236 if (!DereferenceFobx
)
2240 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2241 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2243 /* Delete if asked */
2244 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2246 RxScavengeRelatedFobxs(Fcb
);
2247 RxSynchronizeWithScavenger(Context
);
2249 RxReleaseFcb(Context
, Fcb
);
2251 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2252 RxOrphanThisFcb(Fcb
);
2253 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2255 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2256 ASSERT(NT_SUCCESS(Status
));
2261 RxMarkFobxOnClose(Fobx
);
2264 if (DereferenceFobx
)
2266 ASSERT(Fobx
!= NULL
);
2267 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2271 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2274 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2278 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2279 AcquiredFcb
= !Freed
;
2281 FileObject
->FsContext
= (PVOID
)-1;
2285 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2289 RxReleaseFcb(Context
, Fcb
);
2290 AcquiredFcb
= FALSE
;
2295 if (_SEH2_AbnormalTermination())
2299 RxReleaseFcb(Context
, Fcb
);
2304 ASSERT(!AcquiredFcb
);
2309 DPRINT("Status: %x\n", Status
);
2311 #undef BugCheckFileId
2320 PRX_CONTEXT Context
)
2324 PFILE_OBJECT FileObject
;
2325 PIO_STACK_LOCATION Stack
;
2329 DPRINT("RxCommonCreate(%p)\n", Context
);
2331 Irp
= Context
->CurrentIrp
;
2332 Stack
= Context
->CurrentIrpSp
;
2333 FileObject
= Stack
->FileObject
;
2335 /* Check whether that's a device opening */
2336 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2338 FileObject
->FsContext
= &RxDeviceFCB
;
2339 FileObject
->FsContext2
= NULL
;
2341 ++RxDeviceFCB
.NodeReferenceCount
;
2342 ++RxDeviceFCB
.OpenCount
;
2344 Irp
->IoStatus
.Information
= FILE_OPENED
;
2345 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2347 Status
= STATUS_SUCCESS
;
2351 PFCB RelatedFcb
= NULL
;
2353 /* Make sure caller is consistent */
2354 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2355 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2357 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2358 return STATUS_INVALID_PARAMETER
;
2361 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2362 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2363 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2364 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2366 if (FileObject
->RelatedFileObject
!= NULL
)
2368 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2369 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2372 /* Going to rename? */
2373 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2375 DPRINT("TargetDir!\n");
2378 /* Copy create parameters to the context */
2379 RxCopyCreateParameters(Context
);
2381 /* If the caller wants to establish a connection, go ahead */
2382 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2384 Status
= RxCreateTreeConnect(Context
);
2388 /* Validate file name */
2389 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2390 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2391 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2393 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2394 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2395 FileObject
->FileName
.Length
);
2397 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2398 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2399 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2401 return STATUS_OBJECT_NAME_INVALID
;
2405 /* Attempt to open the file */
2408 UNICODE_STRING NetRootName
;
2410 /* Strip last \ if required */
2411 if (FileObject
->FileName
.Length
!= 0 &&
2412 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2414 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2416 return STATUS_OBJECT_NAME_INVALID
;
2419 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2420 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2423 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2425 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2428 /* Get the associated net root to opening */
2429 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2430 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2435 /* And attempt to open */
2436 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2437 if (Status
== STATUS_SHARING_VIOLATION
)
2439 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2441 /* If that happens for file creation, fail for real */
2442 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2444 Status
= STATUS_OBJECT_NAME_COLLISION
;
2448 /* Otherwise, if possible, attempt to scavenger current FOBX
2449 * to check whether a dormant FOBX is the reason for sharing violation
2451 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2452 !Context
->Create
.ScavengingAlreadyTried
)
2454 /* Only doable with a VNetRoot */
2455 if (Context
->Create
.pVNetRoot
!= NULL
)
2457 PV_NET_ROOT VNetRoot
;
2458 NT_CREATE_PARAMETERS SavedParameters
;
2460 /* Save create parameters */
2461 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2463 /* Reference the VNetRoot for the scavenging time */
2464 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2465 RxReferenceVNetRoot(VNetRoot
);
2467 /* Prepare the RX_CONTEXT for reuse */
2468 RxpPrepareCreateContextForReuse(Context
);
2469 RxReinitializeContext(Context
);
2471 /* Copy what we saved */
2472 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2474 /* And recopy what can be */
2475 RxCopyCreateParameters(Context
);
2477 /* And start purging, then scavenging FOBX */
2478 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2479 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2480 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2483 /* Ask for a second round */
2484 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2486 /* Keep track we already scavenged */
2487 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2489 /* Reference our SRV_CALL for CBS handling */
2490 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2491 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2493 /* Drop our extra reference */
2494 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2499 else if (Status
== STATUS_REPARSE
)
2501 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2505 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2508 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2511 if (Status
== STATUS_RETRY
)
2513 RxpPrepareCreateContextForReuse(Context
);
2515 ASSERT(Status
!= STATUS_PENDING
);
2518 DPRINT("Status: %lx\n", Status
);
2527 RxCommonDevFCBCleanup(
2528 PRX_CONTEXT Context
)
2535 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2537 Fcb
= Context
->pFcb
;
2538 Status
= STATUS_SUCCESS
;
2539 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2541 /* Our FOBX if set, has to be a VNetRoot */
2542 if (Context
->pFobx
!= NULL
)
2544 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2545 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2547 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2549 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2553 --Fcb
->UncleanCount
;
2564 RxCommonDevFCBClose(
2565 PRX_CONTEXT Context
)
2569 PMRX_V_NET_ROOT NetRoot
;
2573 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2575 Fcb
= Context
->pFcb
;
2576 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2577 Status
= STATUS_SUCCESS
;
2578 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2580 /* Our FOBX if set, has to be a VNetRoot */
2581 if (NetRoot
!= NULL
)
2583 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2584 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2586 --NetRoot
->NumberOfOpens
;
2587 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2591 Status
= STATUS_NOT_IMPLEMENTED
;
2593 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2605 RxCommonDevFCBFsCtl(
2606 PRX_CONTEXT Context
)
2609 return STATUS_NOT_IMPLEMENTED
;
2617 RxCommonDevFCBIoCtl(
2618 PRX_CONTEXT Context
)
2624 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2626 if (Context
->pFobx
!= NULL
)
2628 return STATUS_INVALID_HANDLE
;
2631 /* Is that a prefix claim from MUP? */
2632 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2634 return RxPrefixClaim(Context
);
2637 /* Otherwise, pass through the mini-rdr */
2638 Status
= RxXXXControlFileCallthru(Context
);
2639 if (Status
!= STATUS_PENDING
)
2641 if (Context
->PostRequest
)
2643 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2644 Status
= RxFsdPostRequest(Context
);
2648 DPRINT("Status: %lx\n", Status
);
2654 RxCommonDevFCBQueryVolInfo(
2655 PRX_CONTEXT Context
)
2658 return STATUS_NOT_IMPLEMENTED
;
2666 RxCommonDeviceControl(
2667 PRX_CONTEXT Context
)
2673 /* Prefix claim is only allowed for device, not files */
2674 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2676 return STATUS_INVALID_DEVICE_REQUEST
;
2679 /* Submit to mini-rdr */
2680 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2681 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2682 if (Status
== STATUS_PENDING
)
2684 RxDereferenceAndDeleteRxContext_Real(Context
);
2695 RxCommonDirectoryControl(
2696 PRX_CONTEXT Context
)
2701 PIO_STACK_LOCATION Stack
;
2705 Fcb
= (PFCB
)Context
->pFcb
;
2706 Fobx
= (PFOBX
)Context
->pFobx
;
2707 Stack
= Context
->CurrentIrpSp
;
2708 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2710 /* Call the appropriate helper */
2711 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2713 Status
= RxQueryDirectory(Context
);
2715 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2717 Status
= RxNotifyChangeDirectory(Context
);
2718 if (Status
== STATUS_PENDING
)
2720 RxDereferenceAndDeleteRxContext_Real(Context
);
2725 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2733 RxCommonDispatchProblem(
2734 PRX_CONTEXT Context
)
2737 return STATUS_NOT_IMPLEMENTED
;
2742 RxCommonFileSystemControl(
2743 PRX_CONTEXT Context
)
2747 PIO_STACK_LOCATION Stack
;
2751 Irp
= Context
->CurrentIrp
;
2752 Stack
= Context
->CurrentIrpSp
;
2753 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2755 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2758 return STATUS_NOT_IMPLEMENTED
;
2763 RxCommonFlushBuffers(
2764 PRX_CONTEXT Context
)
2767 return STATUS_NOT_IMPLEMENTED
;
2772 RxCommonLockControl(
2773 PRX_CONTEXT Context
)
2776 return STATUS_NOT_IMPLEMENTED
;
2782 PRX_CONTEXT Context
)
2785 return STATUS_NOT_IMPLEMENTED
;
2793 RxCommonQueryInformation(
2794 PRX_CONTEXT Context
)
2796 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2797 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2798 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2805 PIO_STACK_LOCATION Stack
;
2806 FILE_INFORMATION_CLASS FileInfoClass
;
2810 Fcb
= (PFCB
)Context
->pFcb
;
2811 Fobx
= (PFOBX
)Context
->pFobx
;
2812 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2814 Irp
= Context
->CurrentIrp
;
2815 Stack
= Context
->CurrentIrpSp
;
2816 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2817 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2819 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2820 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2827 /* Get a writable buffer */
2828 Buffer
= RxMapSystemBuffer(Context
);
2831 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2835 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2837 /* Validate file type */
2838 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2840 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2842 Status
= STATUS_INVALID_PARAMETER
;
2845 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2847 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2849 Status
= STATUS_NOT_IMPLEMENTED
;
2853 Status
= STATUS_INVALID_PARAMETER
;
2860 /* Acquire the right lock */
2861 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2862 FileInfoClass
!= FileNameInformation
)
2864 if (FileInfoClass
== FileCompressionInformation
)
2866 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2870 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2873 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2875 Status
= STATUS_PENDING
;
2878 else if (!NT_SUCCESS(Status
))
2886 /* Dispatch to the right helper */
2887 switch (FileInfoClass
)
2889 case FileBasicInformation
:
2890 Status
= RxQueryBasicInfo(Context
, Buffer
);
2893 case FileStandardInformation
:
2894 Status
= RxQueryStandardInfo(Context
, Buffer
);
2897 case FileInternalInformation
:
2898 Status
= RxQueryInternalInfo(Context
, Buffer
);
2901 case FileEaInformation
:
2902 Status
= RxQueryEaInfo(Context
, Buffer
);
2905 case FileNameInformation
:
2906 Status
= RxQueryNameInfo(Context
, Buffer
);
2909 case FileAllInformation
:
2910 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2911 if (!NT_SUCCESS(Status
))
2916 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2917 if (!NT_SUCCESS(Status
))
2922 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2923 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2924 if (!NT_SUCCESS(Status
))
2929 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2930 sizeof(FILE_STANDARD_INFORMATION
) +
2931 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2932 if (!NT_SUCCESS(Status
))
2937 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2938 sizeof(FILE_STANDARD_INFORMATION
) +
2939 sizeof(FILE_INTERNAL_INFORMATION
) +
2940 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2941 if (!NT_SUCCESS(Status
))
2946 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2947 sizeof(FILE_STANDARD_INFORMATION
) +
2948 sizeof(FILE_INTERNAL_INFORMATION
) +
2949 sizeof(FILE_EA_INFORMATION
) +
2950 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2953 case FileAlternateNameInformation
:
2954 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2957 case FilePipeInformation
:
2958 case FilePipeLocalInformation
:
2959 case FilePipeRemoteInformation
:
2960 Status
= RxQueryPipeInfo(Context
, Buffer
);
2963 case FileCompressionInformation
:
2964 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2968 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2969 Status
= Context
->IoStatusBlock
.Status
;
2973 if (Context
->Info
.Length
< 0)
2975 Status
= STATUS_BUFFER_OVERFLOW
;
2976 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2979 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2985 RxReleaseFcb(Context
, Fcb
);
2990 DPRINT("Status: %x\n", Status
);
2993 #undef SET_SIZE_AND_QUERY
2998 RxCommonQueryQuotaInformation(
2999 PRX_CONTEXT Context
)
3002 return STATUS_NOT_IMPLEMENTED
;
3007 RxCommonQuerySecurity(
3008 PRX_CONTEXT Context
)
3011 return STATUS_NOT_IMPLEMENTED
;
3019 RxCommonQueryVolumeInformation(
3020 PRX_CONTEXT Context
)
3026 PIO_STACK_LOCATION Stack
;
3030 Fcb
= (PFCB
)Context
->pFcb
;
3031 Fobx
= (PFOBX
)Context
->pFobx
;
3033 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3035 Irp
= Context
->CurrentIrp
;
3036 Stack
= Context
->CurrentIrpSp
;
3037 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3038 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3040 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3041 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3042 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3044 /* Forward to mini-rdr */
3045 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3047 /* Post request if mini-rdr asked to */
3048 if (Context
->PostRequest
)
3050 Status
= RxFsdPostRequest(Context
);
3054 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3057 DPRINT("Status: %x\n", Status
);
3064 PRX_CONTEXT RxContext
)
3072 PFILE_OBJECT FileObject
;
3073 LARGE_INTEGER ByteOffset
;
3074 PIO_STACK_LOCATION Stack
;
3075 PLOWIO_CONTEXT LowIoContext
;
3076 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3077 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3078 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3082 Fcb
= (PFCB
)RxContext
->pFcb
;
3083 Fobx
= (PFOBX
)RxContext
->pFobx
;
3084 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3086 /* Get some parameters */
3087 Irp
= RxContext
->CurrentIrp
;
3088 Stack
= RxContext
->CurrentIrpSp
;
3089 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3090 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3091 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3092 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3093 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3094 ReadLength
= Stack
->Parameters
.Read
.Length
;
3095 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3096 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3097 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3099 RxItsTheSameContext();
3101 Irp
->IoStatus
.Information
= 0;
3103 /* Should the read be loud - so far, it's just ignored on ReactOS:
3104 * s/DPRINT/DPRINT1/g will make it loud
3106 LowIoContext
= &RxContext
->LowIoContext
;
3107 CheckForLoudOperations(RxContext
);
3108 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3110 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3111 ByteOffset
, ReadLength
,
3112 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3115 RxDeviceObject
= RxContext
->RxDeviceObject
;
3117 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3119 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3121 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3123 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3125 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3129 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3133 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3137 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3141 /* A pagefile cannot be a pipe */
3142 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3143 if (IsPipe
&& PagingIo
)
3145 return STATUS_INVALID_DEVICE_REQUEST
;
3148 /* Null-length read is no-op */
3149 if (ReadLength
== 0)
3151 return STATUS_SUCCESS
;
3154 /* Validate FCB type */
3155 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3157 return STATUS_INVALID_DEVICE_REQUEST
;
3160 /* Init the lowio context for possible forward */
3161 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3163 PostRequest
= FALSE
;
3164 ReadCachingDisabled
= FALSE
;
3166 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3167 FileObject
= Stack
->FileObject
;
3168 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3173 /* If no caching, make sure current Cc data have been flushed */
3174 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3176 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3177 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3182 else if (Status
!= STATUS_SUCCESS
)
3187 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3188 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3189 RxReleasePagingIoResource(RxContext
, Fcb
);
3191 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3193 Status
= Irp
->IoStatus
.Status
;
3197 RxAcquirePagingIoResource(RxContext
, Fcb
);
3198 RxReleasePagingIoResource(RxContext
, Fcb
);
3201 /* Acquire the appropriate lock */
3202 if (PagingIo
&& !ReadCachingEnabled
)
3206 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3214 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3219 if (!ReadCachingEnabled
)
3221 if (!CanWait
&& NoCache
)
3223 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3224 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3226 DPRINT1("RdAsyLNG %x\n", RxContext
);
3230 if (Status
!= STATUS_SUCCESS
)
3232 DPRINT1("RdAsyOthr %x\n", RxContext
);
3236 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3238 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3248 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3249 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3254 else if (Status
!= STATUS_SUCCESS
)
3262 RxItsTheSameContext();
3264 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3270 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3272 /* Make sure FLOCK doesn't conflict */
3275 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3277 Status
= STATUS_FILE_LOCK_CONFLICT
;
3282 /* Validate byteoffset vs length */
3283 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3285 if (ByteOffset
.QuadPart
>= FileSize
)
3287 Status
= STATUS_END_OF_FILE
;
3291 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3293 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3298 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3299 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3301 /* File was not cached yet, do it */
3302 if (FileObject
->PrivateCacheMap
== NULL
)
3304 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3306 Status
= STATUS_FILE_CLOSED
;
3310 RxAdjustAllocationSizeforCC(Fcb
);
3312 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3313 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3315 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3317 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3321 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3322 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3325 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3328 /* This should never happen - fix your RDR */
3329 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3334 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3335 Status
= Irp
->IoStatus
.Status
;
3336 ASSERT(NT_SUCCESS(Status
));
3341 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3342 if (SystemBuffer
== NULL
)
3344 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3348 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3350 RxItsTheSameContext();
3352 /* Perform the read */
3353 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3355 if (!ReadCachingEnabled
)
3357 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3360 RxItsTheSameContext();
3366 if (!ReadCachingEnabled
)
3368 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3371 Status
= Irp
->IoStatus
.Status
;
3372 ASSERT(NT_SUCCESS(Status
));
3377 /* Validate the reading */
3378 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3379 ByteOffset
.QuadPart
>= 4096)
3381 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3382 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3385 /* If it's consistent, forward to mini-rdr */
3386 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3387 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3389 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3390 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3392 RxItsTheSameContext();
3394 if (InFsp
&& ReadCachingDisabled
)
3396 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3397 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3401 Status
= RxLowIoReadShell(RxContext
);
3403 RxItsTheSameContext();
3407 if (ByteOffset
.QuadPart
> FileSize
)
3410 Irp
->IoStatus
.Information
= ReadLength
;
3414 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3416 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3419 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3420 RtlZeroMemory(SystemBuffer
, ReadLength
);
3421 Irp
->IoStatus
.Information
= ReadLength
;
3427 RxItsTheSameContext();
3429 /* Post if required */
3432 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3433 Status
= RxFsdPostRequest(RxContext
);
3437 /* Update FO in case of sync IO */
3438 if (!IsPipe
&& !PagingIo
)
3440 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3442 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3447 /* Set FastIo if read was a success */
3448 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3450 if (!IsPipe
&& !PagingIo
)
3452 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3456 /* In case we're done (not expected any further processing */
3457 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3459 /* Release everything that can be */
3460 if (ReadCachingDisabled
)
3466 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3470 RxReleasePagingIoResource(RxContext
, Fcb
);
3477 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3481 RxReleaseFcb(RxContext
, Fcb
);
3486 /* Dereference/Delete context */
3489 RxDereferenceAndDeleteRxContext(RxContext
);
3493 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3495 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3499 /* We cannot return more than asked */
3500 if (Status
== STATUS_SUCCESS
)
3502 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3509 RxDereferenceAndDeleteRxContext(RxContext
);
3520 PRX_CONTEXT Context
)
3523 return STATUS_NOT_IMPLEMENTED
;
3531 RxCommonSetInformation(
3532 PRX_CONTEXT Context
)
3539 PIO_STACK_LOCATION Stack
;
3540 FILE_INFORMATION_CLASS Class
;
3541 BOOLEAN CanWait
, FcbTableAcquired
, FcbAcquired
;
3545 Fcb
= (PFCB
)Context
->pFcb
;
3546 Fobx
= (PFOBX
)Context
->pFobx
;
3547 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3549 Irp
= Context
->CurrentIrp
;
3550 Stack
= Context
->CurrentIrpSp
;
3551 Class
= Stack
->Parameters
.SetFile
.FileInformationClass
;
3552 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3553 Irp
->AssociatedIrp
.SystemBuffer
, Stack
->Parameters
.SetFile
.Length
,
3554 Class
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
3556 Status
= STATUS_SUCCESS
;
3557 CanWait
= BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3558 FcbTableAcquired
= FALSE
;
3559 FcbAcquired
= FALSE
;
3560 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3562 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3566 /* Valide the node type first */
3567 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3568 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3570 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
3572 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3574 Status
= STATUS_SUCCESS
;
3577 else if (NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
3579 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
3581 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3585 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb
));
3586 _SEH2_TRY_RETURN(Status
= STATUS_INVALID_PARAMETER
);
3591 /* We don't autorize advance operation */
3592 if (Class
== FileEndOfFileInformation
&& Stack
->Parameters
.SetFile
.AdvanceOnly
)
3594 DPRINT1("Not allowed\n");
3596 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3599 /* For these to classes, we'll have to deal with the FCB table (removal)
3600 * We thus need the exclusive FCB table lock
3602 if (Class
== FileDispositionInformation
|| Class
== FileRenameInformation
)
3604 RxPurgeRelatedFobxs(NetRoot
, Context
, TRUE
, Fcb
);
3605 RxScavengeFobxsForNetRoot(NetRoot
, Fcb
, TRUE
);
3607 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, CanWait
))
3609 Context
->PostRequest
= TRUE
;
3610 _SEH2_TRY_RETURN(Status
= STATUS_PENDING
);
3613 FcbTableAcquired
= TRUE
;
3616 /* Finally, if not paging file, we need exclusive FCB lock */
3617 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3619 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
3620 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3622 Context
->PostRequest
= TRUE
;
3623 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3625 else if (Status
!= STATUS_SUCCESS
)
3633 Status
= STATUS_SUCCESS
;
3635 /* And now, perform the job! */
3638 case FileBasicInformation
:
3639 Status
= RxSetBasicInfo(Context
);
3642 case FileDispositionInformation
:
3644 PFILE_DISPOSITION_INFORMATION FDI
;
3646 /* Check whether user wants deletion */
3647 FDI
= Irp
->AssociatedIrp
.SystemBuffer
;
3648 if (FDI
->DeleteFile
)
3650 /* If so, check whether it's doable */
3651 if (!MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForDelete
))
3653 Status
= STATUS_CANNOT_DELETE
;
3656 /* And if doable, already remove from FCB table */
3657 if (Status
== STATUS_SUCCESS
)
3659 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3660 RxRemoveNameNetFcb(Fcb
);
3662 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3663 FcbTableAcquired
= FALSE
;
3667 /* If it succeed, perform the operation */
3668 if (Status
== STATUS_SUCCESS
)
3670 Status
= RxSetDispositionInfo(Context
);
3676 case FilePositionInformation
:
3677 Status
= RxSetPositionInfo(Context
);
3680 case FileAllocationInformation
:
3681 Status
= RxSetAllocationInfo(Context
);
3684 case FileEndOfFileInformation
:
3685 Status
= RxSetEndOfFileInfo(Context
);
3688 case FilePipeInformation
:
3689 case FilePipeLocalInformation
:
3690 case FilePipeRemoteInformation
:
3691 Status
= RxSetPipeInfo(Context
);
3694 case FileRenameInformation
:
3695 case FileLinkInformation
:
3696 case FileMoveClusterInformation
:
3697 /* If we can wait, try to perform the operation right now */
3700 /* Of course, collapsing is not doable anymore, file is
3701 * in an inbetween state
3703 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
3705 /* Set the information */
3706 Status
= RxSetRenameInfo(Context
);
3707 /* If it succeed, drop the current entry from FCB table */
3708 if (Status
== STATUS_SUCCESS
&& Class
== FileRenameInformation
)
3710 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3711 RxRemoveNameNetFcb(Fcb
);
3713 _SEH2_TRY_RETURN(Status
);
3715 /* Can't wait? Post for async retry */
3718 Status
= RxFsdPostRequest(Context
);
3719 _SEH2_TRY_RETURN(Status
);
3723 case FileValidDataLengthInformation
:
3724 if (!MmCanFileBeTruncated(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
))
3726 Status
= STATUS_USER_MAPPED_FILE
;
3730 case FileShortNameInformation
:
3731 Status
= RxSetSimpleInfo(Context
);
3735 DPRINT1("Insupported class: %x\n", Class
);
3736 Status
= STATUS_INVALID_PARAMETER
;
3742 /* If mini-rdr was OK and wants a re-post on this, do it */
3743 if (Status
== STATUS_SUCCESS
)
3745 if (Context
->PostRequest
)
3747 Status
= RxFsdPostRequest(Context
);
3753 /* Release any acquired lock */
3756 RxReleaseFcb(Context
, Fcb
);
3759 if (FcbTableAcquired
)
3761 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3766 #undef _SEH2_TRY_RETURN
3773 RxCommonSetQuotaInformation(
3774 PRX_CONTEXT Context
)
3777 return STATUS_NOT_IMPLEMENTED
;
3782 RxCommonSetSecurity(
3783 PRX_CONTEXT Context
)
3786 return STATUS_NOT_IMPLEMENTED
;
3791 RxCommonSetVolumeInformation(
3792 PRX_CONTEXT Context
)
3795 return STATUS_NOT_IMPLEMENTED
;
3800 RxCommonUnimplemented(
3801 PRX_CONTEXT Context
)
3804 return STATUS_NOT_IMPLEMENTED
;
3810 PRX_CONTEXT RxContext
)
3818 PFILE_OBJECT FileObject
;
3819 PIO_STACK_LOCATION Stack
;
3820 LARGE_INTEGER ByteOffset
;
3821 NODE_TYPE_CODE NodeTypeCode
;
3822 PLOWIO_CONTEXT LowIoContext
;
3823 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3824 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3825 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3826 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3830 Fcb
= (PFCB
)RxContext
->pFcb
;
3831 NodeTypeCode
= NodeType(Fcb
);
3832 /* Validate FCB type */
3833 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3834 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3836 return STATUS_INVALID_DEVICE_REQUEST
;
3839 /* We'll write to file, keep track of it */
3840 Fcb
->IsFileWritten
= TRUE
;
3842 Stack
= RxContext
->CurrentIrpSp
;
3843 /* Set write through if asked */
3844 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3846 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3849 Fobx
= (PFOBX
)RxContext
->pFobx
;
3850 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3852 /* Get some parameters */
3853 Irp
= RxContext
->CurrentIrp
;
3854 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3855 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3856 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3857 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3858 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3859 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3860 WriteLength
= Stack
->Parameters
.Write
.Length
;
3861 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3862 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3863 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3865 RxItsTheSameContext();
3867 RxContext
->FcbResourceAcquired
= FALSE
;
3868 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3870 LowIoContext
= &RxContext
->LowIoContext
;
3871 CheckForLoudOperations(RxContext
);
3872 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3874 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3875 ByteOffset
, WriteLength
,
3876 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3879 RxDeviceObject
= RxContext
->RxDeviceObject
;
3881 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3883 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3885 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3887 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3889 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3893 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3897 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3901 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3905 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3906 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3907 /* Keep track for normal writes */
3908 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3917 /* Zero-length write is immediate success */
3918 if (NormalFile
&& WriteLength
== 0)
3920 return STATUS_SUCCESS
;
3923 /* Check whether we have input data */
3924 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3926 return STATUS_INVALID_PARAMETER
;
3929 /* Are we writting to EOF? */
3930 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3931 /* FIXME: validate length/offset */
3933 /* Get our SRV_OPEN in case of normal write */
3936 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3943 FileObject
= Stack
->FileObject
;
3945 /* If we have caching enabled, check whether we have to defer write */
3948 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3950 if (!CcCanIWrite(FileObject
, WriteLength
,
3951 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3952 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
3956 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3958 RxPrePostIrp(RxContext
, Irp
);
3960 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3962 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
3964 return STATUS_PENDING
;
3969 /* Initialize the low IO context for write */
3970 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
3972 /* Initialize our (many) booleans */
3973 RecursiveWriteThrough
= FALSE
;
3974 CalledByLazyWriter
= FALSE
;
3975 SwitchBackToAsync
= FALSE
;
3976 ExtendingFile
= FALSE
;
3977 ExtendingValidData
= FALSE
;
3978 UnwindOutstandingAsync
= FALSE
;
3979 ResourceOwnerSet
= FALSE
;
3981 ContextReferenced
= FALSE
;
3983 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3987 /* No volume FCB here! */
3988 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
3989 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
3990 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
3992 /* Writing to EOF on a paging file is non sense */
3993 ASSERT(!(WriteToEof
&& PagingIo
));
3995 RxItsTheSameContext();
3997 /* Start locking stuff */
3998 if (!PagingIo
&& !NoPreposting
)
4000 /* If it's already acquired, all fine */
4001 if (RxContext
->FcbResourceAcquired
)
4007 /* Otherwise, try to acquire shared (excepted for pipes) */
4010 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4013 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
4015 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
4019 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
4022 /* We'll post IRP to retry */
4023 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4026 DPRINT1("Failed to acquire lock!\n");
4027 _SEH2_TRY_RETURN(Status
);
4030 /* We'll just fail */
4031 if (Status
!= STATUS_SUCCESS
)
4033 _SEH2_TRY_RETURN(Status
);
4036 /* Resource acquired */
4037 RxContext
->FcbResourceAcquired
= TRUE
;
4040 /* At that point, resource is acquired */
4043 ASSERT(RxContext
->FcbResourceAcquired
);
4049 /* Now, check whether we have to promote shared lock */
4050 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4052 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
4059 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4060 if (RxIsFcbAcquiredShared(Fcb
) &&
4061 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
4065 RxReleaseFcb(RxContext
, Fcb
);
4066 RxContext
->FcbResourceAcquired
= FALSE
;
4068 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4069 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4072 DPRINT1("Failed to acquire lock!\n");
4073 _SEH2_TRY_RETURN(Status
);
4076 if (Status
!= STATUS_SUCCESS
)
4078 _SEH2_TRY_RETURN(Status
);
4081 RxContext
->FcbResourceAcquired
= TRUE
;
4085 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4086 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
4089 if (RxIsFcbAcquiredExclusive(Fcb
))
4091 RxConvertToSharedFcb(RxContext
, Fcb
);
4096 /* We're extending file, disable collapsing */
4097 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
4099 DPRINT("Disabling collapsing\n");
4101 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4103 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
4107 ASSERT(RxContext
->FcbResourceAcquired
);
4110 /* Keep track of the acquired resource */
4111 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
4118 /* Lock the paging resource */
4119 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
4121 /* Keep track of the acquired resource */
4122 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
4128 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
4131 /* If it's a non cached write, or if caching is disallowed */
4132 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4134 /* If cache was previously enabled, we'll have to flush before writing */
4135 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
4137 LARGE_INTEGER FlushOffset
;
4140 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
4142 /* If shared, we'll have to relock exclusive */
4143 if (!RxIsFcbAcquiredExclusive(Fcb
))
4145 /* Release and retry exclusive */
4146 RxReleaseFcb(RxContext
, Fcb
);
4147 RxContext
->FcbResourceAcquired
= FALSE
;
4149 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4150 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4153 DPRINT1("Failed to acquire lock for flush!\n");
4154 _SEH2_TRY_RETURN(Status
);
4157 if (Status
!= STATUS_SUCCESS
)
4159 _SEH2_TRY_RETURN(Status
);
4162 RxContext
->FcbResourceAcquired
= TRUE
;
4165 /* Get the length to flush */
4168 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
4172 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
4175 /* Perform the flushing */
4176 RxAcquirePagingIoResource(RxContext
, Fcb
);
4177 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
4178 WriteLength
, &Irp
->IoStatus
);
4179 RxReleasePagingIoResource(RxContext
, Fcb
);
4181 /* Cannot continue if flushing failed */
4182 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
4184 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
4188 RxAcquirePagingIoResource(RxContext
, Fcb
);
4189 RxReleasePagingIoResource(RxContext
, Fcb
);
4192 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
4193 &FlushOffset
, WriteLength
, FALSE
);
4197 /* If not paging IO, check if write is allowed */
4200 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4202 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4206 /* Get file sizes */
4207 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4208 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4209 ASSERT(ValidDataLength
<= FileSize
);
4211 /* If paging IO, we cannot write past file size
4212 * so fix write length if needed
4216 if (ByteOffset
.QuadPart
>= FileSize
)
4218 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4221 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4223 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4227 /* If we're being called by the lazywrite */
4228 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4230 CalledByLazyWriter
= TRUE
;
4232 /* Fail if we're beyong VDL */
4233 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4235 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4236 (ByteOffset
.QuadPart
< FileSize
))
4238 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4240 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4246 /* If that's a recursive synchronous page write */
4247 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4248 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4252 /* Check the top level IRP on the FastIO path */
4253 TopIrp
= RxGetTopIrpIfRdbssIrp();
4254 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4256 PIO_STACK_LOCATION IrpStack
;
4258 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4260 /* If the top level IRP was a cached write for this file, keep track */
4261 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4262 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4263 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4265 RecursiveWriteThrough
= TRUE
;
4266 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4271 /* Now, deal with file size and VDL */
4272 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4273 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4275 /* Not sync? Let's make it sync, just the time we extended */
4279 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4280 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4283 /* Keep track we'll have to switch back to async */
4286 SwitchBackToAsync
= TRUE
;
4290 /* Release all the locks */
4291 RxWriteReleaseResources(RxContext
, 0);
4293 /* Acquire exclusive */
4294 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4295 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4298 DPRINT1("Failed to acquire lock for extension!\n");
4299 _SEH2_TRY_RETURN(Status
);
4302 if (Status
!= STATUS_SUCCESS
)
4304 _SEH2_TRY_RETURN(Status
);
4307 RxContext
->FcbResourceAcquired
= TRUE
;
4309 RxItsTheSameContext();
4311 /* Get the sizes again, to be sure they didn't change in the meantime */
4312 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4313 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4314 ASSERT(ValidDataLength
<= FileSize
);
4316 /* Check we can switch back to async? */
4317 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4318 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4320 SwitchBackToAsync
= FALSE
;
4323 /* If paging IO, check we don't try to extend the file */
4326 if (ByteOffset
.QuadPart
>= FileSize
)
4328 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4331 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4333 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4338 /* Save our initial sizes for potential rollback */
4339 InitialFileSize
= FileSize
;
4340 InitialValidDataLength
= ValidDataLength
;
4341 /* If writing to EOF, update byte offset with file size */
4344 ByteOffset
.QuadPart
= FileSize
;
4347 /* Check again whether we're allowed to write */
4350 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4352 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4355 /* Do we have to extend? */
4356 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4358 DPRINT("Need to extend file\n");
4359 ExtendingFile
= TRUE
;
4360 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4364 /* Let's start to extend */
4367 /* If we're past allocating, inform mini-rdr */
4368 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4369 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4371 LARGE_INTEGER NewAllocationSize
;
4373 DPRINT("Extending %p\n", RxContext
);
4377 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4378 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4379 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4383 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4384 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4385 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4388 if (!NT_SUCCESS(Status
))
4390 _SEH2_TRY_RETURN(Status
);
4393 if (FileSize
> NewAllocationSize
.QuadPart
)
4395 NewAllocationSize
.QuadPart
= FileSize
;
4398 /* And update FCB */
4399 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4402 /* Set the new sizes */
4403 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4404 RxAdjustAllocationSizeforCC(Fcb
);
4407 if (CcIsFileCached(FileObject
))
4409 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4413 /* Do we have to extend VDL? */
4414 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4416 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4418 ExtendingValidData
= TRUE
;
4419 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4423 /* If none cached write */
4424 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4426 /* Switch back to async, if asked to */
4427 if (SwitchBackToAsync
)
4432 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4433 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4436 /* If not synchronous, keep track of writes to be finished */
4439 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4441 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4442 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4443 NotificationEvent
, FALSE
);
4446 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4448 &RxStrucSupSpinLock
) == 0)
4450 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4453 UnwindOutstandingAsync
= TRUE
;
4454 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4457 /* Set our LOWIO_CONTEXT information */
4458 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4459 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4461 RxItsTheSameContext();
4463 /* We have to be locked */
4464 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4466 /* Update thread ID if we're in FSP */
4469 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4471 if (RxContext
->FcbResourceAcquired
)
4473 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4476 if (RxContext
->FcbPagingIoResourceAcquired
)
4478 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4481 ResourceOwnerSet
= TRUE
;
4484 /* And perform the write */
4485 Status
= RxLowIoWriteShell(RxContext
);
4487 RxItsTheSameContext();
4489 /* Not outstanding write anymore */
4490 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4492 UnwindOutstandingAsync
= FALSE
;
4498 /* If cache wasn't enabled yet, do it */
4499 if (FileObject
->PrivateCacheMap
== NULL
)
4501 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4503 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4506 RxAdjustAllocationSizeforCC(Fcb
);
4508 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4509 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4511 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4514 /* If that's a MDL backed write */
4515 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4517 /* Shouldn't happen */
4521 /* Perform it, though */
4522 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4523 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4525 Status
= Irp
->IoStatus
.Status
;
4530 ULONG BreakpointsSave
;
4532 /* Map the user buffer */
4533 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4534 if (SystemBuffer
== NULL
)
4536 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4539 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4541 RxItsTheSameContext();
4543 /* And deal with Cc */
4544 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4547 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4549 RxItsTheSameContext();
4551 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4552 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4558 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4559 Irp
->IoStatus
.Information
= WriteLength
;
4561 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4563 RxItsTheSameContext();
4565 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4566 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4573 /* If we've to post the IRP */
4576 /* Reset the file size if required */
4577 if (ExtendingFile
&& !IsPipe
)
4579 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4580 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4582 RxAcquirePagingIoResource(RxContext
, Fcb
);
4583 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4584 RxReleasePagingIoResource(RxContext
, Fcb
);
4586 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4588 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4592 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4593 ContextReferenced
= TRUE
;
4596 ASSERT(!ResourceOwnerSet
);
4597 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4599 #ifdef RDBSS_TRACKER
4600 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4603 /* And post the request */
4604 Status
= RxFsdPostRequest(RxContext
);
4610 /* Update FILE_OBJECT if synchronous write succeed */
4613 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4615 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4619 /* If write succeed, ,also update FILE_OBJECT flags */
4620 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4622 /* File was modified */
4625 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4628 /* If was even extended */
4631 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4634 /* If VDL was extended, update FCB and inform Cc */
4635 if (ExtendingValidData
)
4637 LONGLONG LastOffset
;
4639 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4640 if (FileSize
< LastOffset
)
4642 LastOffset
= FileSize
;
4645 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4647 if (NoCache
&& CcIsFileCached(FileObject
))
4649 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4658 /* Finally, if we failed while extension was required */
4659 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4664 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4666 RxAcquirePagingIoResource(RxContext
, Fcb
);
4667 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4668 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4669 RxReleasePagingIoResource(RxContext
, Fcb
);
4671 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4673 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4678 /* One async write less */
4679 if (UnwindOutstandingAsync
)
4683 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4684 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4687 /* And now, cleanup everything */
4688 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4690 /* If we didn't post, release every lock (for posting, it's already done) */
4693 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4696 /* If the context was referenced - posting, dereference it */
4697 if (ContextReferenced
)
4699 RxDereferenceAndDeleteRxContext(RxContext
);
4702 /* If that's a pipe operation, resume any blocked one */
4705 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4707 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4711 /* Sanity check for write */
4712 if (Status
== STATUS_SUCCESS
)
4714 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4717 /* Just dereference our context */
4721 RxDereferenceAndDeleteRxContext(RxContext
);
4726 #undef _SEH2_TRY_RETURN
4737 IN PRX_CONTEXT RxContext
)
4740 PFILE_OBJECT FileObject
;
4741 PIO_STACK_LOCATION Stack
;
4743 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4747 Irp
= RxContext
->CurrentIrp
;
4748 Stack
= RxContext
->CurrentIrpSp
;
4749 FileObject
= Stack
->FileObject
;
4751 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4752 switch (RxContext
->MajorFunction
)
4754 /* Call the Cc function */
4756 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4760 /* If here, we can wait */
4761 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4763 /* Call the Cc function */
4764 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4766 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4770 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4771 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4776 Irp
->MdlAddress
= NULL
;
4778 /* And complete the IRP */
4779 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4781 #undef BugCheckFileId
4783 return STATUS_SUCCESS
;
4790 RxCopyCreateParameters(
4791 IN PRX_CONTEXT RxContext
)
4795 PFILE_OBJECT FileObject
;
4796 PIO_STACK_LOCATION Stack
;
4797 PDFS_NAME_CONTEXT DfsNameContext
;
4798 PIO_SECURITY_CONTEXT SecurityContext
;
4800 Irp
= RxContext
->CurrentIrp
;
4801 Stack
= RxContext
->CurrentIrpSp
;
4802 FileObject
= Stack
->FileObject
;
4803 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4805 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4806 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4808 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4809 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4810 RxContext
->Create
.SdLength
);
4812 if (SecurityContext
->SecurityQos
!= NULL
)
4814 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4818 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4820 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4822 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4823 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4824 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4825 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4826 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4828 DfsContext
= FileObject
->FsContext2
;
4829 DfsNameContext
= FileObject
->FsContext
;
4830 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4831 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4832 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4833 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4834 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4835 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4836 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4837 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4838 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4839 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4840 FileObject
->FsContext2
= NULL
;
4841 FileObject
->FsContext
= NULL
;
4843 RxContext
->pFcb
= NULL
;
4844 RxContext
->Create
.ReturnedCreateInformation
= 0;
4846 /* if we stripped last \, it has to be a directory! */
4847 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4849 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4852 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4853 if (RxContext
->Create
.EaLength
== 0)
4855 RxContext
->Create
.EaBuffer
= NULL
;
4859 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4860 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4865 RxCreateFromNetRoot(
4866 PRX_CONTEXT Context
,
4867 PUNICODE_STRING NetRootName
)
4872 PFILE_OBJECT FileObject
;
4873 PIO_STACK_LOCATION Stack
;
4874 ACCESS_MASK DesiredAccess
;
4875 USHORT DesiredShareAccess
;
4879 /* Validate that the context is consistent */
4880 if (Context
->Create
.pNetRoot
== NULL
)
4882 return STATUS_BAD_NETWORK_PATH
;
4885 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
4886 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
4888 return STATUS_BAD_NETWORK_PATH
;
4891 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
4892 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
4894 return STATUS_DFS_UNAVAILABLE
;
4897 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
4898 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
4900 return STATUS_OBJECT_TYPE_MISMATCH
;
4903 Stack
= Context
->CurrentIrpSp
;
4904 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4905 if (NetRoot
->Type
== NET_ROOT_PRINT
)
4907 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
4910 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
4912 /* We don't support renaming yet */
4913 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
4916 return STATUS_NOT_IMPLEMENTED
;
4919 /* Try to find (or create) the FCB for the file */
4920 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
4921 Fcb
= (PFCB
)Context
->pFcb
;
4924 ASSERT(!NT_SUCCESS(Status
));
4926 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
4931 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
4933 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
4937 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
4940 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4941 if (NT_SUCCESS(Status
))
4943 RxTransitionNetFcb(Fcb
, Condition_Good
);
4944 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
4946 RxSetupNetFileObject(Context
);
4947 return STATUS_SUCCESS
;
4951 FileObject
= Stack
->FileObject
;
4952 /* Check SA for conflict */
4953 if (Fcb
->OpenCount
> 0)
4955 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
4956 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
4957 if (!NT_SUCCESS(Status
))
4959 RxDereferenceNetFcb(Fcb
);
4964 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
4965 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
4972 /* Find a SRV_OPEN that suits the opening */
4973 Status
= RxCollapseOrCreateSrvOpen(Context
);
4974 if (Status
== STATUS_SUCCESS
)
4979 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
4980 Fobx
= (PFOBX
)Context
->pFobx
;
4981 /* There are already opens, check for conflict */
4982 if (Fcb
->OpenCount
!= 0)
4984 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
4985 FileObject
, &Fcb
->ShareAccess
,
4986 FALSE
, "second check per useropens",
4989 ++SrvOpen
->UncleanFobxCount
;
4990 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
4997 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
4999 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5000 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
5004 RxSetupNetFileObject(Context
);
5006 /* No conflict? Set up SA */
5007 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
5009 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
5012 ++Fcb
->UncleanCount
;
5013 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
5015 ++Fcb
->UncachedUncleanCount
;
5018 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
5019 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
5021 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
5024 /* No pending close, we're active */
5025 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
5028 ++SrvOpen
->UncleanFobxCount
;
5029 ++SrvOpen
->OpenCount
;
5030 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
5032 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
5034 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
5035 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
5037 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
5038 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
5040 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5043 /* Now, update SA for the SRV_OPEN */
5044 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
5046 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
5048 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
5051 /* Update the FOBX info */
5054 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5056 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
5059 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
5060 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5062 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
5064 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
5065 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
5067 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
5068 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
5069 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
5071 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
5072 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
5076 Status
= STATUS_SUCCESS
;
5081 if (Fcb
->OpenCount
== 0)
5083 if (Context
->Create
.FcbAcquired
)
5085 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
5089 if (!Context
->Create
.FcbAcquired
)
5091 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
5097 RxDereferenceNetFcb(Fcb
);
5109 RxCreateTreeConnect(
5110 IN PRX_CONTEXT RxContext
)
5113 PV_NET_ROOT VNetRoot
;
5114 PFILE_OBJECT FileObject
;
5115 PIO_STACK_LOCATION Stack
;
5116 NET_ROOT_TYPE NetRootType
;
5117 UNICODE_STRING CanonicalName
, RemainingName
;
5121 Stack
= RxContext
->CurrentIrpSp
;
5122 FileObject
= Stack
->FileObject
;
5124 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
5125 /* As long as we don't know connection type, mark it wild */
5126 NetRootType
= NET_ROOT_WILD
;
5127 /* Get the type by parsing the name */
5128 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
5129 if (!NT_SUCCESS(Status
))
5134 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
5135 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
5136 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
5137 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
5138 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
5139 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
5141 /* We don't handle EA - they come from DFS, don't care */
5142 if (Stack
->Parameters
.Create
.EaLength
> 0)
5147 /* Mount if required */
5148 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5149 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
5151 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
5152 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5155 if (!NT_SUCCESS(Status
))
5160 /* Validate the rest of the name with mini-rdr */
5161 if (RemainingName
.Length
> 0)
5163 MINIRDR_CALL(Status
, RxContext
,
5164 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5165 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
5168 if (!NT_SUCCESS(Status
))
5173 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5174 RxReferenceVNetRoot(VNetRoot
);
5175 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
5177 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
5180 FileObject
->FsContext
= &RxDeviceFCB
;
5181 FileObject
->FsContext2
= VNetRoot
;
5183 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
5184 ++VNetRoot
->NumberOfOpens
;
5186 /* Create is over - clear context */
5187 RxContext
->Create
.pSrvCall
= NULL
;
5188 RxContext
->Create
.pNetRoot
= NULL
;
5189 RxContext
->Create
.pVNetRoot
= NULL
;
5196 RxDebugControlCommand(
5197 _In_ PSTR ControlString
)
5205 IN PDRIVER_OBJECT DriverObject
,
5206 IN PUNICODE_STRING RegistryPath
)
5209 USHORT i
, State
= 0;
5211 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
5215 RxCheckFcbStructuresForAlignment();
5217 RtlZeroMemory(&RxData
, sizeof(RxData
));
5218 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
5219 RxData
.NodeByteSize
= sizeof(RxData
);
5220 RxData
.DriverObject
= DriverObject
;
5222 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
5223 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
5224 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5226 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5227 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5229 RxInitializeDebugSupport();
5231 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5232 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5237 RxGetRegistryParameters(RegistryPath
);
5238 RxReadRegistryParameters();
5240 Status
= RxInitializeRegistrationStructures();
5241 if (!NT_SUCCESS(Status
))
5247 RxInitializeDispatcher();
5249 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5251 InitializeListHead(&RxIrpsList
);
5252 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5254 InitializeListHead(&RxActiveContexts
);
5255 InitializeListHead(&RxSrvCalldownList
);
5257 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5258 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5259 KeInitializeMutex(&RxScavengerMutex
, 1);
5260 KeInitializeMutex(&RxSerializationMutex
, 1);
5262 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5264 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5265 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5266 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5269 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5271 RxInitializeDispatchVectors(DriverObject
);
5273 ExInitializeResourceLite(&RxData
.Resource
);
5274 RxData
.OurProcess
= IoGetCurrentProcess();
5276 RxInitializeRxTimer();
5280 if (!NT_SUCCESS(Status
))
5282 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5283 RxInitUnwind(DriverObject
, State
);
5287 /* There are still bits to init - be consider it's fine for now */
5290 return STATUS_NOT_IMPLEMENTED
;
5292 return STATUS_SUCCESS
;
5301 RxDumpCurrentAccess(
5304 _In_ PSZ wherelogtag
,
5305 _In_ PSHARE_ACCESS ShareAccess
)
5317 _In_ PSZ wherelogtag
,
5318 _In_ ACCESS_MASK DesiredAccess
,
5319 _In_ ULONG DesiredShareAccess
)
5330 RxFastIoCheckIfPossible(
5331 PFILE_OBJECT FileObject
,
5332 PLARGE_INTEGER FileOffset
,
5333 ULONG Length
, BOOLEAN Wait
,
5334 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5335 PIO_STATUS_BLOCK IoStatus
,
5336 PDEVICE_OBJECT DeviceObject
)
5340 LARGE_INTEGER LargeLength
;
5344 /* Get the FCB to validate it */
5345 Fcb
= FileObject
->FsContext
;
5346 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5348 DPRINT1("Not a file, FastIO not possible!\n");
5352 if (FileObject
->DeletePending
)
5354 DPRINT1("File delete pending\n");
5358 /* If there's a pending write operation, deny fast operation */
5359 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5361 DPRINT1("Write operations to be completed\n");
5365 /* Deny read on orphaned node */
5366 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5367 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5369 DPRINT1("SRV_OPEN orphaned\n");
5373 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5375 DPRINT1("FCB orphaned\n");
5379 /* If there's a buffering state change pending, deny fast operation (it might change
5382 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5384 DPRINT1("Buffering change pending\n");
5388 /* File got renamed/deleted, deny operation */
5389 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5390 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5392 DPRINT1("File renamed/deleted\n");
5396 /* Process pending change buffering state operations */
5397 FsRtlEnterFileSystem();
5398 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5399 FsRtlExitFileSystem();
5401 LargeLength
.QuadPart
= Length
;
5403 /* If operation to come is a read operation */
5404 if (CheckForReadOperation
)
5406 /* Check that read cache is enabled */
5407 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5409 DPRINT1("Read caching disabled\n");
5413 /* Check whether there's a lock conflict */
5414 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5419 PsGetCurrentProcess()))
5421 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5428 /* Check that write cache is enabled */
5429 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
))
5431 DPRINT1("Write caching disabled\n");
5435 /* Check whether there's a lock conflict */
5436 if (!FsRtlFastCheckLockForWrite(&Fcb
->Specific
.Fcb
.FileLock
,
5441 PsGetCurrentProcess()))
5443 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5452 RxFastIoDeviceControl(
5453 PFILE_OBJECT FileObject
,
5455 PVOID InputBuffer OPTIONAL
,
5456 ULONG InputBufferLength
,
5457 PVOID OutputBuffer OPTIONAL
,
5458 ULONG OutputBufferLength
,
5459 ULONG IoControlCode
,
5460 PIO_STATUS_BLOCK IoStatus
,
5461 PDEVICE_OBJECT DeviceObject
)
5463 /* Only supported IOCTL */
5464 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5481 PFILE_OBJECT FileObject
,
5482 PLARGE_INTEGER FileOffset
,
5487 PIO_STATUS_BLOCK IoStatus
,
5488 PDEVICE_OBJECT DeviceObject
)
5491 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5495 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5496 FileObject
->FsContext2
);
5497 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5499 /* Prepare a TLI context */
5500 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5501 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5502 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5504 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5505 IoStatus
, DeviceObject
, &TopLevelContext
);
5508 DPRINT("Read OK\n");
5512 DPRINT1("Read failed!\n");
5524 PFILE_OBJECT FileObject
,
5525 PLARGE_INTEGER FileOffset
,
5530 PIO_STATUS_BLOCK IoStatus
,
5531 PDEVICE_OBJECT DeviceObject
)
5535 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5539 Fobx
= (PFOBX
)FileObject
->FsContext2
;
5540 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_BAD_HANDLE
))
5545 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5546 FileObject
->FsContext2
);
5547 DPRINT("Writing %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5549 /* Prepare a TLI context */
5550 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5551 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5552 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5554 Ret
= FsRtlCopyWrite2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5555 IoStatus
, DeviceObject
, &TopLevelContext
);
5558 DPRINT("Write OK\n");
5562 DPRINT1("Write failed!\n");
5570 PRX_CONTEXT RxContext
,
5571 PUNICODE_STRING NetRootName
)
5577 PV_NET_ROOT VNetRoot
;
5578 BOOLEAN TableAcquired
, AcquiredExclusive
;
5582 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5583 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5584 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5586 Status
= STATUS_SUCCESS
;
5587 AcquiredExclusive
= FALSE
;
5589 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5590 TableAcquired
= TRUE
;
5591 Version
= NetRoot
->FcbTable
.Version
;
5593 /* Look for a cached FCB */
5594 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5597 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5601 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5602 /* If FCB was to be orphaned, consider it as not suitable */
5603 if (Fcb
->fShouldBeOrphaned
)
5605 RxDereferenceNetFcb(Fcb
);
5606 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5608 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5609 TableAcquired
= TRUE
;
5610 AcquiredExclusive
= TRUE
;
5612 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5613 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5615 RxOrphanThisFcb(Fcb
);
5616 RxDereferenceNetFcb(Fcb
);
5622 /* If FCB was not found or is not covering full path, prepare for more work */
5623 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5627 DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb
->FcbTableEntry
.Path
, NetRootName
);
5630 if (!AcquiredExclusive
)
5632 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5633 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5634 TableAcquired
= TRUE
;
5637 /* If FCB table was updated in between, re-attempt a lookup */
5638 if (NetRoot
->FcbTable
.Version
!= Version
)
5640 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5641 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5648 /* Allocate the FCB */
5653 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5656 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5660 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5661 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5667 if (_SEH2_AbnormalTermination())
5669 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5670 TableAcquired
= FALSE
;
5674 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5676 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5677 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5679 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5688 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5691 if (!NT_SUCCESS(Status
))
5696 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5697 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5699 if (!RxContext
->Create
.FcbAcquired
)
5701 RxWaitForStableNetFcb(Fcb
, RxContext
);
5702 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5703 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5710 RxFirstCanonicalize(
5711 PRX_CONTEXT RxContext
,
5712 PUNICODE_STRING FileName
,
5713 PUNICODE_STRING CanonicalName
,
5714 PNET_ROOT_TYPE NetRootType
)
5718 BOOLEAN UncName
, PrependString
, IsSpecial
;
5719 USHORT CanonicalLength
;
5720 UNICODE_STRING SessionIdString
;
5721 WCHAR SessionIdBuffer
[16];
5725 Type
= NET_ROOT_WILD
;
5726 PrependString
= FALSE
;
5729 Status
= STATUS_SUCCESS
;
5731 /* Name has to contain at least \\ */
5732 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5734 return STATUS_OBJECT_NAME_INVALID
;
5737 /* First easy check, is that a path with a name? */
5738 CanonicalLength
= FileName
->Length
;
5739 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5741 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5743 if (FileName
->Buffer
[3] == ':')
5745 Type
= NET_ROOT_DISK
;
5749 Type
= NET_ROOT_PRINT
;
5754 /* Nope, attempt deeper parsing */
5755 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5758 PWSTR FirstSlash
, EndOfString
;
5760 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5763 /* The lack of drive letter will be replaced by session ID */
5764 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5765 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5766 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5768 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5769 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5771 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5777 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5779 Status
= STATUS_OBJECT_NAME_INVALID
;
5784 DPRINT1("WARNING: Assuming not special + disk!\n");
5785 Type
= NET_ROOT_DISK
;
5786 Status
= STATUS_SUCCESS
;
5787 //Status = STATUS_NOT_IMPLEMENTED;
5788 /* Should be check against IPC, mailslot, and so on */
5792 /* Update net root type with our deduced one */
5793 *NetRootType
= Type
;
5794 DPRINT("Returning type: %x\n", Type
);
5796 if (!NT_SUCCESS(Status
))
5801 /* Do we have to prepend session ID? */
5806 PrependString
= TRUE
;
5807 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5811 /* If not UNC path, we should preprend stuff */
5812 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5814 return STATUS_OBJECT_PATH_INVALID
;
5817 /* Allocate the buffer */
5818 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
5819 if (!NT_SUCCESS(Status
))
5824 /* We don't support that case, we always return disk */
5827 ASSERT(CanonicalName
->Length
== CanonicalLength
);
5829 Status
= STATUS_NOT_IMPLEMENTED
;
5833 /* If we have to prepend, go ahead */
5836 CanonicalName
->Buffer
[0] = '\\';
5837 CanonicalName
->Buffer
[1] = ';';
5838 CanonicalName
->Buffer
[2] = ':';
5839 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
5840 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
5841 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
5843 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
5845 /* Otherwise, that's a simple copy */
5848 RtlCopyUnicodeString(CanonicalName
, FileName
);
5859 RxFreeCanonicalNameBuffer(
5860 PRX_CONTEXT Context
)
5862 /* These two buffers are always the same */
5863 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
5865 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
5867 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
5868 Context
->Create
.CanonicalNameBuffer
= NULL
;
5869 Context
->AlsoCanonicalNameBuffer
= NULL
;
5872 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
5876 RxFsdCommonDispatch(
5877 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
5878 UCHAR MajorFunction
,
5879 PIO_STACK_LOCATION Stack
,
5880 PFILE_OBJECT FileObject
,
5882 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
5886 PRX_CONTEXT Context
;
5887 UCHAR MinorFunction
;
5888 PFILE_OBJECT StackFileObject
;
5889 PRX_FSD_DISPATCH DispatchFunc
;
5890 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5891 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
5893 Status
= STATUS_SUCCESS
;
5895 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
5897 FsRtlEnterFileSystem();
5899 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
5905 PostRequest
= FALSE
;
5906 SetCancelRoutine
= TRUE
;
5907 MinorFunction
= Stack
->MinorFunction
;
5909 switch (MajorFunction
)
5911 case IRP_MJ_FILE_SYSTEM_CONTROL
:
5912 if (FileObject
!= NULL
)
5914 CanWait
= IoIsOperationSynchronous(Irp
);
5924 case IRP_MJ_QUERY_INFORMATION
:
5925 case IRP_MJ_SET_INFORMATION
:
5926 case IRP_MJ_QUERY_EA
:
5928 case IRP_MJ_FLUSH_BUFFERS
:
5929 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
5930 case IRP_MJ_SET_VOLUME_INFORMATION
:
5931 case IRP_MJ_DIRECTORY_CONTROL
:
5932 case IRP_MJ_DEVICE_CONTROL
:
5933 case IRP_MJ_LOCK_CONTROL
:
5934 case IRP_MJ_QUERY_SECURITY
:
5935 case IRP_MJ_SET_SECURITY
:
5936 CanWait
= IoIsOperationSynchronous(Irp
);
5940 case IRP_MJ_CLEANUP
:
5942 SetCancelRoutine
= FALSE
;
5949 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
5950 /* Should we stop it right now, or mini-rdr deserves to know? */
5951 PassToDriver
= TRUE
;
5952 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
5954 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
5956 PassToDriver
= FALSE
;
5957 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
5958 DPRINT1("Not started!\n");
5963 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
5965 PassToDriver
= FALSE
;
5966 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
5967 DPRINT1("Not started!\n");
5970 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
5972 StackFileObject
= Stack
->FileObject
;
5973 /* Make sure we don't deal with orphaned stuff */
5974 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
5976 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
5977 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
5978 StackFileObject
->FsContext
!= &RxDeviceFCB
)
5983 Fcb
= StackFileObject
->FsContext
;
5984 Fobx
= StackFileObject
->FsContext2
;
5986 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
5987 BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5991 PassToDriver
= TRUE
;
5995 PassToDriver
= FALSE
;
5996 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
5997 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
6003 /* Did we receive a close request whereas we're stopping? */
6004 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
6008 Fcb
= StackFileObject
->FsContext
;
6010 DPRINT1("Close received after stop\n");
6011 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6012 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
6014 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
6017 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6018 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
6022 /* Should we stop the whole thing now? */
6025 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
6027 IoMarkIrpPending(Irp
);
6028 Irp
->IoStatus
.Status
= Status
;
6029 Irp
->IoStatus
.Information
= 0;
6030 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6031 Status
= STATUS_PENDING
;
6035 Irp
->IoStatus
.Status
= Status
;
6036 Irp
->IoStatus
.Information
= 0;
6037 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6043 /* No? Allocate a context to deal with the mini-rdr */
6044 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
6045 if (Context
== NULL
)
6047 Status
= STATUS_INSUFFICIENT_RESOURCES
;
6048 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
6052 /* Set cancel routine if required */
6053 if (SetCancelRoutine
)
6055 IoAcquireCancelSpinLock(&OldIrql
);
6056 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
6060 IoAcquireCancelSpinLock(&OldIrql
);
6061 IoSetCancelRoutine(Irp
, NULL
);
6063 IoReleaseCancelSpinLock(OldIrql
);
6065 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6067 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6068 Irp
->IoStatus
.Information
= 0;
6069 /* Get the dispatch routine */
6070 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
6072 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
6074 /* Handle the complete MDL case */
6075 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
6077 DispatchFunc
= RxCompleteMdl
;
6081 /* Do we have to post request? */
6082 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
6088 /* Our read function needs stack, make sure we won't overflow,
6089 * otherwise, post the request
6091 if (MajorFunction
== IRP_MJ_READ
)
6093 if (IoGetRemainingStackSize() < 0xE00)
6095 Context
->PendingReturned
= TRUE
;
6096 Status
= RxPostStackOverflowRead(Context
);
6097 if (Status
!= STATUS_PENDING
)
6099 Context
->PendingReturned
= FALSE
;
6100 RxCompleteAsynchronousRequest(Context
, Status
);
6110 Context
->ResumeRoutine
= DispatchFunc
;
6111 /* There's a dispatch routine? Time to dispatch! */
6112 if (DispatchFunc
!= NULL
)
6114 Context
->PendingReturned
= TRUE
;
6117 Status
= RxFsdPostRequest(Context
);
6121 /* Retry as long as we have */
6124 Status
= DispatchFunc(Context
);
6126 while (Status
== STATUS_RETRY
);
6128 if (Status
== STATUS_PENDING
)
6133 /* Sanity check: did someone mess with our context? */
6134 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
6135 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
6137 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
6138 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
6139 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
6140 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
6141 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
6143 Context
->PendingReturned
= FALSE
;
6144 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
6149 Status
= STATUS_NOT_IMPLEMENTED
;
6156 RxUnwindTopLevelIrp(&TopLevelContext
);
6159 FsRtlExitFileSystem();
6163 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
6173 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
6177 PIO_STACK_LOCATION Stack
;
6178 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
6182 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
6184 Stack
= IoGetCurrentIrpStackLocation(Irp
);
6186 /* Dispatch easy case */
6187 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
6189 return RxSystemControl(RxDeviceObject
, Irp
);
6192 /* Bail out broken cases */
6193 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
6194 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
6196 IoMarkIrpPending(Irp
);
6197 Irp
->IoStatus
.Information
= 0;
6198 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
6199 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6200 return STATUS_PENDING
;
6203 /* Immediately handle create */
6204 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
6206 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6209 /* If not a creation, we must have at least a FO with a FCB */
6210 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
6212 IoMarkIrpPending(Irp
);
6213 Irp
->IoStatus
.Information
= 0;
6214 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6215 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6216 return STATUS_PENDING
;
6219 /* Set the dispatch vector if required */
6220 Fcb
= Stack
->FileObject
->FsContext
;
6221 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
6223 DispatchVector
= &RxFsdDispatchVector
[0];
6227 DispatchVector
= Fcb
->PrivateDispatchVector
;
6230 /* Device cannot accept such requests */
6231 if (RxDeviceObject
== RxFileSystemDeviceObject
)
6233 IoMarkIrpPending(Irp
);
6234 Irp
->IoStatus
.Information
= 0;
6235 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6236 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6237 return STATUS_PENDING
;
6240 /* Dispatch for real! */
6241 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6249 IN PRX_CONTEXT RxContext
)
6251 /* Initialize posting if required */
6252 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
6254 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
6257 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6258 RxContext
->MinorFunction
, RxContext
,
6259 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6260 RxContext
->SerialNumber
);
6262 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
6263 return STATUS_PENDING
;
6275 WORK_QUEUE_TYPE Queue
;
6276 PRDBSS_DEVICE_OBJECT VolumeDO
;
6277 PRX_CONTEXT RxContext
, EntryContext
;
6281 RxContext
= Context
;
6282 EntryContext
= Context
;
6283 /* Save IRQL at entry for later checking */
6284 EntryIrql
= KeGetCurrentIrql();
6286 /* No FO, deal with device */
6287 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6289 VolumeDO
= RxFileSystemDeviceObject
;
6296 /* Which queue to used for delayed? */
6297 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6299 Queue
= DelayedWorkQueue
;
6303 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6304 Queue
= CriticalWorkQueue
;
6311 BOOLEAN RecursiveCall
;
6312 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6314 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6315 ASSERT(!RxContext
->PostRequest
);
6317 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6318 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6320 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext
->MinorFunction
,
6321 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6322 RxContext
->SerialNumber
);
6324 Irp
= RxContext
->CurrentIrp
;
6326 FsRtlEnterFileSystem();
6328 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6329 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6330 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6331 RxContext
->RxDeviceObject
, TRUE
);
6333 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6335 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6337 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6338 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6341 /* Call the resume routine */
6346 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6348 Status
= RxContext
->ResumeRoutine(RxContext
);
6349 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6351 if (Status
!= STATUS_RETRY
)
6353 Status
= RxCompleteRequest(RxContext
, Status
);
6357 while (Status
== STATUS_RETRY
);
6359 RxUnwindTopLevelIrp(&TopLevelContext
);
6360 FsRtlExitFileSystem();
6362 if (VolumeDO
!= NULL
)
6364 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6370 } while (RxContext
!= NULL
);
6372 /* Did we mess with IRQL? */
6373 if (KeGetCurrentIrql() >= APC_LEVEL
)
6375 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6383 RxGetNetworkProviderPriority(
6384 PUNICODE_STRING DeviceName
)
6395 RxGetRegistryParameters(
6396 IN PUNICODE_STRING RegistryPath
)
6400 UCHAR Buffer
[0x400];
6401 HANDLE DriverHandle
, KeyHandle
;
6402 UNICODE_STRING KeyName
, OutString
;
6403 OBJECT_ATTRIBUTES ObjectAttributes
;
6407 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6408 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6409 if (!NT_SUCCESS(Status
))
6414 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6415 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6416 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6417 if (NT_SUCCESS(Status
))
6419 /* The only parameter we deal with is InitialDebugString */
6420 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6421 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6426 Read
= OutString
.Buffer
;
6427 Write
= (PSTR
)OutString
.Buffer
;
6428 for (i
= 0; i
< OutString
.Length
; ++i
)
6436 /* Which is a string we'll just write out */
6437 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6438 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6444 ZwClose(DriverHandle
);
6452 IN PIO_STACK_LOCATION IrpSp
)
6455 PACCESS_TOKEN Token
;
6456 PIO_SECURITY_CONTEXT SecurityContext
;
6460 /* If that's not a prefix claim, not an open request, session id will be 0 */
6461 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6463 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6468 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6472 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6475 /* Query the session id */
6476 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6477 SeQuerySessionIdToken(Token
, &SessionId
);
6487 RxGetStringRegistryParameter(
6488 IN HANDLE KeyHandle
,
6490 OUT PUNICODE_STRING OutString
,
6492 IN ULONG BufferLength
,
6493 IN BOOLEAN LogFailure
)
6497 UNICODE_STRING KeyString
;
6501 RtlInitUnicodeString(&KeyString
, KeyName
);
6502 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6503 OutString
->Length
= 0;
6504 OutString
->Buffer
= 0;
6505 if (!NT_SUCCESS(Status
))
6509 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6515 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6516 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6517 OutString
->MaximumLength
= OutString
->Length
;
6519 return STATUS_SUCCESS
;
6525 PRDBSS_DEVICE_OBJECT
6526 RxGetTopDeviceObjectIfRdbssIrp(
6530 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6532 TopLevelIrp
= IoGetTopLevelIrp();
6533 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6535 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6545 RxGetTopIrpIfRdbssIrp(
6549 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6551 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6552 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6554 Irp
= TopLevel
->Irp
;
6565 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6568 PACCESS_TOKEN Token
;
6572 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6573 SeQueryAuthenticationIdToken(Token
, &Luid
);
6580 RxIndicateChangeOfBufferingStateForSrvOpen(
6581 PMRX_SRV_CALL SrvCall
,
6582 PMRX_SRV_OPEN SrvOpen
,
6591 RxInitializeDebugSupport(
6602 RxInitializeDispatchVectors(
6603 PDRIVER_OBJECT DriverObject
)
6609 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6611 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6614 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6615 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6616 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6618 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6619 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6620 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6621 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6622 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6623 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6624 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6625 RxFastIoDispatch
.FastIoLock
= NULL
;
6626 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6627 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6628 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6629 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6630 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6631 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6632 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6633 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6635 RxInitializeTopLevelIrpPackage();
6637 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6638 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6639 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6640 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6642 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6643 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6644 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6645 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6654 return STATUS_NOT_IMPLEMENTED
;
6661 RxInitializeMinirdrDispatchTable(
6662 IN PDRIVER_OBJECT DriverObject
)
6672 RxInitializeRegistrationStructures(
6677 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6678 RxData
.NumberOfMinirdrsRegistered
= 0;
6679 RxData
.NumberOfMinirdrsStarted
= 0;
6680 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6682 return STATUS_SUCCESS
;
6690 RxInitializeTopLevelIrpPackage(
6693 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6694 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6700 PDRIVER_OBJECT DriverObject
,
6710 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6711 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6714 PLIST_ENTRY NextEntry
;
6715 BOOLEAN Found
= FALSE
;
6716 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6718 /* Browse all the allocated TLC to find ours */
6719 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6720 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6721 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6722 NextEntry
= NextEntry
->Flink
)
6724 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6725 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6726 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6729 if (ListContext
== TopLevelContext
)
6735 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6749 /* No associated SRV_OPEN, it's OK to purge */
6750 if (IsListEmpty(&Fcb
->SrvOpenList
))
6755 /* Only allow to purge if all the associated SRV_OPEN
6756 * - have no outstanding opens ongoing
6757 * - have only read attribute set
6759 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6760 Entry
!= &Fcb
->SrvOpenList
;
6761 Entry
= Entry
->Flink
)
6765 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6767 /* Failing previous needs, don't allow purge */
6768 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6769 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6775 /* All correct, allow purge */
6783 RxIsThisAnRdbssTopLevelContext(
6784 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6786 ULONG_PTR StackTop
, StackBottom
;
6788 /* Bail out for flags */
6789 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6794 /* Is our provided TLC allocated on stack? */
6795 IoGetStackLimits(&StackTop
, &StackBottom
);
6796 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6797 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6799 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6800 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6808 /* No, use the helper function */
6809 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6816 RxIsThisTheTopLevelIrp(
6821 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6822 TopLevelIrp
= IoGetTopLevelIrp();
6823 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6825 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
6828 return (TopLevelIrp
== Irp
);
6833 RxLockOperationCompletion(
6838 return STATUS_NOT_IMPLEMENTED
;
6847 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6848 IN PUNICODE_STRING OriginatorId
,
6853 PUNICODE_STRING Originator
= OriginatorId
;
6854 LARGE_INTEGER LargeLine
;
6856 /* Set optional parameters */
6857 LargeLine
.QuadPart
= Line
;
6858 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
6860 Originator
= (PUNICODE_STRING
)&unknownId
;
6864 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
6869 RxLogEventWithAnnotation(
6870 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6873 IN PVOID DataBuffer
,
6874 IN USHORT DataBufferLength
,
6875 IN PUNICODE_STRING Annotation
,
6876 IN ULONG AnnotationCount
)
6884 PRX_CONTEXT RxContext
)
6887 return STATUS_NOT_IMPLEMENTED
;
6895 RxLowIoIoCtlShellCompletion(
6896 PRX_CONTEXT RxContext
)
6903 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
6905 Irp
= RxContext
->CurrentIrp
;
6906 Status
= RxContext
->IoStatusBlock
.Status
;
6908 /* Set information and status */
6909 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
6911 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6914 Irp
->IoStatus
.Status
= Status
;
6920 RxLowIoLockControlShell(
6921 IN PRX_CONTEXT RxContext
)
6924 return STATUS_NOT_IMPLEMENTED
;
6932 RxLowIoNotifyChangeDirectoryCompletion(
6933 PRX_CONTEXT RxContext
)
6937 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
6939 /* Just copy back the IO_STATUS to the IRP */
6940 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
6941 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
6943 return RxContext
->IoStatusBlock
.Status
;
6951 PRX_CONTEXT RxContext
)
6958 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
6960 Fcb
= (PFCB
)RxContext
->pFcb
;
6961 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
6963 return STATUS_MORE_PROCESSING_REQUIRED
;
6966 /* Always update stats for disks */
6967 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
6969 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
6972 /* And forward the read to the mini-rdr */
6973 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
6974 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
6981 RxLowIoReadShellCompletion(
6982 PRX_CONTEXT RxContext
)
6987 BOOLEAN PagingIo
, IsPipe
;
6988 PIO_STACK_LOCATION Stack
;
6989 PLOWIO_CONTEXT LowIoContext
;
6993 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
6995 Status
= RxContext
->IoStatusBlock
.Status
;
6996 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
6998 Irp
= RxContext
->CurrentIrp
;
6999 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7001 /* Set IRP information from the RX_CONTEXT status block */
7002 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7004 /* Fixup status for paging file if nothing was read */
7007 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
7009 Status
= STATUS_END_OF_FILE
;
7013 LowIoContext
= &RxContext
->LowIoContext
;
7014 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7016 /* Check broken cases that should never happen */
7017 Fcb
= (PFCB
)RxContext
->pFcb
;
7018 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
7020 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
7023 return STATUS_RETRY
;
7026 else if (Status
== STATUS_SUCCESS
)
7028 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
7030 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
7031 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
7037 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7043 /* Readahead should go through Cc and not finish here */
7044 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
7046 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7047 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7052 Stack
= RxContext
->CurrentIrpSp
;
7053 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
7054 /* Release lock if required */
7057 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7061 /* Set FastIo if read was a success */
7062 if (NT_SUCCESS(Status
) && !IsPipe
)
7064 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
7067 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7069 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
7073 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7082 /* Final sanity checks */
7083 ASSERT(Status
!= STATUS_RETRY
);
7084 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
7085 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
7095 IN PRX_CONTEXT RxContext
)
7102 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
7104 Fcb
= (PFCB
)RxContext
->pFcb
;
7106 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7107 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7109 /* Always update stats for disks */
7110 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7112 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7115 /* And forward the write to the mini-rdr */
7116 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
7117 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
7124 RxLowIoWriteShellCompletion(
7125 PRX_CONTEXT RxContext
)
7131 PLOWIO_CONTEXT LowIoContext
;
7135 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
7137 Status
= RxContext
->IoStatusBlock
.Status
;
7138 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7140 Irp
= RxContext
->CurrentIrp
;
7142 /* Set IRP information from the RX_CONTEXT status block */
7143 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7145 LowIoContext
= &RxContext
->LowIoContext
;
7146 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7148 /* Perform a few sanity checks */
7149 Fcb
= (PFCB
)RxContext
->pFcb
;
7150 if (Status
== STATUS_SUCCESS
)
7152 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
7154 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7155 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7158 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
7161 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7162 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
7164 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
7167 /* In case of async call, perform last bits not done in RxCommonWrite */
7168 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7170 PFILE_OBJECT FileObject
;
7171 PIO_STACK_LOCATION Stack
;
7173 /* We only succeed if we wrote what was asked for */
7174 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7176 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
7179 /* If write succeed, ,also update FILE_OBJECT flags */
7180 Stack
= RxContext
->CurrentIrpSp
;
7181 FileObject
= Stack
->FileObject
;
7184 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
7187 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
7189 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
7192 /* If VDL was extended, fix attributes */
7193 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
7195 LONGLONG LastOffset
, FileSize
;
7197 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
7198 Irp
->IoStatus
.Information
;
7199 RxGetFileSizeWithLock(Fcb
, &FileSize
);
7201 if (FileSize
< LastOffset
)
7203 LastOffset
= FileSize
;
7206 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
7209 /* One less outstanding write */
7210 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7212 PNON_PAGED_FCB NonPagedFcb
;
7214 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
7215 if (NonPagedFcb
!= NULL
)
7217 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
7218 -1, &RxStrucSupSpinLock
) == 1)
7220 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
7225 /* Release paging resource if acquired */
7226 if (RxContext
->FcbPagingIoResourceAcquired
)
7228 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7231 /* Resume blocked operations for pipes */
7232 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7234 RxResumeBlockedOperations_Serially(RxContext
,
7235 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
7239 /* And release FCB only for files */
7240 if (RxContext
->FcbResourceAcquired
)
7242 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7246 /* Final sanity checks */
7247 ASSERT(Status
!= STATUS_RETRY
);
7248 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
7249 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
7251 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7264 RxNotifyChangeDirectory(
7265 PRX_CONTEXT RxContext
)
7269 PIO_STACK_LOCATION Stack
;
7273 /* The IRP can abviously wait */
7274 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
7276 /* Initialize its lowio */
7277 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
7281 /* Lock user buffer */
7282 Stack
= RxContext
->CurrentIrpSp
;
7283 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
7285 /* Copy parameters from IO_STACK */
7286 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
7287 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7288 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7290 /* If we have an associated MDL */
7291 Irp
= RxContext
->CurrentIrp
;
7292 if (Irp
->MdlAddress
!= NULL
)
7294 /* Then, call mini-rdr */
7295 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7296 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7298 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7302 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7307 Status
= STATUS_INVALID_PARAMETER
;
7320 RxPostStackOverflowRead (
7321 IN PRX_CONTEXT RxContext
)
7326 return STATUS_NOT_IMPLEMENTED
;
7333 RxpPrepareCreateContextForReuse(
7334 PRX_CONTEXT RxContext
)
7336 /* Reuse can only happen for open operations (STATUS_RETRY) */
7337 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7339 /* Release the FCB if it was acquired */
7340 if (RxContext
->Create
.FcbAcquired
)
7342 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7343 RxContext
->Create
.FcbAcquired
= FALSE
;
7346 /* Free the canonical name */
7347 RxFreeCanonicalNameBuffer(RxContext
);
7349 /* If we have a VNetRoot associated */
7350 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7352 /* Remove our link and thus, dereference the VNetRoot */
7353 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7354 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7356 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7357 RxContext
->Create
.pVNetRoot
= NULL
;
7359 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7362 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7369 RxpQueryInfoMiniRdr(
7370 PRX_CONTEXT RxContext
,
7371 FILE_INFORMATION_CLASS FileInfoClass
,
7377 Fcb
= (PFCB
)RxContext
->pFcb
;
7379 /* Set the RX_CONTEXT */
7380 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7381 RxContext
->Info
.Buffer
= Buffer
;
7384 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7394 IN PRX_CONTEXT RxContext
)
7398 NET_ROOT_TYPE NetRootType
;
7399 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7403 Irp
= RxContext
->CurrentIrp
;
7405 /* This has to come from MUP */
7406 if (Irp
->RequestorMode
== UserMode
)
7408 return STATUS_INVALID_DEVICE_REQUEST
;
7411 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7413 PQUERY_PATH_REQUEST QueryRequest
;
7415 /* Get parameters */
7416 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7418 /* Don't overflow allocation */
7419 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7421 return STATUS_INVALID_DEVICE_REQUEST
;
7424 /* Forcefully rewrite IRP MJ */
7425 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7427 /* Fake canon name */
7428 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7429 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7431 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7435 /* Copy the prefix to look for */
7436 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7437 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7438 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7440 /* Zero the create parameters */
7441 RtlZeroMemory(&RxContext
->Create
.NtCreateParameters
,
7442 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7443 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7444 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7448 /* If not devcontrol, it comes from open, name was already copied */
7449 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7450 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7453 /* Canonilize name */
7454 NetRootType
= NET_ROOT_WILD
;
7455 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7456 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7457 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7458 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7459 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7460 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7461 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7462 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7463 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7464 if (NT_SUCCESS(Status
))
7466 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7468 if (Status
== STATUS_PENDING
)
7473 if (NT_SUCCESS(Status
))
7475 PQUERY_PATH_RESPONSE QueryResponse
;
7477 /* We accept the length that was canon (minus netroot) */
7478 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7479 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7483 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7484 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7486 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7488 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7491 RxpPrepareCreateContextForReuse(RxContext
);
7493 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7504 RxPrepareToReparseSymbolicLink(
7505 PRX_CONTEXT RxContext
,
7506 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7507 PUNICODE_STRING NewPath
,
7508 BOOLEAN NewPathIsAbsolute
,
7509 PBOOLEAN ReparseRequired
)
7513 PFILE_OBJECT FileObject
;
7515 /* Assume no reparse is required first */
7516 *ReparseRequired
= FALSE
;
7518 /* Only supported for IRP_MJ_CREATE */
7519 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
)
7521 return STATUS_INVALID_PARAMETER
;
7524 /* If symbolic link is not embedded, and DELETE is specified, fail */
7525 if (!SymbolicLinkEmbeddedInOldPath
)
7527 /* Excepted if DELETE is the only flag specified, then, open has to succeed
7528 * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7530 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
) &&
7531 BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, ~DELETE
))
7533 return STATUS_ACCESS_DENIED
;
7537 /* At that point, assume reparse will be required */
7538 *ReparseRequired
= TRUE
;
7540 /* If new path isn't absolute, it's up to us to make it absolute */
7541 if (!NewPathIsAbsolute
)
7543 /* The prefix will be \Device\Mup */
7544 NewLength
= NewPath
->Length
+ (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
));
7545 NewBuffer
= ExAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, NewLength
,
7547 if (NewBuffer
== NULL
)
7549 return STATUS_INSUFFICIENT_RESOURCES
;
7552 /* Copy data for the new path */
7553 RtlMoveMemory(NewBuffer
, L
"\\Device\\Mup", (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
)));
7554 RtlMoveMemory(Add2Ptr(NewBuffer
, (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
))),
7555 NewPath
->Buffer
, NewPath
->Length
);
7557 /* Otherwise, use caller path as it */
7560 NewLength
= NewPath
->Length
;
7561 NewBuffer
= NewPath
->Buffer
;
7564 /* Get the FILE_OBJECT we'll modify */
7565 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
7567 /* Free old path first */
7568 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
7569 /* And setup new one */
7570 FileObject
->FileName
.Length
= NewLength
;
7571 FileObject
->FileName
.MaximumLength
= NewLength
;
7572 FileObject
->FileName
.Buffer
= NewBuffer
;
7574 /* And set reparse flag */
7575 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
);
7578 return STATUS_SUCCESS
;
7589 LOCK_OPERATION Lock
;
7590 PIO_STACK_LOCATION Stack
;
7591 PRX_CONTEXT RxContext
= Context
;
7593 /* NULL IRP is no option */
7599 /* Check whether preparation was really needed */
7600 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7604 /* Mark the context as prepared */
7605 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7607 /* Just lock the user buffer, with the correct length, depending on the MJ */
7608 Lock
= IoReadAccess
;
7609 Stack
= RxContext
->CurrentIrpSp
;
7610 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7612 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7614 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7616 Lock
= IoWriteAccess
;
7618 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7623 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7624 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7626 Lock
= IoWriteAccess
;
7627 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7629 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7631 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7635 /* As it will be posted (async), mark the IRP pending */
7636 IoMarkIrpPending(Irp
);
7644 PRX_CONTEXT RxContext
,
7645 FILE_INFORMATION_CLASS Class
)
7650 /* Initialize parameters in RX_CONTEXT */
7651 RxContext
->Info
.FileInformationClass
= Class
;
7652 RxContext
->Info
.Buffer
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
7653 RxContext
->Info
.Length
= RxContext
->CurrentIrpSp
->Parameters
.SetFile
.Length
;
7655 /* And call mini-rdr */
7656 Fcb
= (PFCB
)RxContext
->pFcb
;
7657 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
7664 RxpUnregisterMinirdr(
7665 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7676 PRX_CONTEXT LocalContext
)
7683 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7685 /* And force close */
7686 RxReleaseFcb(NULL
, Fcb
);
7687 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7688 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7689 ASSERT(Status
== STATUS_SUCCESS
);
7693 RxQueryAlternateNameInfo(
7694 PRX_CONTEXT RxContext
,
7695 PFILE_NAME_INFORMATION AltNameInfo
)
7698 return STATUS_NOT_IMPLEMENTED
;
7706 PRX_CONTEXT RxContext
,
7707 PFILE_BASIC_INFORMATION BasicInfo
)
7711 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7713 /* Simply zero and forward to mini-rdr */
7714 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7715 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7719 RxQueryCompressedInfo(
7720 PRX_CONTEXT RxContext
,
7721 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7724 return STATUS_NOT_IMPLEMENTED
;
7732 PRX_CONTEXT RxContext
)
7739 BOOLEAN LockNotGranted
;
7740 ULONG Length
, FileIndex
;
7741 PUNICODE_STRING FileName
;
7742 PIO_STACK_LOCATION Stack
;
7743 FILE_INFORMATION_CLASS FileInfoClass
;
7747 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7749 /* Get parameters */
7750 Stack
= RxContext
->CurrentIrpSp
;
7751 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7752 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7753 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7754 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7755 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7756 FileName
, FileInfoClass
);
7758 Irp
= RxContext
->CurrentIrp
;
7759 Flags
= Stack
->Flags
;
7760 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7761 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7763 if (FileName
!= NULL
)
7765 DPRINT("FileName: %wZ\n", FileName
);
7768 /* No FOBX: not a standard file/directory */
7769 Fobx
= (PFOBX
)RxContext
->pFobx
;
7772 return STATUS_OBJECT_NAME_INVALID
;
7775 /* We can only deal with a disk */
7776 Fcb
= (PFCB
)RxContext
->pFcb
;
7777 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7779 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7780 return STATUS_INVALID_DEVICE_REQUEST
;
7783 /* Setup RX_CONTEXT related fields */
7784 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7785 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7786 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7787 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7788 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7790 /* We don't support (yet?) a specific index being set */
7791 if (RxContext
->QueryDirectory
.IndexSpecified
)
7793 return STATUS_NOT_IMPLEMENTED
;
7796 /* Try to lock FCB */
7797 LockNotGranted
= TRUE
;
7798 if (RxContext
->QueryDirectory
.InitialQuery
)
7800 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7801 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7803 if (!NT_SUCCESS(Status
))
7808 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7810 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7811 RxConvertToSharedFcb(RxContext
, Fcb
);
7814 LockNotGranted
= FALSE
;
7819 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7820 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7822 if (!NT_SUCCESS(Status
))
7827 LockNotGranted
= FALSE
;
7831 /* If it failed, post request */
7834 return RxFsdPostRequest(RxContext
);
7837 /* This cannot be done on a orphaned directory */
7838 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
7840 RxReleaseFcb(RxContext
, Fcb
);
7841 return STATUS_FILE_CLOSED
;
7847 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
7849 RxContext
->QueryDirectory
.FileIndex
= 0;
7852 /* Assume success */
7853 Status
= STATUS_SUCCESS
;
7854 /* If initial query, prepare FOBX */
7855 if (RxContext
->QueryDirectory
.InitialQuery
)
7857 /* We cannot have a template already! */
7858 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
7860 /* If we have a file name and a correct one, duplicate it in the FOBX */
7861 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
7862 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
7863 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
7864 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
7866 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
7868 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
7869 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7871 /* UNICODE_STRING; length has to be even */
7872 if ((FileName
->Length
& 1) != 0)
7874 Status
= STATUS_INVALID_PARAMETER
;
7875 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
7879 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
7880 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
7881 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
7883 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
7888 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7891 /* No name specified, or a match all wildcard? Match everything */
7894 Fobx
->ContainsWildCards
= TRUE
;
7896 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
7897 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
7898 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
7900 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7903 /* No need for exclusive any longer */
7904 if (NT_SUCCESS(Status
))
7906 RxConvertToSharedFcb(RxContext
, Fcb
);
7910 /* Lock user buffer and forward to mini-rdr */
7911 if (NT_SUCCESS(Status
))
7913 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
7914 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7915 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
7916 RxContext
->Info
.Length
= Length
;
7918 if (RxContext
->Info
.Buffer
!= NULL
)
7920 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
7923 /* Post if mini-rdr asks to */
7924 if (RxContext
->PostRequest
)
7926 RxFsdPostRequest(RxContext
);
7930 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
7936 RxReleaseFcb(RxContext
, Fcb
);
7945 PRX_CONTEXT RxContext
,
7946 PFILE_EA_INFORMATION EaInfo
)
7949 return STATUS_NOT_IMPLEMENTED
;
7953 RxQueryInternalInfo(
7954 PRX_CONTEXT RxContext
,
7955 PFILE_INTERNAL_INFORMATION InternalInfo
)
7958 return STATUS_NOT_IMPLEMENTED
;
7963 PRX_CONTEXT RxContext
,
7964 PFILE_NAME_INFORMATION NameInfo
)
7967 return STATUS_NOT_IMPLEMENTED
;
7972 PRX_CONTEXT RxContext
,
7973 PFILE_PIPE_INFORMATION PipeInfo
)
7976 return STATUS_NOT_IMPLEMENTED
;
7980 RxQueryPositionInfo(
7981 PRX_CONTEXT RxContext
,
7982 PFILE_POSITION_INFORMATION PositionInfo
)
7985 return STATUS_NOT_IMPLEMENTED
;
7992 RxQueryStandardInfo(
7993 PRX_CONTEXT RxContext
,
7994 PFILE_STANDARD_INFORMATION StandardInfo
)
8002 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
8004 /* Zero output buffer */
8005 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
8007 Fcb
= (PFCB
)RxContext
->pFcb
;
8008 Fobx
= (PFOBX
)RxContext
->pFobx
;
8009 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8010 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
8011 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8013 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8016 /* Otherwise, fill what we can already */
8017 Status
= STATUS_SUCCESS
;
8018 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
8019 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8020 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
8021 if (StandardInfo
->NumberOfLinks
== 0)
8023 StandardInfo
->NumberOfLinks
= 1;
8026 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
8028 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
8029 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
8032 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8033 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
8035 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8039 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
8050 RxReadRegistryParameters(
8057 UNICODE_STRING KeyName
, ParamName
;
8058 OBJECT_ATTRIBUTES ObjectAttributes
;
8059 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
8063 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8064 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
8065 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
8066 if (!NT_SUCCESS(Status
))
8071 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
8072 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
8073 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8074 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8076 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
8079 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
8080 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8081 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8083 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
8085 if (Granularity
> 16)
8090 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
8093 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
8094 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8095 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8097 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
8109 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
8110 IN OUT PDRIVER_OBJECT DriverObject
,
8111 IN PMINIRDR_DISPATCH MrdrDispatch
,
8113 IN PUNICODE_STRING DeviceName
,
8114 IN ULONG DeviceExtensionSize
,
8115 IN DEVICE_TYPE DeviceType
,
8116 IN ULONG DeviceCharacteristics
)
8119 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
8125 return STATUS_INVALID_PARAMETER
;
8128 /* Create device object with provided parameters */
8129 Status
= IoCreateDevice(DriverObject
,
8130 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
8133 DeviceCharacteristics
,
8135 (PDEVICE_OBJECT
*)&RDBSSDevice
);
8136 if (!NT_SUCCESS(Status
))
8141 if (!RxData
.DriverObject
)
8143 return STATUS_UNSUCCESSFUL
;
8146 /* Initialize our DO extension */
8147 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
8148 ++RxFileSystemDeviceObject
->ReferenceCount
;
8149 *DeviceObject
= RDBSSDevice
;
8150 RDBSSDevice
->RdbssExports
= &RxExports
;
8151 RDBSSDevice
->Dispatch
= MrdrDispatch
;
8152 RDBSSDevice
->RegistrationControls
= Controls
;
8153 RDBSSDevice
->DeviceName
= *DeviceName
;
8154 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
8155 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
8156 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
8157 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
8158 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
8159 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
8160 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
8162 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
8164 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
8165 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
8166 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
8168 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8169 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
8171 RxInitializeMinirdrDispatchTable(DriverObject
);
8174 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8175 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
8177 LARGE_INTEGER ScavengerTimeLimit
;
8179 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
8180 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
8181 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
8182 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
8183 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
8184 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
8187 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
8189 return STATUS_SUCCESS
;
8196 RxRemoveFromTopLevelIrpAllocatedContextsList(
8197 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8201 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8202 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8203 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8205 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
8206 RemoveEntryList(&TopLevelContext
->ListEntry
);
8207 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
8214 RxRemoveOverflowEntry(
8215 PRDBSS_DEVICE_OBJECT DeviceObject
,
8216 WORK_QUEUE_TYPE Queue
)
8219 PRX_CONTEXT Context
;
8221 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
8222 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
8224 /* No entries left, nothing to return */
8225 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
8232 /* Decrement count */
8233 --DeviceObject
->OverflowQueueCount
[Queue
];
8236 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
8237 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
8238 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
8239 Context
->OverflowListEntry
.Flink
= NULL
;
8241 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
8251 RxRemoveShareAccess(
8252 _Inout_ PFILE_OBJECT FileObject
,
8253 _Inout_ PSHARE_ACCESS ShareAccess
,
8255 _In_ PSZ wherelogtag
)
8259 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8260 IoRemoveShareAccess(FileObject
, ShareAccess
);
8261 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8269 RxRemoveShareAccessPerSrvOpens(
8270 IN OUT PSRV_OPEN SrvOpen
)
8272 ACCESS_MASK DesiredAccess
;
8274 BOOLEAN WriteAccess
;
8275 BOOLEAN DeleteAccess
;
8279 /* Get access that were granted to SRV_OPEN */
8280 DesiredAccess
= SrvOpen
->DesiredAccess
;
8281 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
8282 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
8283 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
8285 /* If any, drop them */
8286 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
8289 BOOLEAN SharedWrite
;
8290 BOOLEAN SharedDelete
;
8291 ULONG DesiredShareAccess
;
8292 PSHARE_ACCESS ShareAccess
;
8294 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
8295 DesiredShareAccess
= SrvOpen
->ShareAccess
;
8297 ShareAccess
->Readers
-= ReadAccess
;
8298 ShareAccess
->Writers
-= WriteAccess
;
8299 ShareAccess
->Deleters
-= DeleteAccess
;
8301 ShareAccess
->OpenCount
--;
8303 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
8304 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
8305 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
8306 ShareAccess
->SharedRead
-= SharedRead
;
8307 ShareAccess
->SharedWrite
-= SharedWrite
;
8308 ShareAccess
->SharedDelete
-= SharedDelete
;
8313 RxSearchForCollapsibleOpen(
8314 PRX_CONTEXT RxContext
,
8315 ACCESS_MASK DesiredAccess
,
8320 PLIST_ENTRY ListEntry
;
8321 BOOLEAN ShouldTry
, Purged
, Scavenged
;
8325 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext
, DesiredAccess
, ShareAccess
);
8327 Fcb
= (PFCB
)RxContext
->pFcb
;
8329 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8330 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8332 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8334 RxScavengeRelatedFobxs(Fcb
);
8335 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8337 return STATUS_NOT_FOUND
;
8340 /* If basic open, ask the mini-rdr if we should try to collapse */
8341 if (RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN
||
8342 RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN_IF
)
8346 if (Fcb
->MRxDispatch
!= NULL
)
8348 ASSERT(RxContext
->pRelevantSrvOpen
== NULL
);
8349 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8351 ShouldTry
= NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
));
8359 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
))
8364 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8367 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
)))
8369 return STATUS_NOT_FOUND
;
8372 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8374 RxScavengeRelatedFobxs(Fcb
);
8375 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8377 return STATUS_NOT_FOUND
;
8380 /* Only collapse for matching NET_ROOT & disks */
8381 if (Fcb
->pNetRoot
!= RxContext
->Create
.pNetRoot
||
8382 Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
8384 return STATUS_NOT_FOUND
;
8389 Status
= STATUS_NOT_FOUND
;
8391 /* Browse all our SRV_OPEN to find the matching one */
8392 for (ListEntry
= Fcb
->SrvOpenList
.Flink
;
8393 ListEntry
!= &Fcb
->SrvOpenList
;
8394 ListEntry
= ListEntry
->Flink
)
8398 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
8399 /* Not the same VNET_ROOT, move to the next one */
8400 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8402 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8406 /* Is there a sharing violation? */
8407 if (SrvOpen
->DesiredAccess
!= DesiredAccess
|| SrvOpen
->ShareAccess
!= ShareAccess
||
8408 BooleanFlagOn(SrvOpen
->Flags
, (SRVOPEN_FLAG_CLOSED
| SRVOPEN_FLAG_COLLAPSING_DISABLED
| SRVOPEN_FLAG_FILE_DELETED
| SRVOPEN_FLAG_FILE_RENAMED
)))
8410 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8412 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8416 /* Check against the SRV_OPEN */
8417 Status
= RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
);
8418 if (!NT_SUCCESS(Status
))
8425 /* Don't allow collaspse for reparse point opening */
8426 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
^ SrvOpen
->CreateOptions
, FILE_OPEN_REPARSE_POINT
))
8430 Status
= STATUS_NOT_FOUND
;
8434 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8435 if (DisableByteRangeLockingOnReadOnlyFiles
|| !BooleanFlagOn(SrvOpen
->pFcb
->Attributes
, FILE_ATTRIBUTE_READONLY
))
8437 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
8439 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8440 if (NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
)))
8442 /* Is close delayed - great reuse*/
8443 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
8445 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen
);
8446 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
8447 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
8450 return STATUS_SUCCESS
;
8453 Status
= STATUS_NOT_FOUND
;
8458 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8459 if (ListEntry
== &Fcb
->SrvOpenList
)
8461 Status
= STATUS_NOT_FOUND
;
8464 /* Only required access: read attributes? Don't reuse */
8465 if ((DesiredAccess
& 0xFFEFFFFF) == FILE_READ_ATTRIBUTES
)
8467 return STATUS_NOT_FOUND
;
8470 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8473 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8475 RxScavengeRelatedFobxs(Fcb
);
8479 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8480 if (!Purged
&& RxIsOkToPurgeFcb(Fcb
))
8482 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8487 /* If sharing violation, keep track of it */
8488 if (Status
== STATUS_SHARING_VIOLATION
)
8490 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8493 DPRINT("Status: %x\n", Status
);
8498 RxSetAllocationInfo(
8499 PRX_CONTEXT RxContext
)
8502 return STATUS_NOT_IMPLEMENTED
;
8510 PRX_CONTEXT RxContext
)
8516 #define FILE_ATTRIBUTE_VOLUME 0x8
8517 #define VALID_FILE_ATTRIBUTES ( \
8518 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8519 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8520 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8521 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8522 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8523 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8524 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8525 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8527 /* First of all, call the mini-rdr */
8528 Status
= RxpSetInfoMiniRdr(RxContext
, FileBasicInformation
);
8529 /* If it succeed, perform last bits */
8530 if (NT_SUCCESS(Status
))
8535 PFILE_OBJECT FileObject
;
8536 ULONG Attributes
, CleanAttr
;
8537 PFILE_BASIC_INFORMATION BasicInfo
;
8539 Fcb
= (PFCB
)RxContext
->pFcb
;
8540 Fobx
= (PFOBX
)RxContext
->pFobx
;
8541 Irp
= RxContext
->CurrentIrp
;
8542 BasicInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
8543 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8545 /* If caller provided flags, handle the change */
8546 Attributes
= BasicInfo
->FileAttributes
;
8547 if (Attributes
!= 0)
8549 /* Clean our flags first, with only stuff we support */
8550 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
8552 CleanAttr
= (Attributes
& VALID_DIR_ATTRIBUTES
) | FILE_ATTRIBUTE_DIRECTORY
;
8556 CleanAttr
= Attributes
& VALID_FILE_ATTRIBUTES
;
8559 /* Handle the temporary mark (set/unset depending on caller) */
8560 if (BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_TEMPORARY
))
8562 SetFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8563 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8567 ClearFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8568 ClearFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8571 /* And set new attributes */
8572 Fcb
->Attributes
= CleanAttr
;
8575 /* If caller provided a creation time, set it */
8576 if (BasicInfo
->CreationTime
.QuadPart
!= 0LL)
8578 Fcb
->CreationTime
.QuadPart
= BasicInfo
->CreationTime
.QuadPart
;
8579 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_CREATION
);
8582 /* If caller provided a last access time, set it */
8583 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0LL)
8585 Fcb
->LastAccessTime
.QuadPart
= BasicInfo
->LastAccessTime
.QuadPart
;
8586 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
);
8589 /* If caller provided a last write time, set it */
8590 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0LL)
8592 Fcb
->LastWriteTime
.QuadPart
= BasicInfo
->LastWriteTime
.QuadPart
;
8593 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
8596 /* If caller provided a last change time, set it */
8597 if (BasicInfo
->ChangeTime
.QuadPart
!= 0LL)
8599 Fcb
->LastChangeTime
.QuadPart
= BasicInfo
->ChangeTime
.QuadPart
;
8600 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
8609 RxSetDispositionInfo(
8610 PRX_CONTEXT RxContext
)
8613 return STATUS_NOT_IMPLEMENTED
;
8618 PRX_CONTEXT RxContext
)
8621 return STATUS_NOT_IMPLEMENTED
;
8626 PRX_CONTEXT RxContext
)
8629 return STATUS_NOT_IMPLEMENTED
;
8634 PRX_CONTEXT RxContext
)
8637 return STATUS_NOT_IMPLEMENTED
;
8642 PRX_CONTEXT RxContext
)
8645 return STATUS_NOT_IMPLEMENTED
;
8654 _In_ ACCESS_MASK DesiredAccess
,
8655 _In_ ULONG DesiredShareAccess
,
8656 _Inout_ PFILE_OBJECT FileObject
,
8657 _Out_ PSHARE_ACCESS ShareAccess
,
8659 _In_ PSZ wherelogtag
)
8663 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8664 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8665 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8671 PRX_CONTEXT RxContext
)
8674 return STATUS_NOT_IMPLEMENTED
;
8681 RxSetupNetFileObject(
8682 PRX_CONTEXT RxContext
)
8686 PFILE_OBJECT FileObject
;
8687 PIO_STACK_LOCATION Stack
;
8691 /* Assert FOBX is FOBX or NULL */
8692 Fobx
= (PFOBX
)RxContext
->pFobx
;
8693 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
8695 Fcb
= (PFCB
)RxContext
->pFcb
;
8696 Stack
= RxContext
->CurrentIrpSp
;
8697 FileObject
= Stack
->FileObject
;
8698 /* If it's temporary mark FO as such */
8699 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
8700 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
8702 if (FileObject
== NULL
)
8707 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
8710 /* No FO, nothing to setup */
8711 if (FileObject
== NULL
)
8716 /* Assign FCB & CCB (FOBX) to FO */
8717 FileObject
->FsContext
= Fcb
;
8718 FileObject
->FsContext2
= Fobx
;
8721 ULONG_PTR StackTop
, StackBottom
;
8723 /* If FO is allocated on pool, keep track of it */
8724 IoGetStackLimits(&StackTop
, &StackBottom
);
8725 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
8727 Fobx
->AssociatedFileObject
= FileObject
;
8731 Fobx
->AssociatedFileObject
= NULL
;
8734 /* Make sure to mark FOBX if it's a DFS open */
8735 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
8737 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8741 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8745 /* Set Cc pointers */
8746 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
8748 /* Update access state */
8749 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
8751 PACCESS_STATE AccessState
;
8753 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
8754 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
8755 AccessState
->RemainingDesiredAccess
= 0;
8765 IN PRX_CONTEXT RxContext
,
8766 OUT PBOOLEAN PostToFsp
)
8769 BOOLEAN Wait
, AlreadyStarted
;
8770 PRDBSS_DEVICE_OBJECT DeviceObject
;
8772 /* If we've not been post, then, do it */
8773 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
8775 SECURITY_SUBJECT_CONTEXT SubjectContext
;
8777 SeCaptureSubjectContext(&SubjectContext
);
8778 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
8779 SeReleaseSubjectContext(&SubjectContext
);
8782 return STATUS_PENDING
;
8785 /* Acquire all the required locks */
8786 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8787 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
8790 return STATUS_PENDING
;
8793 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
8795 ExReleaseResourceLite(&RxData
.Resource
);
8797 return STATUS_PENDING
;
8800 AlreadyStarted
= FALSE
;
8801 DeviceObject
= RxContext
->RxDeviceObject
;
8804 /* MUP handle set, means already registered */
8805 if (DeviceObject
->MupHandle
!= NULL
)
8807 AlreadyStarted
= TRUE
;
8808 Status
= STATUS_REDIRECTOR_STARTED
;
8812 /* If we're asked to register to MUP, then do it */
8813 Status
= STATUS_SUCCESS
;
8814 if (DeviceObject
->RegisterUncProvider
)
8816 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
8817 &DeviceObject
->DeviceName
,
8818 DeviceObject
->RegisterMailSlotProvider
);
8820 if (!NT_SUCCESS(Status
))
8822 DeviceObject
->MupHandle
= NULL
;
8826 /* Register as file system */
8827 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
8828 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
8830 /* Inform mini-rdr it has to start */
8831 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
8832 if (NT_SUCCESS(Status
))
8834 ++DeviceObject
->StartStopContext
.Version
;
8835 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
8836 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
8838 Status
= RxInitializeMRxDispatcher(DeviceObject
);
8843 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
8845 if (!AlreadyStarted
)
8847 RxUnstart(RxContext
, DeviceObject
);
8851 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
8852 ExReleaseResourceLite(&RxData
.Resource
);
8862 IN PRX_CONTEXT RxContext
,
8863 OUT PBOOLEAN PostToFsp
)
8866 return STATUS_NOT_IMPLEMENTED
;
8871 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8875 return STATUS_NOT_IMPLEMENTED
;
8882 RxTryToBecomeTheTopLevelIrp(
8883 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
8885 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8886 IN BOOLEAN ForceTopLevel
8889 BOOLEAN FromPool
= FALSE
;
8893 /* If not top level, and not have to be, quit */
8894 if (IoGetTopLevelIrp() && !ForceTopLevel
)
8899 /* If not TLC provider, allocate one */
8900 if (TopLevelContext
== NULL
)
8902 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
8903 if (TopLevelContext
== NULL
)
8912 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
8914 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8917 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8920 /* Make it top level IRP */
8921 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
8930 RxUpdateShareAccess(
8931 _Inout_ PFILE_OBJECT FileObject
,
8932 _Inout_ PSHARE_ACCESS ShareAccess
,
8934 _In_ PSZ wherelogtag
)
8938 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8939 IoUpdateShareAccess(FileObject
, ShareAccess
);
8940 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8948 RxUninitializeCacheMap(
8949 PRX_CONTEXT RxContext
,
8950 PFILE_OBJECT FileObject
,
8951 PLARGE_INTEGER TruncateSize
)
8955 CACHE_UNINITIALIZE_EVENT UninitEvent
;
8959 Fcb
= FileObject
->FsContext
;
8960 ASSERT(NodeTypeIsFcb(Fcb
));
8961 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
8963 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
8964 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
8966 /* Always release the FCB before waiting for the uninit event */
8967 RxReleaseFcb(RxContext
, Fcb
);
8969 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
8971 /* Re-acquire it afterwards */
8972 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
8973 ASSERT(NT_SUCCESS(Status
));
8979 IN PDRIVER_OBJECT DriverObject
)
8988 IN PFILE_LOCK_INFO LockInfo
)
8995 PRX_CONTEXT Context
,
8996 PRDBSS_DEVICE_OBJECT DeviceObject
)
9005 RxUnwindTopLevelIrp(
9006 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
9008 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
9010 /* No TLC provided? Ask the system for ours! */
9011 if (TopLevelContext
== NULL
)
9013 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
9014 if (TopLevelContext
== NULL
)
9019 /* In that case, just assert it's really ours */
9020 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
9021 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9024 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9025 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
9026 /* Restore the previous top level IRP */
9027 IoSetTopLevelIrp(TopLevelContext
->Previous
);
9028 /* If TLC was allocated from pool, remove it from list and release it */
9029 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
9031 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
9032 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
9040 RxUpdateShareAccessPerSrvOpens(
9041 IN PSRV_OPEN SrvOpen
)
9043 ACCESS_MASK DesiredAccess
;
9045 BOOLEAN WriteAccess
;
9046 BOOLEAN DeleteAccess
;
9050 /* If already updated, no need to continue */
9051 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
9056 /* Check if any access wanted */
9057 DesiredAccess
= SrvOpen
->DesiredAccess
;
9058 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
9059 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
9060 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
9062 /* In that case, update it */
9063 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
9066 BOOLEAN SharedWrite
;
9067 BOOLEAN SharedDelete
;
9068 ULONG DesiredShareAccess
;
9069 PSHARE_ACCESS ShareAccess
;
9071 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
9072 DesiredShareAccess
= SrvOpen
->ShareAccess
;
9074 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
9075 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
9076 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
9078 ShareAccess
->OpenCount
++;
9080 ShareAccess
->Readers
+= ReadAccess
;
9081 ShareAccess
->Writers
+= WriteAccess
;
9082 ShareAccess
->Deleters
+= DeleteAccess
;
9083 ShareAccess
->SharedRead
+= SharedRead
;
9084 ShareAccess
->SharedWrite
+= SharedWrite
;
9085 ShareAccess
->SharedDelete
+= SharedDelete
;
9088 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
9095 RxXXXControlFileCallthru(
9096 PRX_CONTEXT Context
)
9102 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
9104 /* No dispatch table? Nothing to dispatch */
9105 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
9107 Context
->pFobx
= NULL
;
9108 return STATUS_INVALID_DEVICE_REQUEST
;
9111 /* Init the lowio context */
9112 Status
= RxLowIoPopulateFsctlInfo(Context
);
9113 if (!NT_SUCCESS(Status
))
9118 /* Check whether we're consistent: a length means a buffer */
9119 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
9120 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
9122 return STATUS_INVALID_PARAMETER
;
9125 /* Forward the call to the mini-rdr */
9126 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
9127 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
9128 if (Status
!= STATUS_PENDING
)
9130 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
9133 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);