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 */
748 RxAcquireExclusiveFcbResourceInMRx(
749 _Inout_ PMRX_FCB Fcb
)
752 return STATUS_NOT_IMPLEMENTED
;
757 RxAcquireFcbForLazyWrite(
767 RxAcquireFcbForReadAhead(
777 RxAcquireFileForNtCreateSection(
778 PFILE_OBJECT FileObject
)
786 PFILE_OBJECT FileObject
,
787 PDEVICE_OBJECT DeviceObject
)
790 return STATUS_NOT_IMPLEMENTED
;
797 RxAddToTopLevelIrpAllocatedContextsList(
798 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
802 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
804 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
805 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
807 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
808 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
809 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
818 IN PRX_CONTEXT RxContext
,
823 WORK_QUEUE_TYPE Queue
;
824 PIO_STACK_LOCATION Stack
;
826 Stack
= RxContext
->CurrentIrpSp
;
827 RxContext
->PostRequest
= FALSE
;
829 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
830 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
831 Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
833 Queue
= DelayedWorkQueue
;
834 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
838 Queue
= CriticalWorkQueue
;
839 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
842 /* Check for overflow */
843 if (Stack
->FileObject
!= NULL
)
845 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
847 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
848 /* In case of an overflow, add the new queued call to the overflow list */
851 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
852 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
853 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
855 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
859 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
862 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
863 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
870 RxAdjustFileTimesAndSize(
876 PFILE_OBJECT FileObject
;
877 LARGE_INTEGER CurrentTime
;
878 FILE_BASIC_INFORMATION FileBasicInfo
;
879 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
880 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
884 FileObject
= Context
->CurrentIrpSp
->FileObject
;
885 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
886 if (FileObject
->PrivateCacheMap
== NULL
)
892 KeQuerySystemTime(&CurrentTime
);
894 Fobx
= (PFOBX
)Context
->pFobx
;
895 /* Was the file modified? */
896 FileModified
= BooleanFlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
);
897 /* We'll set last write if it was modified and user didn't update yet */
898 SetLastWrite
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
899 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
900 SetLastAccess
= SetLastWrite
||
901 (BooleanFlagOn(FileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
902 !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
903 /* We'll set last change if it was modified and user didn't update yet */
904 SetLastChange
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
906 /* Nothing to update? Job done */
907 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
912 Fcb
= (PFCB
)Context
->pFcb
;
913 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
915 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
917 /* Update lastwrite time if required */
921 Fcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
922 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
925 /* Update lastaccess time if required */
929 Fcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
930 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
933 /* Update lastchange time if required */
937 Fcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
938 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
941 /* If one of the date was modified, issue a call to mini-rdr */
944 Context
->Info
.FileInformationClass
= FileBasicInformation
;
945 Context
->Info
.Buffer
= &FileBasicInfo
;
946 Context
->Info
.Length
= sizeof(FileBasicInfo
);
948 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
952 /* If the file was modified, update its EOF */
955 FileEOFInfo
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
957 Context
->Info
.FileInformationClass
= FileEndOfFileInformation
;
958 Context
->Info
.Buffer
= &FileEOFInfo
;
959 Context
->Info
.Length
= sizeof(FileEOFInfo
);
961 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
970 RxAllocateCanonicalNameBuffer(
971 PRX_CONTEXT RxContext
,
972 PUNICODE_STRING CanonicalName
,
973 USHORT CanonicalLength
)
977 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
979 /* Context must be free of any already allocated name */
980 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
982 /* Validate string length */
983 if (CanonicalLength
> USHRT_MAX
- 1)
985 CanonicalName
->Buffer
= NULL
;
986 return STATUS_OBJECT_PATH_INVALID
;
989 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
990 if (CanonicalName
->Buffer
== NULL
)
992 return STATUS_INSUFFICIENT_RESOURCES
;
995 CanonicalName
->Length
= 0;
996 CanonicalName
->MaximumLength
= CanonicalLength
;
998 /* Set the two places - they must always be identical */
999 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
1000 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
1002 return STATUS_SUCCESS
;
1009 RxCancelNotifyChangeDirectoryRequestsForFobx(
1014 PRX_CONTEXT Context
;
1015 LIST_ENTRY ContextsToCancel
;
1017 /* Init a list for the contexts to cancel */
1018 InitializeListHead(&ContextsToCancel
);
1020 /* Lock our list lock */
1021 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1023 /* Now, browse all the active contexts, to find the associated ones */
1024 Entry
= RxActiveContexts
.Flink
;
1025 while (Entry
!= &RxActiveContexts
)
1027 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1028 Entry
= Entry
->Flink
;
1030 /* Not the IRP we're looking for, ignore */
1031 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1032 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1037 /* Not the FOBX we're looking for, ignore */
1038 if ((PFOBX
)Context
->pFobx
!= Fobx
)
1043 /* No cancel routine (can't be cancel, then), ignore */
1044 if (Context
->MRxCancelRoutine
== NULL
)
1049 /* Mark our context as cancelled */
1050 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1052 /* Move it to our list */
1053 RemoveEntryList(&Context
->ContextListEntry
);
1054 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1056 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1059 /* Done with the contexts */
1060 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1062 /* Now, handle all our "extracted" contexts */
1063 while (!IsListEmpty(&ContextsToCancel
))
1065 Entry
= RemoveHeadList(&ContextsToCancel
);
1066 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1068 /* If they had an associated IRP (should be always true) */
1069 if (Context
->CurrentIrp
!= NULL
)
1071 /* Then, call cancel routine */
1072 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1073 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1074 Context
->MRxCancelRoutine(Context
);
1077 /* And delete the context */
1078 RxDereferenceAndDeleteRxContext(Context
);
1086 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1087 PV_NET_ROOT VNetRoot
,
1088 BOOLEAN ForceFilesClosed
)
1093 PRX_CONTEXT Context
;
1094 LIST_ENTRY ContextsToCancel
;
1096 /* Init a list for the contexts to cancel */
1097 InitializeListHead(&ContextsToCancel
);
1099 /* Lock our list lock */
1100 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1102 /* Now, browse all the active contexts, to find the associated ones */
1103 Entry
= RxActiveContexts
.Flink
;
1104 while (Entry
!= &RxActiveContexts
)
1106 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1107 Entry
= Entry
->Flink
;
1109 /* Not the IRP we're looking for, ignore */
1110 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1111 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1116 /* Not the VNetRoot we're looking for, ignore */
1117 if (Context
->pFcb
== NULL
||
1118 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1123 /* No cancel routine (can't be cancel, then), ignore */
1124 if (Context
->MRxCancelRoutine
== NULL
)
1129 /* At that point, we found a matching context
1130 * If we're not asked to force close, then fail - it's still open
1132 if (!ForceFilesClosed
)
1134 Status
= STATUS_FILES_OPEN
;
1138 /* Mark our context as cancelled */
1139 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1141 /* Move it to our list */
1142 RemoveEntryList(&Context
->ContextListEntry
);
1143 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1145 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1148 /* Done with the contexts */
1149 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1151 if (Status
!= STATUS_SUCCESS
)
1156 /* Now, handle all our "extracted" contexts */
1157 while (!IsListEmpty(&ContextsToCancel
))
1159 Entry
= RemoveHeadList(&ContextsToCancel
);
1160 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1162 /* If they had an associated IRP (should be always true) */
1163 if (Context
->CurrentIrp
!= NULL
)
1165 /* Then, call cancel routine */
1166 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1167 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1168 Context
->MRxCancelRoutine(Context
);
1171 /* And delete the context */
1172 RxDereferenceAndDeleteRxContext(Context
);
1181 PDEVICE_OBJECT DeviceObject
,
1191 RxCanonicalizeFileNameByServerSpecs(
1192 PRX_CONTEXT RxContext
,
1193 PUNICODE_STRING NetRootName
)
1195 USHORT NextChar
, CurChar
;
1200 /* Validate file name is not empty */
1201 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1204 return STATUS_MORE_PROCESSING_REQUIRED
;
1207 /* Validate name is correct */
1208 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1212 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1214 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1221 if (CurChar
== NextChar
)
1223 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1230 if (CurChar
>= MaxChars
- 1)
1235 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1237 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1242 if (NetRootName
->Buffer
[1] != ':')
1244 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1250 if ((CurChar
- NextChar
) == 1)
1252 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1257 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1259 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1264 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1265 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1270 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1272 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1278 return STATUS_MORE_PROCESSING_REQUIRED
;
1282 RxCanonicalizeNameAndObtainNetRoot(
1283 PRX_CONTEXT RxContext
,
1284 PUNICODE_STRING FileName
,
1285 PUNICODE_STRING NetRootName
)
1288 NET_ROOT_TYPE NetRootType
;
1289 UNICODE_STRING CanonicalName
;
1293 NetRootType
= NET_ROOT_WILD
;
1295 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1296 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1298 /* if not relative opening, just handle the passed name */
1299 if (RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
== NULL
)
1301 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1302 if (!NT_SUCCESS(Status
))
1311 /* Make sure we have a valid FCB and a FOBX */
1312 Fcb
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1314 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1316 return STATUS_INVALID_PARAMETER
;
1319 if (!NodeTypeIsFcb(Fcb
))
1321 return STATUS_INVALID_PARAMETER
;
1327 /* Get/Create the associated VNetRoot for opening */
1328 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1329 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1330 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1332 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1334 RxFreeCanonicalNameBuffer(RxContext
);
1335 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1336 if (NT_SUCCESS(Status
))
1338 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1342 /* Filename cannot contain wildcards */
1343 if (FsRtlDoesNameContainWildCards(NetRootName
))
1345 Status
= STATUS_OBJECT_NAME_INVALID
;
1348 /* Make sure file name is correct */
1349 if (NT_SUCCESS(Status
))
1351 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1354 /* Give the mini-redirector a chance to prepare the name */
1355 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1357 if (RxContext
->Create
.pNetRoot
!= NULL
)
1359 NTSTATUS IgnoredStatus
;
1361 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1362 MRxPreparseName
, (RxContext
, NetRootName
));
1363 (void)IgnoredStatus
;
1372 RxCheckFcbStructuresForAlignment(
1380 _In_ ACCESS_MASK DesiredAccess
,
1381 _In_ ULONG DesiredShareAccess
,
1382 _Inout_ PFILE_OBJECT FileObject
,
1383 _Inout_ PSHARE_ACCESS ShareAccess
,
1384 _In_ BOOLEAN Update
,
1386 _In_ PSZ wherelogtag
)
1390 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1391 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1393 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1400 RxCheckShareAccessPerSrvOpens(
1402 IN ACCESS_MASK DesiredAccess
,
1403 IN ULONG DesiredShareAccess
)
1406 BOOLEAN WriteAccess
;
1407 BOOLEAN DeleteAccess
;
1408 PSHARE_ACCESS ShareAccess
;
1412 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1414 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1415 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1417 /* Check if any access wanted */
1418 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1419 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1420 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1422 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1424 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1425 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1426 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1428 /* Check whether there's a violation */
1430 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1432 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1434 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1435 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1436 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1437 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1439 return STATUS_SHARING_VIOLATION
;
1443 return STATUS_SUCCESS
;
1447 RxCleanupPipeQueues(
1448 PRX_CONTEXT Context
)
1457 RxCloseAssociatedSrvOpen(
1459 IN PRX_CONTEXT RxContext OPTIONAL
)
1464 BOOLEAN CloseSrvOpen
;
1465 PRX_CONTEXT LocalContext
;
1469 /* Assume SRV_OPEN is already closed */
1470 CloseSrvOpen
= FALSE
;
1471 /* If we have a FOBX, we'll have to close it */
1474 /* If the FOBX isn't closed yet */
1475 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1477 SrvOpen
= Fobx
->SrvOpen
;
1478 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1479 /* Check whether we've to close SRV_OPEN first */
1480 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1482 CloseSrvOpen
= TRUE
;
1486 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1488 /* Not much to do */
1489 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1491 if (SrvOpen
->OpenCount
> 0)
1493 --SrvOpen
->OpenCount
;
1498 /* No need to close SRV_OPEN, so close FOBX */
1501 RxMarkFobxOnClose(Fobx
);
1503 return STATUS_SUCCESS
;
1508 /* No FOBX? No RX_CONTEXT, ok, job done! */
1509 if (RxContext
== NULL
)
1511 return STATUS_SUCCESS
;
1514 /* Get the FCB from RX_CONTEXT */
1515 Fcb
= (PFCB
)RxContext
->pFcb
;
1519 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1520 if (RxContext
== NULL
)
1522 ASSERT(Fobx
!= NULL
);
1524 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1525 if (LocalContext
== NULL
)
1527 return STATUS_INSUFFICIENT_RESOURCES
;
1530 LocalContext
->MajorFunction
= 2;
1531 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1532 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1533 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1537 LocalContext
= RxContext
;
1540 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1542 /* Now, close the FOBX */
1545 RxMarkFobxOnClose(Fobx
);
1549 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1552 /* If not a "standard" file, SRV_OPEN can be null */
1553 if (SrvOpen
== NULL
)
1555 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1556 RxDereferenceNetFcb(Fcb
);
1558 if (LocalContext
!= RxContext
)
1560 RxDereferenceAndDeleteRxContext(LocalContext
);
1563 return STATUS_SUCCESS
;
1566 /* If SRV_OPEN isn't in a good condition, nothing to close */
1567 if (SrvOpen
->Condition
!= Condition_Good
)
1569 if (LocalContext
!= RxContext
)
1571 RxDereferenceAndDeleteRxContext(LocalContext
);
1574 return STATUS_SUCCESS
;
1577 /* Decrease open count */
1578 if (SrvOpen
->OpenCount
> 0)
1580 --SrvOpen
->OpenCount
;
1583 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1584 if (SrvOpen
->OpenCount
== 1)
1586 if (!IsListEmpty(&SrvOpen
->FobxList
))
1588 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1590 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1595 /* Nothing left, purge FCB */
1596 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1598 RxPurgeNetFcb(Fcb
, LocalContext
);
1601 /* Already closed? Job done! */
1602 SrvOpen
= Fobx
->SrvOpen
;
1603 if (SrvOpen
== NULL
||
1604 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1605 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1607 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1608 if (LocalContext
!= RxContext
)
1610 RxDereferenceAndDeleteRxContext(LocalContext
);
1613 return STATUS_SUCCESS
;
1616 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1618 /* Inform mini-rdr about closing */
1619 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1620 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1621 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1623 /* And mark as such */
1624 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1625 SrvOpen
->Key
= (PVOID
)-1;
1627 /* If we were delayed, we're not! */
1628 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1630 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1634 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1635 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1638 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1640 /* Mark the FOBX closed as well */
1641 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1643 if (LocalContext
!= RxContext
)
1645 RxDereferenceAndDeleteRxContext(LocalContext
);
1655 RxCollapseOrCreateSrvOpen(
1656 PRX_CONTEXT RxContext
)
1663 PIO_STACK_LOCATION Stack
;
1664 ACCESS_MASK DesiredAccess
;
1665 RX_BLOCK_CONDITION FcbCondition
;
1669 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1671 Fcb
= (PFCB
)RxContext
->pFcb
;
1672 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1673 ++Fcb
->UncleanCount
;
1675 Stack
= RxContext
->CurrentIrpSp
;
1676 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1677 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1679 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1681 /* Try to find a reusable SRV_OPEN */
1682 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1683 if (Status
== STATUS_NOT_FOUND
)
1685 /* If none found, create one */
1686 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1687 if (SrvOpen
== NULL
)
1689 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1693 SrvOpen
->DesiredAccess
= DesiredAccess
;
1694 SrvOpen
->ShareAccess
= ShareAccess
;
1695 Status
= STATUS_SUCCESS
;
1698 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1700 if (Status
!= STATUS_SUCCESS
)
1702 FcbCondition
= Condition_Bad
;
1706 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1708 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1709 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1710 /* Inform the mini-rdr we're handling a create */
1711 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1712 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1714 DPRINT("MRxCreate returned: %x\n", Status
);
1715 if (Status
== STATUS_SUCCESS
)
1717 /* In case of overwrite, reset file size */
1718 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1720 RxAcquirePagingIoResource(RxContext
, Fcb
);
1721 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1722 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1723 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1724 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1725 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1726 RxReleasePagingIoResource(RxContext
, Fcb
);
1730 /* Otherwise, adjust sizes */
1731 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1732 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1734 RxAdjustAllocationSizeforCC(Fcb
);
1736 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1740 /* Set the IoStatus with information returned by mini-rdr */
1741 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1743 SrvOpen
->OpenStatus
= Status
;
1744 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1745 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1747 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1749 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1751 if (Status
== STATUS_SUCCESS
)
1753 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1755 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1757 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1758 FcbCondition
= Condition_Good
;
1762 FcbCondition
= Condition_Bad
;
1763 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1764 RxContext
->pRelevantSrvOpen
= NULL
;
1766 if (RxContext
->pFobx
!= NULL
)
1768 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1769 RxContext
->pFobx
= NULL
;
1774 /* Set FCB state - good or bad - depending on whether create succeed */
1775 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1776 RxTransitionNetFcb(Fcb
, FcbCondition
);
1778 else if (Status
== STATUS_SUCCESS
)
1780 BOOLEAN IsGood
, ExtraOpen
;
1782 /* A reusable SRV_OPEN was found */
1783 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1786 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1788 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1789 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1790 if (!StableCondition(SrvOpen
->Condition
))
1792 RxReferenceSrvOpen(SrvOpen
);
1793 ++SrvOpen
->OpenCount
;
1796 RxReleaseFcb(RxContext
, Fcb
);
1797 RxContext
->Create
.FcbAcquired
= FALSE
;
1799 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1801 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1803 RxContext
->Create
.FcbAcquired
= TRUE
;
1806 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1809 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1812 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1814 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1818 Status
= SrvOpen
->OpenStatus
;
1823 --SrvOpen
->OpenCount
;
1824 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1828 --Fcb
->UncleanCount
;
1830 DPRINT("Status: %x\n", Status
);
1840 PRX_CONTEXT Context
)
1842 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1848 PFILE_OBJECT FileObject
;
1849 LARGE_INTEGER TruncateSize
;
1850 PLARGE_INTEGER TruncateSizePtr
;
1851 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1855 Fcb
= (PFCB
)Context
->pFcb
;
1856 Fobx
= (PFOBX
)Context
->pFobx
;
1857 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1859 /* File system closing, it's OK */
1862 if (Fcb
->UncleanCount
> 0)
1864 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1867 return STATUS_SUCCESS
;
1870 /* Check we have a correct FCB type */
1871 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1872 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1873 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1874 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1876 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1877 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1880 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1881 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1883 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1885 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1886 if (!NT_SUCCESS(Status
))
1893 Fobx
->AssociatedFileObject
= NULL
;
1895 /* In case SRV_OPEN used is part of FCB */
1896 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
))
1898 ASSERT(Fcb
->UncleanCount
!= 0);
1899 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1901 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1903 --Fcb
->UncachedUncleanCount
;
1906 /* Inform mini-rdr */
1907 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1909 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1910 --Fobx
->SrvOpen
->UncleanFobxCount
;
1912 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1914 RxReleaseFcb(Context
, Fcb
);
1916 return STATUS_SUCCESS
;
1919 /* Report the fact that file could be set as delete on close */
1920 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1922 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1925 /* Cancel any pending notification */
1926 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1928 /* Backup open count before we start playing with it */
1929 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1931 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1932 FcbTableAcquired
= FALSE
;
1933 LeftForDelete
= FALSE
;
1934 OneLeft
= (Fcb
->UncleanCount
== 1);
1938 /* Unclean count and delete on close? Verify whether we're the one */
1939 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1941 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1943 FcbTableAcquired
= TRUE
;
1947 RxReleaseFcb(Context
, Fcb
);
1949 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1951 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1952 if (Status
!= STATUS_SUCCESS
)
1954 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1958 FcbTableAcquired
= TRUE
;
1961 /* That means we'll perform the delete on close! */
1962 if (Fcb
->UncleanCount
== 1)
1964 LeftForDelete
= TRUE
;
1968 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1969 FcbTableAcquired
= FALSE
;
1974 TruncateSizePtr
= NULL
;
1975 /* Handle cleanup for pipes and printers */
1976 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1978 RxCleanupPipeQueues(Context
);
1980 /* Handle cleanup for files */
1981 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1983 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1984 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1987 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1989 /* If there are still locks to release, proceed */
1990 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1992 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1993 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1994 Status
= RxLowIoLockControlShell(Context
);
1997 /* Fix times and size */
1998 RxAdjustFileTimesAndSize(Context
);
2000 /* If we're the only one left... */
2003 /* And if we're supposed to delete on close */
2006 /* Update the sizes */
2007 RxAcquirePagingIoResource(Context
, Fcb
);
2008 Fcb
->Header
.FileSize
.QuadPart
= 0;
2009 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
2010 RxReleasePagingIoResource(Context
, Fcb
);
2012 /* Otherwise, call the mini-rdr to adjust sizes */
2015 /* File got grown up, fill with zeroes */
2016 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2017 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
2019 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
2020 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2023 /* File was truncated, let mini-rdr proceed */
2024 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
2026 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
2027 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
2029 /* Keep track of file change for Cc uninit */
2030 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2031 TruncateSizePtr
= &TruncateSize
;
2036 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2044 /* Otherwise, try to see whether we can purge */
2047 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2054 /* We have to still be there! */
2055 ASSERT(Fcb
->UncleanCount
!= 0);
2056 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2058 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2060 --Fcb
->UncachedUncleanCount
;
2063 /* Inform mini-rdr about ongoing cleanup */
2064 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2066 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2067 --Fobx
->SrvOpen
->UncleanFobxCount
;
2070 if (DisableFlushOnCleanup
)
2072 /* Only if we're the last standing */
2073 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2074 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2076 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2077 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2083 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2085 DPRINT("Flushing %p on cleanup\n", Context
);
2086 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2090 /* If only remaining uncached & unclean, then flush and purge */
2091 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2093 if (Fcb
->UncachedUncleanCount
!= 0)
2095 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2096 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2098 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2099 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2104 /* If purge required, and not about to delete, flush */
2105 if (!LeftForDelete
&& NeedPurge
)
2107 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2108 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2111 /* If it was a file, drop cache */
2114 DPRINT("Uninit cache map for file\n");
2115 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2118 /* If that's the one left for deletion, or if it needs purge, flush */
2119 if (LeftForDelete
|| NeedPurge
)
2121 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2122 /* If that's for deletion, also remove from FCB table */
2125 RxRemoveNameNetFcb(Fcb
);
2126 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2127 FcbTableAcquired
= FALSE
;
2131 /* Remove any share access */
2132 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2134 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2137 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2138 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2139 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2141 NTSTATUS InternalStatus
;
2142 PRX_CONTEXT InternalContext
;
2144 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2145 InternalStatus
= STATUS_UNSUCCESSFUL
;
2146 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2147 Fcb
->RxDeviceObject
,
2148 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2149 if (InternalContext
!= NULL
)
2151 FILE_END_OF_FILE_INFORMATION FileEOF
;
2153 InternalStatus
= STATUS_SUCCESS
;
2155 /* Initialize the context for file information set */
2156 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2157 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2158 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2160 /* Get EOF from the FCB */
2161 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2162 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2163 InternalContext
->Info
.Buffer
= &FileEOF
;
2164 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2166 /* Call the mini-rdr */
2167 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2170 RxDereferenceAndDeleteRxContext(InternalContext
);
2173 /* We tried, so, clean the FOBX flag */
2174 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2175 /* If it failed, then, disable collapsing on the FCB */
2176 if (!NT_SUCCESS(InternalStatus
))
2178 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2183 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2185 FcbAcquired
= FALSE
;
2186 RxReleaseFcb(Context
, Fcb
);
2192 RxReleaseFcb(Context
, Fcb
);
2195 if (FcbTableAcquired
)
2197 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2203 #undef BugCheckFileId
2209 PRX_CONTEXT Context
)
2211 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2215 PFILE_OBJECT FileObject
;
2216 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2220 Fcb
= (PFCB
)Context
->pFcb
;
2221 Fobx
= (PFOBX
)Context
->pFobx
;
2222 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2223 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2225 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2226 if (!NT_SUCCESS(Status
))
2236 /* Check our FCB type is expected */
2237 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2238 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2239 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2241 RxBugCheck(NodeType(Fcb
), 0, 0);
2244 RxReferenceNetFcb(Fcb
);
2246 DereferenceFobx
= FALSE
;
2247 /* If we're not closing FS */
2253 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2254 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2255 /* Handle delayed close */
2256 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2258 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2260 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2262 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2264 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2266 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2268 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2272 DereferenceFobx
= TRUE
;
2273 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2280 /* If we reach maximum of delayed close/or if there are no delayed close */
2281 if (!DereferenceFobx
)
2285 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2286 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2288 /* Delete if asked */
2289 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2291 RxScavengeRelatedFobxs(Fcb
);
2292 RxSynchronizeWithScavenger(Context
);
2294 RxReleaseFcb(Context
, Fcb
);
2296 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2297 RxOrphanThisFcb(Fcb
);
2298 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2300 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2301 ASSERT(NT_SUCCESS(Status
));
2306 RxMarkFobxOnClose(Fobx
);
2309 if (DereferenceFobx
)
2311 ASSERT(Fobx
!= NULL
);
2312 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2316 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2319 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2323 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2324 AcquiredFcb
= !Freed
;
2326 FileObject
->FsContext
= (PVOID
)-1;
2330 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2334 RxReleaseFcb(Context
, Fcb
);
2335 AcquiredFcb
= FALSE
;
2340 if (_SEH2_AbnormalTermination())
2344 RxReleaseFcb(Context
, Fcb
);
2349 ASSERT(!AcquiredFcb
);
2354 DPRINT("Status: %x\n", Status
);
2356 #undef BugCheckFileId
2365 PRX_CONTEXT Context
)
2369 PFILE_OBJECT FileObject
;
2370 PIO_STACK_LOCATION Stack
;
2374 DPRINT("RxCommonCreate(%p)\n", Context
);
2376 Irp
= Context
->CurrentIrp
;
2377 Stack
= Context
->CurrentIrpSp
;
2378 FileObject
= Stack
->FileObject
;
2380 /* Check whether that's a device opening */
2381 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2383 FileObject
->FsContext
= &RxDeviceFCB
;
2384 FileObject
->FsContext2
= NULL
;
2386 ++RxDeviceFCB
.NodeReferenceCount
;
2387 ++RxDeviceFCB
.OpenCount
;
2389 Irp
->IoStatus
.Information
= FILE_OPENED
;
2390 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2392 Status
= STATUS_SUCCESS
;
2396 PFCB RelatedFcb
= NULL
;
2398 /* Make sure caller is consistent */
2399 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2400 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2402 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2403 return STATUS_INVALID_PARAMETER
;
2406 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2407 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2408 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2409 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2411 if (FileObject
->RelatedFileObject
!= NULL
)
2413 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2414 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2417 /* Going to rename? */
2418 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2420 DPRINT("TargetDir!\n");
2423 /* Copy create parameters to the context */
2424 RxCopyCreateParameters(Context
);
2426 /* If the caller wants to establish a connection, go ahead */
2427 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2429 Status
= RxCreateTreeConnect(Context
);
2433 /* Validate file name */
2434 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2435 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2436 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2438 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2439 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2440 FileObject
->FileName
.Length
);
2442 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2443 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2444 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2446 return STATUS_OBJECT_NAME_INVALID
;
2450 /* Attempt to open the file */
2453 UNICODE_STRING NetRootName
;
2455 /* Strip last \ if required */
2456 if (FileObject
->FileName
.Length
!= 0 &&
2457 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2459 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2461 return STATUS_OBJECT_NAME_INVALID
;
2464 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2465 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2468 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2470 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2473 /* Get the associated net root to opening */
2474 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2475 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2480 /* And attempt to open */
2481 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2482 if (Status
== STATUS_SHARING_VIOLATION
)
2484 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2486 /* If that happens for file creation, fail for real */
2487 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2489 Status
= STATUS_OBJECT_NAME_COLLISION
;
2493 /* Otherwise, if possible, attempt to scavenger current FOBX
2494 * to check whether a dormant FOBX is the reason for sharing violation
2496 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2497 !Context
->Create
.ScavengingAlreadyTried
)
2499 /* Only doable with a VNetRoot */
2500 if (Context
->Create
.pVNetRoot
!= NULL
)
2502 PV_NET_ROOT VNetRoot
;
2503 NT_CREATE_PARAMETERS SavedParameters
;
2505 /* Save create parameters */
2506 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2508 /* Reference the VNetRoot for the scavenging time */
2509 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2510 RxReferenceVNetRoot(VNetRoot
);
2512 /* Prepare the RX_CONTEXT for reuse */
2513 RxpPrepareCreateContextForReuse(Context
);
2514 RxReinitializeContext(Context
);
2516 /* Copy what we saved */
2517 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2519 /* And recopy what can be */
2520 RxCopyCreateParameters(Context
);
2522 /* And start purging, then scavenging FOBX */
2523 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2524 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2525 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2528 /* Ask for a second round */
2529 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2531 /* Keep track we already scavenged */
2532 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2534 /* Reference our SRV_CALL for CBS handling */
2535 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2536 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2538 /* Drop our extra reference */
2539 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2544 else if (Status
== STATUS_REPARSE
)
2546 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2550 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2553 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2556 if (Status
== STATUS_RETRY
)
2558 RxpPrepareCreateContextForReuse(Context
);
2560 ASSERT(Status
!= STATUS_PENDING
);
2563 DPRINT("Status: %lx\n", Status
);
2572 RxCommonDevFCBCleanup(
2573 PRX_CONTEXT Context
)
2580 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2582 Fcb
= Context
->pFcb
;
2583 Status
= STATUS_SUCCESS
;
2584 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2586 /* Our FOBX if set, has to be a VNetRoot */
2587 if (Context
->pFobx
!= NULL
)
2589 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2590 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2592 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2594 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2598 --Fcb
->UncleanCount
;
2609 RxCommonDevFCBClose(
2610 PRX_CONTEXT Context
)
2614 PMRX_V_NET_ROOT NetRoot
;
2618 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2620 Fcb
= Context
->pFcb
;
2621 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2622 Status
= STATUS_SUCCESS
;
2623 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2625 /* Our FOBX if set, has to be a VNetRoot */
2626 if (NetRoot
!= NULL
)
2628 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2629 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2631 --NetRoot
->NumberOfOpens
;
2632 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2636 Status
= STATUS_NOT_IMPLEMENTED
;
2638 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2650 RxCommonDevFCBFsCtl(
2651 PRX_CONTEXT Context
)
2654 return STATUS_NOT_IMPLEMENTED
;
2662 RxCommonDevFCBIoCtl(
2663 PRX_CONTEXT Context
)
2669 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2671 if (Context
->pFobx
!= NULL
)
2673 return STATUS_INVALID_HANDLE
;
2676 /* Is that a prefix claim from MUP? */
2677 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2679 return RxPrefixClaim(Context
);
2682 /* Otherwise, pass through the mini-rdr */
2683 Status
= RxXXXControlFileCallthru(Context
);
2684 if (Status
!= STATUS_PENDING
)
2686 if (Context
->PostRequest
)
2688 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2689 Status
= RxFsdPostRequest(Context
);
2693 DPRINT("Status: %lx\n", Status
);
2699 RxCommonDevFCBQueryVolInfo(
2700 PRX_CONTEXT Context
)
2703 return STATUS_NOT_IMPLEMENTED
;
2711 RxCommonDeviceControl(
2712 PRX_CONTEXT Context
)
2718 /* Prefix claim is only allowed for device, not files */
2719 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2721 return STATUS_INVALID_DEVICE_REQUEST
;
2724 /* Submit to mini-rdr */
2725 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2726 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2727 if (Status
== STATUS_PENDING
)
2729 RxDereferenceAndDeleteRxContext_Real(Context
);
2740 RxCommonDirectoryControl(
2741 PRX_CONTEXT Context
)
2746 PIO_STACK_LOCATION Stack
;
2750 Fcb
= (PFCB
)Context
->pFcb
;
2751 Fobx
= (PFOBX
)Context
->pFobx
;
2752 Stack
= Context
->CurrentIrpSp
;
2753 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2755 /* Call the appropriate helper */
2756 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2758 Status
= RxQueryDirectory(Context
);
2760 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2762 Status
= RxNotifyChangeDirectory(Context
);
2763 if (Status
== STATUS_PENDING
)
2765 RxDereferenceAndDeleteRxContext_Real(Context
);
2770 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2778 RxCommonDispatchProblem(
2779 PRX_CONTEXT Context
)
2782 return STATUS_NOT_IMPLEMENTED
;
2787 RxCommonFileSystemControl(
2788 PRX_CONTEXT Context
)
2792 PIO_STACK_LOCATION Stack
;
2796 Irp
= Context
->CurrentIrp
;
2797 Stack
= Context
->CurrentIrpSp
;
2798 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2800 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2803 return STATUS_NOT_IMPLEMENTED
;
2808 RxCommonFlushBuffers(
2809 PRX_CONTEXT Context
)
2812 return STATUS_NOT_IMPLEMENTED
;
2817 RxCommonLockControl(
2818 PRX_CONTEXT Context
)
2821 return STATUS_NOT_IMPLEMENTED
;
2827 PRX_CONTEXT Context
)
2830 return STATUS_NOT_IMPLEMENTED
;
2838 RxCommonQueryInformation(
2839 PRX_CONTEXT Context
)
2841 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2842 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2843 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2850 PIO_STACK_LOCATION Stack
;
2851 FILE_INFORMATION_CLASS FileInfoClass
;
2855 Fcb
= (PFCB
)Context
->pFcb
;
2856 Fobx
= (PFOBX
)Context
->pFobx
;
2857 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2859 Irp
= Context
->CurrentIrp
;
2860 Stack
= Context
->CurrentIrpSp
;
2861 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2862 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2864 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2865 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2872 /* Get a writable buffer */
2873 Buffer
= RxMapSystemBuffer(Context
);
2876 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2880 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2882 /* Validate file type */
2883 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2885 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2887 Status
= STATUS_INVALID_PARAMETER
;
2890 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2892 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2894 Status
= STATUS_NOT_IMPLEMENTED
;
2898 Status
= STATUS_INVALID_PARAMETER
;
2905 /* Acquire the right lock */
2906 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2907 FileInfoClass
!= FileNameInformation
)
2909 if (FileInfoClass
== FileCompressionInformation
)
2911 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2915 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2918 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2920 Status
= STATUS_PENDING
;
2923 else if (!NT_SUCCESS(Status
))
2931 /* Dispatch to the right helper */
2932 switch (FileInfoClass
)
2934 case FileBasicInformation
:
2935 Status
= RxQueryBasicInfo(Context
, Buffer
);
2938 case FileStandardInformation
:
2939 Status
= RxQueryStandardInfo(Context
, Buffer
);
2942 case FileInternalInformation
:
2943 Status
= RxQueryInternalInfo(Context
, Buffer
);
2946 case FileEaInformation
:
2947 Status
= RxQueryEaInfo(Context
, Buffer
);
2950 case FileNameInformation
:
2951 Status
= RxQueryNameInfo(Context
, Buffer
);
2954 case FileAllInformation
:
2955 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2956 if (!NT_SUCCESS(Status
))
2961 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2962 if (!NT_SUCCESS(Status
))
2967 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2968 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2969 if (!NT_SUCCESS(Status
))
2974 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2975 sizeof(FILE_STANDARD_INFORMATION
) +
2976 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2977 if (!NT_SUCCESS(Status
))
2982 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2983 sizeof(FILE_STANDARD_INFORMATION
) +
2984 sizeof(FILE_INTERNAL_INFORMATION
) +
2985 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2986 if (!NT_SUCCESS(Status
))
2991 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2992 sizeof(FILE_STANDARD_INFORMATION
) +
2993 sizeof(FILE_INTERNAL_INFORMATION
) +
2994 sizeof(FILE_EA_INFORMATION
) +
2995 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2998 case FileAlternateNameInformation
:
2999 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
3002 case FilePipeInformation
:
3003 case FilePipeLocalInformation
:
3004 case FilePipeRemoteInformation
:
3005 Status
= RxQueryPipeInfo(Context
, Buffer
);
3008 case FileCompressionInformation
:
3009 Status
= RxQueryCompressedInfo(Context
, Buffer
);
3013 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
3014 Status
= Context
->IoStatusBlock
.Status
;
3018 if (Context
->Info
.Length
< 0)
3020 Status
= STATUS_BUFFER_OVERFLOW
;
3021 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
3024 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
3030 RxReleaseFcb(Context
, Fcb
);
3035 DPRINT("Status: %x\n", Status
);
3038 #undef SET_SIZE_AND_QUERY
3043 RxCommonQueryQuotaInformation(
3044 PRX_CONTEXT Context
)
3047 return STATUS_NOT_IMPLEMENTED
;
3052 RxCommonQuerySecurity(
3053 PRX_CONTEXT Context
)
3056 return STATUS_NOT_IMPLEMENTED
;
3064 RxCommonQueryVolumeInformation(
3065 PRX_CONTEXT Context
)
3071 PIO_STACK_LOCATION Stack
;
3075 Fcb
= (PFCB
)Context
->pFcb
;
3076 Fobx
= (PFOBX
)Context
->pFobx
;
3078 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3080 Irp
= Context
->CurrentIrp
;
3081 Stack
= Context
->CurrentIrpSp
;
3082 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3083 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3085 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3086 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3087 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3089 /* Forward to mini-rdr */
3090 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3092 /* Post request if mini-rdr asked to */
3093 if (Context
->PostRequest
)
3095 Status
= RxFsdPostRequest(Context
);
3099 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3102 DPRINT("Status: %x\n", Status
);
3109 PRX_CONTEXT RxContext
)
3117 PFILE_OBJECT FileObject
;
3118 LARGE_INTEGER ByteOffset
;
3119 PIO_STACK_LOCATION Stack
;
3120 PLOWIO_CONTEXT LowIoContext
;
3121 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3122 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3123 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3127 Fcb
= (PFCB
)RxContext
->pFcb
;
3128 Fobx
= (PFOBX
)RxContext
->pFobx
;
3129 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3131 /* Get some parameters */
3132 Irp
= RxContext
->CurrentIrp
;
3133 Stack
= RxContext
->CurrentIrpSp
;
3134 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3135 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3136 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3137 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3138 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3139 ReadLength
= Stack
->Parameters
.Read
.Length
;
3140 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3141 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3142 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3144 RxItsTheSameContext();
3146 Irp
->IoStatus
.Information
= 0;
3148 /* Should the read be loud - so far, it's just ignored on ReactOS:
3149 * s/DPRINT/DPRINT1/g will make it loud
3151 LowIoContext
= &RxContext
->LowIoContext
;
3152 CheckForLoudOperations(RxContext
);
3153 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3155 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3156 ByteOffset
, ReadLength
,
3157 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3160 RxDeviceObject
= RxContext
->RxDeviceObject
;
3162 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3164 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3166 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3168 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3170 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3174 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3178 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3182 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3186 /* A pagefile cannot be a pipe */
3187 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3188 if (IsPipe
&& PagingIo
)
3190 return STATUS_INVALID_DEVICE_REQUEST
;
3193 /* Null-length read is no-op */
3194 if (ReadLength
== 0)
3196 return STATUS_SUCCESS
;
3199 /* Validate FCB type */
3200 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3202 return STATUS_INVALID_DEVICE_REQUEST
;
3205 /* Init the lowio context for possible forward */
3206 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3208 PostRequest
= FALSE
;
3209 ReadCachingDisabled
= FALSE
;
3211 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3212 FileObject
= Stack
->FileObject
;
3213 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3218 /* If no caching, make sure current Cc data have been flushed */
3219 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3221 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3222 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3227 else if (Status
!= STATUS_SUCCESS
)
3232 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3233 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3234 RxReleasePagingIoResource(RxContext
, Fcb
);
3236 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3241 RxAcquirePagingIoResource(RxContext
, Fcb
);
3242 RxReleasePagingIoResource(RxContext
, Fcb
);
3245 /* Acquire the appropriate lock */
3246 if (PagingIo
&& !ReadCachingEnabled
)
3250 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3258 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3263 if (!ReadCachingEnabled
)
3265 if (!CanWait
&& NoCache
)
3267 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3268 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3270 DPRINT1("RdAsyLNG %x\n", RxContext
);
3274 if (Status
!= STATUS_SUCCESS
)
3276 DPRINT1("RdAsyOthr %x\n", RxContext
);
3280 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3282 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3292 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3293 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3298 else if (Status
!= STATUS_SUCCESS
)
3306 RxItsTheSameContext();
3308 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3314 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3316 /* Make sure FLOCK doesn't conflict */
3319 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3321 Status
= STATUS_FILE_LOCK_CONFLICT
;
3326 /* Validate byteoffset vs length */
3327 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3329 if (ByteOffset
.QuadPart
>= FileSize
)
3331 Status
= STATUS_END_OF_FILE
;
3335 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3337 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3342 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3343 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3345 /* File was not cached yet, do it */
3346 if (FileObject
->PrivateCacheMap
== NULL
)
3348 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3350 Status
= STATUS_FILE_CLOSED
;
3354 RxAdjustAllocationSizeforCC(Fcb
);
3356 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3357 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3359 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3361 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3365 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3366 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3369 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3372 /* This should never happen - fix your RDR */
3373 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3378 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3379 Status
= Irp
->IoStatus
.Status
;
3380 ASSERT(NT_SUCCESS(Status
));
3385 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3386 if (SystemBuffer
== NULL
)
3388 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3392 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3394 RxItsTheSameContext();
3396 /* Perform the read */
3397 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3399 if (!ReadCachingEnabled
)
3401 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3404 RxItsTheSameContext();
3410 if (!ReadCachingEnabled
)
3412 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3415 Status
= Irp
->IoStatus
.Status
;
3416 ASSERT(NT_SUCCESS(Status
));
3421 /* Validate the reading */
3422 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3423 ByteOffset
.QuadPart
>= 4096)
3425 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3426 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3429 /* If it's consistent, forward to mini-rdr */
3430 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3431 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3433 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3434 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3436 RxItsTheSameContext();
3438 if (InFsp
&& ReadCachingDisabled
)
3440 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3441 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3445 Status
= RxLowIoReadShell(RxContext
);
3447 RxItsTheSameContext();
3451 if (ByteOffset
.QuadPart
> FileSize
)
3454 Irp
->IoStatus
.Information
= ReadLength
;
3458 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3460 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3463 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3464 RtlZeroMemory(SystemBuffer
, ReadLength
);
3465 Irp
->IoStatus
.Information
= ReadLength
;
3471 RxItsTheSameContext();
3473 /* Post if required */
3476 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3477 Status
= RxFsdPostRequest(RxContext
);
3481 /* Update FO in case of sync IO */
3482 if (!IsPipe
&& !PagingIo
)
3484 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3486 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3491 /* Set FastIo if read was a success */
3492 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3494 if (!IsPipe
&& !PagingIo
)
3496 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3500 /* In case we're done (not expected any further processing */
3501 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3503 /* Release everything that can be */
3504 if (ReadCachingDisabled
)
3510 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3514 RxReleasePagingIoResource(RxContext
, Fcb
);
3521 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3525 RxReleaseFcb(RxContext
, Fcb
);
3530 /* Dereference/Delete context */
3533 RxDereferenceAndDeleteRxContext(RxContext
);
3537 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3539 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3543 /* We cannot return more than asked */
3544 if (Status
== STATUS_SUCCESS
)
3546 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3553 RxDereferenceAndDeleteRxContext(RxContext
);
3564 PRX_CONTEXT Context
)
3567 return STATUS_NOT_IMPLEMENTED
;
3575 RxCommonSetInformation(
3576 PRX_CONTEXT Context
)
3583 PIO_STACK_LOCATION Stack
;
3584 FILE_INFORMATION_CLASS Class
;
3585 BOOLEAN CanWait
, FcbTableAcquired
, FcbAcquired
;
3589 Fcb
= (PFCB
)Context
->pFcb
;
3590 Fobx
= (PFOBX
)Context
->pFobx
;
3591 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3593 Irp
= Context
->CurrentIrp
;
3594 Stack
= Context
->CurrentIrpSp
;
3595 Class
= Stack
->Parameters
.SetFile
.FileInformationClass
;
3596 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3597 Irp
->AssociatedIrp
.SystemBuffer
, Stack
->Parameters
.SetFile
.Length
,
3598 Class
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
3600 Status
= STATUS_SUCCESS
;
3601 CanWait
= BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3602 FcbTableAcquired
= FALSE
;
3603 FcbAcquired
= FALSE
;
3604 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3606 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3610 /* Valide the node type first */
3611 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3612 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3614 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
3616 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3618 Status
= STATUS_SUCCESS
;
3621 else if (NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
3623 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
3625 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3629 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb
));
3630 _SEH2_TRY_RETURN(Status
= STATUS_INVALID_PARAMETER
);
3635 /* We don't autorize advance operation */
3636 if (Class
== FileEndOfFileInformation
&& Stack
->Parameters
.SetFile
.AdvanceOnly
)
3638 DPRINT1("Not allowed\n");
3640 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3643 /* For these to classes, we'll have to deal with the FCB table (removal)
3644 * We thus need the exclusive FCB table lock
3646 if (Class
== FileDispositionInformation
|| Class
== FileRenameInformation
)
3648 RxPurgeRelatedFobxs(NetRoot
, Context
, TRUE
, Fcb
);
3649 RxScavengeFobxsForNetRoot(NetRoot
, Fcb
, TRUE
);
3651 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, CanWait
))
3653 Context
->PostRequest
= TRUE
;
3654 _SEH2_TRY_RETURN(Status
= STATUS_PENDING
);
3657 FcbTableAcquired
= TRUE
;
3660 /* Finally, if not paging file, we need exclusive FCB lock */
3661 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3663 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
3664 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3666 Context
->PostRequest
= TRUE
;
3667 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3669 else if (Status
!= STATUS_SUCCESS
)
3677 Status
= STATUS_SUCCESS
;
3679 /* And now, perform the job! */
3682 case FileBasicInformation
:
3683 Status
= RxSetBasicInfo(Context
);
3686 case FileDispositionInformation
:
3688 PFILE_DISPOSITION_INFORMATION FDI
;
3690 /* Check whether user wants deletion */
3691 FDI
= Irp
->AssociatedIrp
.SystemBuffer
;
3692 if (FDI
->DeleteFile
)
3694 /* If so, check whether it's doable */
3695 if (!MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForDelete
))
3697 Status
= STATUS_CANNOT_DELETE
;
3700 /* And if doable, already remove from FCB table */
3701 if (Status
== STATUS_SUCCESS
)
3703 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3704 RxRemoveNameNetFcb(Fcb
);
3706 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3707 FcbTableAcquired
= FALSE
;
3711 /* If it succeed, perform the operation */
3712 if (Status
== STATUS_SUCCESS
)
3714 Status
= RxSetDispositionInfo(Context
);
3720 case FilePositionInformation
:
3721 Status
= RxSetPositionInfo(Context
);
3724 case FileAllocationInformation
:
3725 Status
= RxSetAllocationInfo(Context
);
3728 case FileEndOfFileInformation
:
3729 Status
= RxSetEndOfFileInfo(Context
);
3732 case FilePipeInformation
:
3733 case FilePipeLocalInformation
:
3734 case FilePipeRemoteInformation
:
3735 Status
= RxSetPipeInfo(Context
);
3738 case FileRenameInformation
:
3739 case FileLinkInformation
:
3740 case FileMoveClusterInformation
:
3741 /* If we can wait, try to perform the operation right now */
3744 /* Of course, collapsing is not doable anymore, file is
3745 * in an inbetween state
3747 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
3749 /* Set the information */
3750 Status
= RxSetRenameInfo(Context
);
3751 /* If it succeed, drop the current entry from FCB table */
3752 if (Status
== STATUS_SUCCESS
&& Class
== FileRenameInformation
)
3754 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3755 RxRemoveNameNetFcb(Fcb
);
3757 _SEH2_TRY_RETURN(Status
);
3759 /* Can't wait? Post for async retry */
3762 Status
= RxFsdPostRequest(Context
);
3763 _SEH2_TRY_RETURN(Status
);
3767 case FileValidDataLengthInformation
:
3768 if (!MmCanFileBeTruncated(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
))
3770 Status
= STATUS_USER_MAPPED_FILE
;
3774 case FileShortNameInformation
:
3775 Status
= RxSetSimpleInfo(Context
);
3779 DPRINT1("Insupported class: %x\n", Class
);
3780 Status
= STATUS_INVALID_PARAMETER
;
3786 /* If mini-rdr was OK and wants a re-post on this, do it */
3787 if (Status
== STATUS_SUCCESS
)
3789 if (Context
->PostRequest
)
3791 Status
= RxFsdPostRequest(Context
);
3797 /* Release any acquired lock */
3800 RxReleaseFcb(Context
, Fcb
);
3803 if (FcbTableAcquired
)
3805 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3810 #undef _SEH2_TRY_RETURN
3817 RxCommonSetQuotaInformation(
3818 PRX_CONTEXT Context
)
3821 return STATUS_NOT_IMPLEMENTED
;
3826 RxCommonSetSecurity(
3827 PRX_CONTEXT Context
)
3830 return STATUS_NOT_IMPLEMENTED
;
3835 RxCommonSetVolumeInformation(
3836 PRX_CONTEXT Context
)
3839 return STATUS_NOT_IMPLEMENTED
;
3844 RxCommonUnimplemented(
3845 PRX_CONTEXT Context
)
3848 return STATUS_NOT_IMPLEMENTED
;
3854 PRX_CONTEXT RxContext
)
3862 PFILE_OBJECT FileObject
;
3863 PIO_STACK_LOCATION Stack
;
3864 LARGE_INTEGER ByteOffset
;
3865 NODE_TYPE_CODE NodeTypeCode
;
3866 PLOWIO_CONTEXT LowIoContext
;
3867 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3868 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3869 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3870 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3874 Fcb
= (PFCB
)RxContext
->pFcb
;
3875 NodeTypeCode
= NodeType(Fcb
);
3876 /* Validate FCB type */
3877 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3878 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3880 return STATUS_INVALID_DEVICE_REQUEST
;
3883 /* We'll write to file, keep track of it */
3884 Fcb
->IsFileWritten
= TRUE
;
3886 Stack
= RxContext
->CurrentIrpSp
;
3887 /* Set write through if asked */
3888 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3890 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3893 Fobx
= (PFOBX
)RxContext
->pFobx
;
3894 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3896 /* Get some parameters */
3897 Irp
= RxContext
->CurrentIrp
;
3898 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3899 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3900 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3901 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3902 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3903 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3904 WriteLength
= Stack
->Parameters
.Write
.Length
;
3905 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3906 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3907 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3909 RxItsTheSameContext();
3911 RxContext
->FcbResourceAcquired
= FALSE
;
3912 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3914 LowIoContext
= &RxContext
->LowIoContext
;
3915 CheckForLoudOperations(RxContext
);
3916 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3918 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3919 ByteOffset
, WriteLength
,
3920 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3923 RxDeviceObject
= RxContext
->RxDeviceObject
;
3925 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3927 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3929 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3931 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3933 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3937 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3941 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3945 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3949 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3950 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3951 /* Keep track for normal writes */
3952 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3961 /* Zero-length write is immediate success */
3962 if (NormalFile
&& WriteLength
== 0)
3964 return STATUS_SUCCESS
;
3967 /* Check whether we have input data */
3968 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3970 return STATUS_INVALID_PARAMETER
;
3973 /* Are we writting to EOF? */
3974 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3975 /* FIXME: validate length/offset */
3977 /* Get our SRV_OPEN in case of normal write */
3980 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3987 FileObject
= Stack
->FileObject
;
3989 /* If we have caching enabled, check whether we have to defer write */
3992 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3994 if (!CcCanIWrite(FileObject
, WriteLength
,
3995 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3996 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
4000 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
4002 RxPrePostIrp(RxContext
, Irp
);
4004 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
4006 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
4008 return STATUS_PENDING
;
4013 /* Initialize the low IO context for write */
4014 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
4016 /* Initialize our (many) booleans */
4017 RecursiveWriteThrough
= FALSE
;
4018 CalledByLazyWriter
= FALSE
;
4019 SwitchBackToAsync
= FALSE
;
4020 ExtendingFile
= FALSE
;
4021 ExtendingValidData
= FALSE
;
4022 UnwindOutstandingAsync
= FALSE
;
4023 ResourceOwnerSet
= FALSE
;
4025 ContextReferenced
= FALSE
;
4027 #define _SEH2_TRY_RETURN(S) S; goto try_exit
4031 /* No volume FCB here! */
4032 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
4033 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
4034 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
4036 /* Writing to EOF on a paging file is non sense */
4037 ASSERT(!(WriteToEof
&& PagingIo
));
4039 RxItsTheSameContext();
4041 /* Start locking stuff */
4042 if (!PagingIo
&& !NoPreposting
)
4044 /* If it's already acquired, all fine */
4045 if (RxContext
->FcbResourceAcquired
)
4051 /* Otherwise, try to acquire shared (excepted for pipes) */
4054 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4057 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
4059 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
4063 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
4066 /* We'll post IRP to retry */
4067 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4070 DPRINT1("Failed to acquire lock!\n");
4071 _SEH2_TRY_RETURN(Status
);
4074 /* We'll just fail */
4075 if (Status
!= STATUS_SUCCESS
)
4077 _SEH2_TRY_RETURN(Status
);
4080 /* Resource acquired */
4081 RxContext
->FcbResourceAcquired
= TRUE
;
4084 /* At that point, resource is acquired */
4087 ASSERT(RxContext
->FcbResourceAcquired
);
4093 /* Now, check whether we have to promote shared lock */
4094 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4096 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
4103 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4104 if (RxIsFcbAcquiredShared(Fcb
) &&
4105 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
4109 RxReleaseFcb(RxContext
, Fcb
);
4110 RxContext
->FcbResourceAcquired
= FALSE
;
4112 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4113 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4116 DPRINT1("Failed to acquire lock!\n");
4117 _SEH2_TRY_RETURN(Status
);
4120 if (Status
!= STATUS_SUCCESS
)
4122 _SEH2_TRY_RETURN(Status
);
4125 RxContext
->FcbResourceAcquired
= TRUE
;
4129 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4130 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
4133 if (RxIsFcbAcquiredExclusive(Fcb
))
4135 RxConvertToSharedFcb(RxContext
, Fcb
);
4140 /* We're extending file, disable collapsing */
4141 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
4143 DPRINT("Disabling collapsing\n");
4145 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4147 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
4151 ASSERT(RxContext
->FcbResourceAcquired
);
4154 /* Keep track of the acquired resource */
4155 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
4162 /* Lock the paging resource */
4163 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
4165 /* Keep track of the acquired resource */
4166 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
4172 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
4175 /* If it's a non cached write, or if caching is disallowed */
4176 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4178 /* If cache was previously enabled, we'll have to flush before writing */
4179 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
4181 LARGE_INTEGER FlushOffset
;
4184 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
4186 /* If shared, we'll have to relock exclusive */
4187 if (!RxIsFcbAcquiredExclusive(Fcb
))
4189 /* Release and retry exclusive */
4190 RxReleaseFcb(RxContext
, Fcb
);
4191 RxContext
->FcbResourceAcquired
= FALSE
;
4193 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4194 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4197 DPRINT1("Failed to acquire lock for flush!\n");
4198 _SEH2_TRY_RETURN(Status
);
4201 if (Status
!= STATUS_SUCCESS
)
4203 _SEH2_TRY_RETURN(Status
);
4206 RxContext
->FcbResourceAcquired
= TRUE
;
4209 /* Get the length to flush */
4212 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
4216 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
4219 /* Perform the flushing */
4220 RxAcquirePagingIoResource(RxContext
, Fcb
);
4221 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
4222 WriteLength
, &Irp
->IoStatus
);
4223 RxReleasePagingIoResource(RxContext
, Fcb
);
4225 /* Cannot continue if flushing failed */
4226 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
4228 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
4232 RxAcquirePagingIoResource(RxContext
, Fcb
);
4233 RxReleasePagingIoResource(RxContext
, Fcb
);
4236 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
4237 &FlushOffset
, WriteLength
, FALSE
);
4241 /* If not paging IO, check if write is allowed */
4244 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4246 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4250 /* Get file sizes */
4251 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4252 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4253 ASSERT(ValidDataLength
<= FileSize
);
4255 /* If paging IO, we cannot write past file size
4256 * so fix write length if needed
4260 if (ByteOffset
.QuadPart
>= FileSize
)
4262 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4265 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4267 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4271 /* If we're being called by the lazywrite */
4272 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4274 CalledByLazyWriter
= TRUE
;
4276 /* Fail if we're beyong VDL */
4277 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4279 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4280 (ByteOffset
.QuadPart
< FileSize
))
4282 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4284 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4290 /* If that's a recursive synchronous page write */
4291 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4292 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4296 /* Check the top level IRP on the FastIO path */
4297 TopIrp
= RxGetTopIrpIfRdbssIrp();
4298 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4300 PIO_STACK_LOCATION IrpStack
;
4302 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4304 /* If the top level IRP was a cached write for this file, keep track */
4305 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4306 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4307 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4309 RecursiveWriteThrough
= TRUE
;
4310 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4315 /* Now, deal with file size and VDL */
4316 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4317 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4319 /* Not sync? Let's make it sync, just the time we extended */
4323 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4324 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4327 /* Keep track we'll have to switch back to async */
4330 SwitchBackToAsync
= TRUE
;
4334 /* Release all the locks */
4335 RxWriteReleaseResources(RxContext
, 0);
4337 /* Acquire exclusive */
4338 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4339 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4342 DPRINT1("Failed to acquire lock for extension!\n");
4343 _SEH2_TRY_RETURN(Status
);
4346 if (Status
!= STATUS_SUCCESS
)
4348 _SEH2_TRY_RETURN(Status
);
4351 RxContext
->FcbResourceAcquired
= TRUE
;
4353 RxItsTheSameContext();
4355 /* Get the sizes again, to be sure they didn't change in the meantime */
4356 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4357 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4358 ASSERT(ValidDataLength
<= FileSize
);
4360 /* Check we can switch back to async? */
4361 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4362 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4364 SwitchBackToAsync
= FALSE
;
4367 /* If paging IO, check we don't try to extend the file */
4370 if (ByteOffset
.QuadPart
>= FileSize
)
4372 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4375 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4377 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4382 /* Save our initial sizes for potential rollback */
4383 InitialFileSize
= FileSize
;
4384 InitialValidDataLength
= ValidDataLength
;
4385 /* If writing to EOF, update byte offset with file size */
4388 ByteOffset
.QuadPart
= FileSize
;
4391 /* Check again whether we're allowed to write */
4394 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4396 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4399 /* Do we have to extend? */
4400 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4402 DPRINT("Need to extend file\n");
4403 ExtendingFile
= TRUE
;
4404 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4408 /* Let's start to extend */
4411 /* If we're past allocating, inform mini-rdr */
4412 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4413 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4415 LARGE_INTEGER NewAllocationSize
;
4417 DPRINT("Extending %p\n", RxContext
);
4421 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4422 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4423 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4427 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4428 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4429 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4432 if (!NT_SUCCESS(Status
))
4434 _SEH2_TRY_RETURN(Status
);
4437 if (FileSize
> NewAllocationSize
.QuadPart
)
4439 NewAllocationSize
.QuadPart
= FileSize
;
4442 /* And update FCB */
4443 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4446 /* Set the new sizes */
4447 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4448 RxAdjustAllocationSizeforCC(Fcb
);
4451 if (CcIsFileCached(FileObject
))
4453 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4457 /* Do we have to extend VDL? */
4458 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4460 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4462 ExtendingValidData
= TRUE
;
4463 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4467 /* If none cached write */
4468 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4470 /* Switch back to async, if asked to */
4471 if (SwitchBackToAsync
)
4476 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4477 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4480 /* If not synchronous, keep track of writes to be finished */
4483 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4485 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4486 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4487 NotificationEvent
, FALSE
);
4490 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4492 &RxStrucSupSpinLock
) == 0)
4494 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4497 UnwindOutstandingAsync
= TRUE
;
4498 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4501 /* Set our LOWIO_CONTEXT information */
4502 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4503 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4505 RxItsTheSameContext();
4507 /* We have to be locked */
4508 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4510 /* Update thread ID if we're in FSP */
4513 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4515 if (RxContext
->FcbResourceAcquired
)
4517 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4520 if (RxContext
->FcbPagingIoResourceAcquired
)
4522 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4525 ResourceOwnerSet
= TRUE
;
4528 /* And perform the write */
4529 Status
= RxLowIoWriteShell(RxContext
);
4531 RxItsTheSameContext();
4533 /* Not outstanding write anymore */
4534 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4536 UnwindOutstandingAsync
= FALSE
;
4542 /* If cache wasn't enabled yet, do it */
4543 if (FileObject
->PrivateCacheMap
== NULL
)
4545 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4547 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4550 RxAdjustAllocationSizeforCC(Fcb
);
4552 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4553 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4555 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4558 /* If that's a MDL backed write */
4559 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4561 /* Shouldn't happen */
4565 /* Perform it, though */
4566 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4567 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4569 Status
= Irp
->IoStatus
.Status
;
4574 ULONG BreakpointsSave
;
4576 /* Map the user buffer */
4577 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4578 if (SystemBuffer
== NULL
)
4580 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4583 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4585 RxItsTheSameContext();
4587 /* And deal with Cc */
4588 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4591 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4593 RxItsTheSameContext();
4595 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4596 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4602 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4603 Irp
->IoStatus
.Information
= WriteLength
;
4605 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4607 RxItsTheSameContext();
4609 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4610 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4617 /* If we've to post the IRP */
4620 /* Reset the file size if required */
4621 if (ExtendingFile
&& !IsPipe
)
4623 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4624 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4626 RxAcquirePagingIoResource(RxContext
, Fcb
);
4627 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4628 RxReleasePagingIoResource(RxContext
, Fcb
);
4630 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4632 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4636 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4637 ContextReferenced
= TRUE
;
4640 ASSERT(!ResourceOwnerSet
);
4641 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4643 #ifdef RDBSS_TRACKER
4644 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4647 /* And post the request */
4648 Status
= RxFsdPostRequest(RxContext
);
4654 /* Update FILE_OBJECT if synchronous write succeed */
4657 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4659 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4663 /* If write succeed, ,also update FILE_OBJECT flags */
4664 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4666 /* File was modified */
4669 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4672 /* If was even extended */
4675 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4678 /* If VDL was extended, update FCB and inform Cc */
4679 if (ExtendingValidData
)
4681 LONGLONG LastOffset
;
4683 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4684 if (FileSize
< LastOffset
)
4686 LastOffset
= FileSize
;
4689 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4691 if (NoCache
&& CcIsFileCached(FileObject
))
4693 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4702 /* Finally, if we failed while extension was required */
4703 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4708 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4710 RxAcquirePagingIoResource(RxContext
, Fcb
);
4711 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4712 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4713 RxReleasePagingIoResource(RxContext
, Fcb
);
4715 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4717 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4722 /* One async write less */
4723 if (UnwindOutstandingAsync
)
4727 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4728 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4731 /* And now, cleanup everything */
4732 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4734 /* If we didn't post, release every lock (for posting, it's already done) */
4737 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4740 /* If the context was referenced - posting, dereference it */
4741 if (ContextReferenced
)
4743 RxDereferenceAndDeleteRxContext(RxContext
);
4746 /* If that's a pipe operation, resume any blocked one */
4749 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4751 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4755 /* Sanity check for write */
4756 if (Status
== STATUS_SUCCESS
)
4758 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4761 /* Just dereference our context */
4765 RxDereferenceAndDeleteRxContext(RxContext
);
4770 #undef _SEH2_TRY_RETURN
4781 IN PRX_CONTEXT RxContext
)
4784 PFILE_OBJECT FileObject
;
4785 PIO_STACK_LOCATION Stack
;
4787 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4791 Irp
= RxContext
->CurrentIrp
;
4792 Stack
= RxContext
->CurrentIrpSp
;
4793 FileObject
= Stack
->FileObject
;
4795 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4796 switch (RxContext
->MajorFunction
)
4798 /* Call the Cc function */
4800 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4804 /* If here, we can wait */
4805 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4807 /* Call the Cc function */
4808 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4810 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4814 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4815 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4820 Irp
->MdlAddress
= NULL
;
4822 /* And complete the IRP */
4823 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4825 #undef BugCheckFileId
4827 return STATUS_SUCCESS
;
4834 RxCopyCreateParameters(
4835 IN PRX_CONTEXT RxContext
)
4839 PFILE_OBJECT FileObject
;
4840 PIO_STACK_LOCATION Stack
;
4841 PDFS_NAME_CONTEXT DfsNameContext
;
4842 PIO_SECURITY_CONTEXT SecurityContext
;
4844 Irp
= RxContext
->CurrentIrp
;
4845 Stack
= RxContext
->CurrentIrpSp
;
4846 FileObject
= Stack
->FileObject
;
4847 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4849 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4850 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4852 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4853 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4854 RxContext
->Create
.SdLength
);
4856 if (SecurityContext
->SecurityQos
!= NULL
)
4858 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4862 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4864 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4866 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4867 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4868 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4869 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4870 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4872 DfsContext
= FileObject
->FsContext2
;
4873 DfsNameContext
= FileObject
->FsContext
;
4874 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4875 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4876 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4877 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4878 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4879 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4880 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4881 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4882 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4883 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4884 FileObject
->FsContext2
= NULL
;
4885 FileObject
->FsContext
= NULL
;
4887 RxContext
->pFcb
= NULL
;
4888 RxContext
->Create
.ReturnedCreateInformation
= 0;
4890 /* if we stripped last \, it has to be a directory! */
4891 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4893 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4896 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4897 if (RxContext
->Create
.EaLength
== 0)
4899 RxContext
->Create
.EaBuffer
= NULL
;
4903 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4904 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4909 RxCreateFromNetRoot(
4910 PRX_CONTEXT Context
,
4911 PUNICODE_STRING NetRootName
)
4916 PFILE_OBJECT FileObject
;
4917 PIO_STACK_LOCATION Stack
;
4918 ACCESS_MASK DesiredAccess
;
4919 USHORT DesiredShareAccess
;
4923 /* Validate that the context is consistent */
4924 if (Context
->Create
.pNetRoot
== NULL
)
4926 return STATUS_BAD_NETWORK_PATH
;
4929 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
4930 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
4932 return STATUS_BAD_NETWORK_PATH
;
4935 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
4936 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
4938 return STATUS_DFS_UNAVAILABLE
;
4941 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
4942 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
4944 return STATUS_OBJECT_TYPE_MISMATCH
;
4947 Stack
= Context
->CurrentIrpSp
;
4948 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4949 if (NetRoot
->Type
== NET_ROOT_PRINT
)
4951 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
4954 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
4956 /* We don't support renaming yet */
4957 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
4960 return STATUS_NOT_IMPLEMENTED
;
4963 /* Try to find (or create) the FCB for the file */
4964 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
4965 Fcb
= (PFCB
)Context
->pFcb
;
4968 ASSERT(!NT_SUCCESS(Status
));
4970 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
4975 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
4977 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
4981 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
4984 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4985 if (NT_SUCCESS(Status
))
4987 RxTransitionNetFcb(Fcb
, Condition_Good
);
4988 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
4990 RxSetupNetFileObject(Context
);
4991 return STATUS_SUCCESS
;
4995 FileObject
= Stack
->FileObject
;
4996 /* Check SA for conflict */
4997 if (Fcb
->OpenCount
> 0)
4999 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5000 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
5001 if (!NT_SUCCESS(Status
))
5003 RxDereferenceNetFcb(Fcb
);
5008 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
5009 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
5016 /* Find a SRV_OPEN that suits the opening */
5017 Status
= RxCollapseOrCreateSrvOpen(Context
);
5018 if (Status
== STATUS_SUCCESS
)
5023 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
5024 Fobx
= (PFOBX
)Context
->pFobx
;
5025 /* There are already opens, check for conflict */
5026 if (Fcb
->OpenCount
!= 0)
5028 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
5029 FileObject
, &Fcb
->ShareAccess
,
5030 FALSE
, "second check per useropens",
5033 ++SrvOpen
->UncleanFobxCount
;
5034 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
5041 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
5043 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5044 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
5048 RxSetupNetFileObject(Context
);
5050 /* No conflict? Set up SA */
5051 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
5053 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
5056 ++Fcb
->UncleanCount
;
5057 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
5059 ++Fcb
->UncachedUncleanCount
;
5062 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
5063 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
5065 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
5068 /* No pending close, we're active */
5069 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
5072 ++SrvOpen
->UncleanFobxCount
;
5073 ++SrvOpen
->OpenCount
;
5074 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
5076 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
5078 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
5079 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
5081 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
5082 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
5084 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5087 /* Now, update SA for the SRV_OPEN */
5088 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
5090 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
5092 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
5095 /* Update the FOBX info */
5098 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5100 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
5103 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
5104 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5106 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
5108 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
5109 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
5111 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
5112 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
5113 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
5115 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
5116 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
5120 Status
= STATUS_SUCCESS
;
5125 if (Fcb
->OpenCount
== 0)
5127 if (Context
->Create
.FcbAcquired
)
5129 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
5133 if (!Context
->Create
.FcbAcquired
)
5135 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
5141 RxDereferenceNetFcb(Fcb
);
5153 RxCreateTreeConnect(
5154 IN PRX_CONTEXT RxContext
)
5157 PV_NET_ROOT VNetRoot
;
5158 PFILE_OBJECT FileObject
;
5159 PIO_STACK_LOCATION Stack
;
5160 NET_ROOT_TYPE NetRootType
;
5161 UNICODE_STRING CanonicalName
, RemainingName
;
5165 Stack
= RxContext
->CurrentIrpSp
;
5166 FileObject
= Stack
->FileObject
;
5168 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
5169 /* As long as we don't know connection type, mark it wild */
5170 NetRootType
= NET_ROOT_WILD
;
5171 /* Get the type by parsing the name */
5172 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
5173 if (!NT_SUCCESS(Status
))
5178 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
5179 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
5180 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
5181 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
5182 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
5183 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
5185 /* We don't handle EA - they come from DFS, don't care */
5186 if (Stack
->Parameters
.Create
.EaLength
> 0)
5191 /* Mount if required */
5192 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5193 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
5195 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
5196 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5199 if (!NT_SUCCESS(Status
))
5204 /* Validate the rest of the name with mini-rdr */
5205 if (RemainingName
.Length
> 0)
5207 MINIRDR_CALL(Status
, RxContext
,
5208 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5209 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
5212 if (!NT_SUCCESS(Status
))
5217 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5218 RxReferenceVNetRoot(VNetRoot
);
5219 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
5221 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
5224 FileObject
->FsContext
= &RxDeviceFCB
;
5225 FileObject
->FsContext2
= VNetRoot
;
5227 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
5228 ++VNetRoot
->NumberOfOpens
;
5230 /* Create is over - clear context */
5231 RxContext
->Create
.pSrvCall
= NULL
;
5232 RxContext
->Create
.pNetRoot
= NULL
;
5233 RxContext
->Create
.pVNetRoot
= NULL
;
5240 RxDebugControlCommand(
5241 _In_ PSTR ControlString
)
5249 IN PDRIVER_OBJECT DriverObject
,
5250 IN PUNICODE_STRING RegistryPath
)
5253 USHORT i
, State
= 0;
5255 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
5259 RxCheckFcbStructuresForAlignment();
5261 RtlZeroMemory(&RxData
, sizeof(RxData
));
5262 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
5263 RxData
.NodeByteSize
= sizeof(RxData
);
5264 RxData
.DriverObject
= DriverObject
;
5266 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
5267 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
5268 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5270 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5271 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5273 RxInitializeDebugSupport();
5275 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5276 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5281 RxGetRegistryParameters(RegistryPath
);
5282 RxReadRegistryParameters();
5284 Status
= RxInitializeRegistrationStructures();
5285 if (!NT_SUCCESS(Status
))
5291 RxInitializeDispatcher();
5293 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5295 InitializeListHead(&RxIrpsList
);
5296 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5298 InitializeListHead(&RxActiveContexts
);
5299 InitializeListHead(&RxSrvCalldownList
);
5301 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5302 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5303 KeInitializeMutex(&RxScavengerMutex
, 1);
5304 KeInitializeMutex(&RxSerializationMutex
, 1);
5306 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5308 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5309 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5310 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5313 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5315 RxInitializeDispatchVectors(DriverObject
);
5317 ExInitializeResourceLite(&RxData
.Resource
);
5318 RxData
.OurProcess
= IoGetCurrentProcess();
5320 RxInitializeRxTimer();
5324 if (!NT_SUCCESS(Status
))
5326 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5327 RxInitUnwind(DriverObject
, State
);
5331 /* There are still bits to init - be consider it's fine for now */
5334 return STATUS_NOT_IMPLEMENTED
;
5336 return STATUS_SUCCESS
;
5344 RxDumpCurrentAccess(
5347 _In_ PSZ wherelogtag
,
5348 _In_ PSHARE_ACCESS ShareAccess
)
5360 _In_ PSZ wherelogtag
,
5361 _In_ ACCESS_MASK DesiredAccess
,
5362 _In_ ULONG DesiredShareAccess
)
5372 RxFastIoCheckIfPossible(
5373 PFILE_OBJECT FileObject
,
5374 PLARGE_INTEGER FileOffset
,
5375 ULONG Length
, BOOLEAN Wait
,
5376 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5377 PIO_STATUS_BLOCK IoStatus
,
5378 PDEVICE_OBJECT DeviceObject
)
5382 LARGE_INTEGER LargeLength
;
5386 /* Get the FCB to validate it */
5387 Fcb
= FileObject
->FsContext
;
5388 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5390 DPRINT1("Not a file, FastIO not possible!\n");
5394 if (FileObject
->DeletePending
)
5396 DPRINT1("File delete pending\n");
5400 /* If there's a pending write operation, deny fast operation */
5401 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5403 DPRINT1("Write operations to be completed\n");
5407 /* Deny read on orphaned node */
5408 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5409 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5411 DPRINT1("SRV_OPEN orphaned\n");
5415 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5417 DPRINT1("FCB orphaned\n");
5421 /* If there's a buffering state change pending, deny fast operation (it might change
5424 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5426 DPRINT1("Buffering change pending\n");
5430 /* File got renamed/deleted, deny operation */
5431 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5432 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5434 DPRINT1("File renamed/deleted\n");
5438 /* Process pending change buffering state operations */
5439 FsRtlEnterFileSystem();
5440 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5441 FsRtlExitFileSystem();
5443 LargeLength
.QuadPart
= Length
;
5445 /* If operation to come is a read operation */
5446 if (CheckForReadOperation
)
5448 /* Check that read cache is enabled */
5449 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5451 DPRINT1("Read caching disabled\n");
5455 /* Check whether there's a lock conflict */
5456 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5461 PsGetCurrentProcess()))
5463 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5470 /* Check that write cache is enabled */
5471 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
))
5473 DPRINT1("Write caching disabled\n");
5477 /* Check whether there's a lock conflict */
5478 if (!FsRtlFastCheckLockForWrite(&Fcb
->Specific
.Fcb
.FileLock
,
5483 PsGetCurrentProcess()))
5485 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5494 RxFastIoDeviceControl(
5495 PFILE_OBJECT FileObject
,
5497 PVOID InputBuffer OPTIONAL
,
5498 ULONG InputBufferLength
,
5499 PVOID OutputBuffer OPTIONAL
,
5500 ULONG OutputBufferLength
,
5501 ULONG IoControlCode
,
5502 PIO_STATUS_BLOCK IoStatus
,
5503 PDEVICE_OBJECT DeviceObject
)
5505 /* Only supported IOCTL */
5506 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5523 PFILE_OBJECT FileObject
,
5524 PLARGE_INTEGER FileOffset
,
5529 PIO_STATUS_BLOCK IoStatus
,
5530 PDEVICE_OBJECT DeviceObject
)
5533 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5537 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5538 FileObject
->FsContext2
);
5539 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5541 /* Prepare a TLI context */
5542 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5543 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5544 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5546 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5547 IoStatus
, DeviceObject
, &TopLevelContext
);
5550 DPRINT("Read OK\n");
5554 DPRINT1("Read failed!\n");
5566 PFILE_OBJECT FileObject
,
5567 PLARGE_INTEGER FileOffset
,
5572 PIO_STATUS_BLOCK IoStatus
,
5573 PDEVICE_OBJECT DeviceObject
)
5577 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5581 Fobx
= (PFOBX
)FileObject
->FsContext2
;
5582 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_BAD_HANDLE
))
5587 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5588 FileObject
->FsContext2
);
5589 DPRINT("Writing %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5591 /* Prepare a TLI context */
5592 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5593 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5594 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5596 Ret
= FsRtlCopyWrite2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5597 IoStatus
, DeviceObject
, &TopLevelContext
);
5600 DPRINT("Write OK\n");
5604 DPRINT1("Write failed!\n");
5612 PRX_CONTEXT RxContext
,
5613 PUNICODE_STRING NetRootName
)
5619 PV_NET_ROOT VNetRoot
;
5620 BOOLEAN TableAcquired
, AcquiredExclusive
;
5624 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5625 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5626 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5628 Status
= STATUS_SUCCESS
;
5629 AcquiredExclusive
= FALSE
;
5631 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5632 TableAcquired
= TRUE
;
5633 Version
= NetRoot
->FcbTable
.Version
;
5635 /* Look for a cached FCB */
5636 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5639 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5643 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5644 /* If FCB was to be orphaned, consider it as not suitable */
5645 if (Fcb
->fShouldBeOrphaned
)
5647 RxDereferenceNetFcb(Fcb
);
5648 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5650 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5651 TableAcquired
= TRUE
;
5652 AcquiredExclusive
= TRUE
;
5654 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5655 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5657 RxOrphanThisFcb(Fcb
);
5658 RxDereferenceNetFcb(Fcb
);
5664 /* If FCB was not found or is not covering full path, prepare for more work */
5665 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5667 if (!AcquiredExclusive
)
5669 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5670 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5671 TableAcquired
= TRUE
;
5674 /* If FCB table was updated in between, re-attempt a lookup */
5675 if (NetRoot
->FcbTable
.Version
!= Version
)
5677 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5678 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5685 /* Allocate the FCB */
5690 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5693 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5697 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5698 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5704 if (_SEH2_AbnormalTermination())
5706 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5707 TableAcquired
= FALSE
;
5711 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5713 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5714 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5716 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5725 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5728 if (!NT_SUCCESS(Status
))
5733 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5734 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5736 if (!RxContext
->Create
.FcbAcquired
)
5738 RxWaitForStableNetFcb(Fcb
, RxContext
);
5739 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5740 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5747 RxFirstCanonicalize(
5748 PRX_CONTEXT RxContext
,
5749 PUNICODE_STRING FileName
,
5750 PUNICODE_STRING CanonicalName
,
5751 PNET_ROOT_TYPE NetRootType
)
5755 BOOLEAN UncName
, PrependString
, IsSpecial
;
5756 USHORT CanonicalLength
;
5757 UNICODE_STRING SessionIdString
;
5758 WCHAR SessionIdBuffer
[16];
5762 Type
= NET_ROOT_WILD
;
5763 PrependString
= FALSE
;
5766 Status
= STATUS_SUCCESS
;
5768 /* Name has to contain at least \\ */
5769 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5771 return STATUS_OBJECT_NAME_INVALID
;
5774 /* First easy check, is that a path with a name? */
5775 CanonicalLength
= FileName
->Length
;
5776 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5778 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5780 if (FileName
->Buffer
[3] == ':')
5782 Type
= NET_ROOT_DISK
;
5786 Type
= NET_ROOT_PRINT
;
5791 /* Nope, attempt deeper parsing */
5792 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5795 PWSTR FirstSlash
, EndOfString
;
5797 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5800 /* The lack of drive letter will be replaced by session ID */
5801 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5802 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5803 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5805 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5806 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5808 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5814 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5816 Status
= STATUS_OBJECT_NAME_INVALID
;
5821 DPRINT1("WARNING: Assuming not special + disk!\n");
5822 Type
= NET_ROOT_DISK
;
5823 Status
= STATUS_SUCCESS
;
5824 //Status = STATUS_NOT_IMPLEMENTED;
5825 /* Should be check against IPC, mailslot, and so on */
5829 /* Update net root type with our deduced one */
5830 *NetRootType
= Type
;
5831 DPRINT("Returning type: %x\n", Type
);
5833 if (!NT_SUCCESS(Status
))
5838 /* Do we have to prepend session ID? */
5843 PrependString
= TRUE
;
5844 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5848 /* If not UNC path, we should preprend stuff */
5849 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5851 return STATUS_OBJECT_PATH_INVALID
;
5854 /* Allocate the buffer */
5855 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
5856 if (!NT_SUCCESS(Status
))
5861 /* We don't support that case, we always return disk */
5864 ASSERT(CanonicalName
->Length
== CanonicalLength
);
5866 Status
= STATUS_NOT_IMPLEMENTED
;
5870 /* If we have to prepend, go ahead */
5873 CanonicalName
->Buffer
[0] = '\\';
5874 CanonicalName
->Buffer
[1] = ';';
5875 CanonicalName
->Buffer
[2] = ':';
5876 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
5877 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
5878 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
5880 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
5882 /* Otherwise, that's a simple copy */
5885 RtlCopyUnicodeString(CanonicalName
, FileName
);
5896 RxFreeCanonicalNameBuffer(
5897 PRX_CONTEXT Context
)
5899 /* These two buffers are always the same */
5900 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
5902 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
5904 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
5905 Context
->Create
.CanonicalNameBuffer
= NULL
;
5906 Context
->AlsoCanonicalNameBuffer
= NULL
;
5909 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
5913 RxFsdCommonDispatch(
5914 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
5915 UCHAR MajorFunction
,
5916 PIO_STACK_LOCATION Stack
,
5917 PFILE_OBJECT FileObject
,
5919 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
5923 PRX_CONTEXT Context
;
5924 UCHAR MinorFunction
;
5925 PFILE_OBJECT StackFileObject
;
5926 PRX_FSD_DISPATCH DispatchFunc
;
5927 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5928 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
5930 Status
= STATUS_SUCCESS
;
5932 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
5934 FsRtlEnterFileSystem();
5936 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
5942 PostRequest
= FALSE
;
5943 SetCancelRoutine
= TRUE
;
5944 MinorFunction
= Stack
->MinorFunction
;
5946 switch (MajorFunction
)
5948 case IRP_MJ_FILE_SYSTEM_CONTROL
:
5949 if (FileObject
!= NULL
)
5951 CanWait
= IoIsOperationSynchronous(Irp
);
5961 case IRP_MJ_QUERY_INFORMATION
:
5962 case IRP_MJ_SET_INFORMATION
:
5963 case IRP_MJ_QUERY_EA
:
5965 case IRP_MJ_FLUSH_BUFFERS
:
5966 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
5967 case IRP_MJ_SET_VOLUME_INFORMATION
:
5968 case IRP_MJ_DIRECTORY_CONTROL
:
5969 case IRP_MJ_DEVICE_CONTROL
:
5970 case IRP_MJ_LOCK_CONTROL
:
5971 case IRP_MJ_QUERY_SECURITY
:
5972 case IRP_MJ_SET_SECURITY
:
5973 CanWait
= IoIsOperationSynchronous(Irp
);
5977 case IRP_MJ_CLEANUP
:
5979 SetCancelRoutine
= FALSE
;
5986 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
5987 /* Should we stop it right now, or mini-rdr deserves to know? */
5988 PassToDriver
= TRUE
;
5989 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
5991 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
5993 PassToDriver
= FALSE
;
5994 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
5995 DPRINT1("Not started!\n");
6000 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
6002 PassToDriver
= FALSE
;
6003 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6004 DPRINT1("Not started!\n");
6007 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
6009 StackFileObject
= Stack
->FileObject
;
6010 /* Make sure we don't deal with orphaned stuff */
6011 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
6013 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
6014 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
6015 StackFileObject
->FsContext
!= &RxDeviceFCB
)
6020 Fcb
= StackFileObject
->FsContext
;
6021 Fobx
= StackFileObject
->FsContext2
;
6023 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
6024 BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
6028 PassToDriver
= TRUE
;
6032 PassToDriver
= FALSE
;
6033 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
6034 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
6040 /* Did we receive a close request whereas we're stopping? */
6041 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
6045 Fcb
= StackFileObject
->FsContext
;
6047 DPRINT1("Close received after stop\n");
6048 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6049 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
6051 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
6054 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6055 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
6059 /* Should we stop the whole thing now? */
6062 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
6064 IoMarkIrpPending(Irp
);
6065 Irp
->IoStatus
.Status
= Status
;
6066 Irp
->IoStatus
.Information
= 0;
6067 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6068 Status
= STATUS_PENDING
;
6072 Irp
->IoStatus
.Status
= Status
;
6073 Irp
->IoStatus
.Information
= 0;
6074 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6080 /* No? Allocate a context to deal with the mini-rdr */
6081 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
6082 if (Context
== NULL
)
6084 Status
= STATUS_INSUFFICIENT_RESOURCES
;
6085 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
6089 /* Set cancel routine if required */
6090 if (SetCancelRoutine
)
6092 IoAcquireCancelSpinLock(&OldIrql
);
6093 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
6097 IoAcquireCancelSpinLock(&OldIrql
);
6098 IoSetCancelRoutine(Irp
, NULL
);
6100 IoReleaseCancelSpinLock(OldIrql
);
6102 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6104 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6105 Irp
->IoStatus
.Information
= 0;
6106 /* Get the dispatch routine */
6107 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
6109 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
6111 /* Handle the complete MDL case */
6112 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
6114 DispatchFunc
= RxCompleteMdl
;
6118 /* Do we have to post request? */
6119 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
6125 /* Our read function needs stack, make sure we won't overflow,
6126 * otherwise, post the request
6128 if (MajorFunction
== IRP_MJ_READ
)
6130 if (IoGetRemainingStackSize() < 0xE00)
6132 Context
->PendingReturned
= TRUE
;
6133 Status
= RxPostStackOverflowRead(Context
);
6134 if (Status
!= STATUS_PENDING
)
6136 Context
->PendingReturned
= FALSE
;
6137 RxCompleteAsynchronousRequest(Context
, Status
);
6147 Context
->ResumeRoutine
= DispatchFunc
;
6148 /* There's a dispatch routine? Time to dispatch! */
6149 if (DispatchFunc
!= NULL
)
6151 Context
->PendingReturned
= TRUE
;
6154 Status
= RxFsdPostRequest(Context
);
6158 /* Retry as long as we have */
6161 Status
= DispatchFunc(Context
);
6163 while (Status
== STATUS_RETRY
);
6165 if (Status
== STATUS_PENDING
)
6170 /* Sanity check: did someone mess with our context? */
6171 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
6172 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
6174 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
6175 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
6176 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
6177 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
6178 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
6180 Context
->PendingReturned
= FALSE
;
6181 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
6186 Status
= STATUS_NOT_IMPLEMENTED
;
6193 RxUnwindTopLevelIrp(&TopLevelContext
);
6196 FsRtlExitFileSystem();
6200 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
6210 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
6214 PIO_STACK_LOCATION Stack
;
6215 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
6219 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
6221 Stack
= IoGetCurrentIrpStackLocation(Irp
);
6223 /* Dispatch easy case */
6224 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
6226 return RxSystemControl(RxDeviceObject
, Irp
);
6229 /* Bail out broken cases */
6230 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
6231 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
6233 IoMarkIrpPending(Irp
);
6234 Irp
->IoStatus
.Information
= 0;
6235 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
6236 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6237 return STATUS_PENDING
;
6240 /* Immediately handle create */
6241 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
6243 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6246 /* If not a creation, we must have at least a FO with a FCB */
6247 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
6249 IoMarkIrpPending(Irp
);
6250 Irp
->IoStatus
.Information
= 0;
6251 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6252 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6253 return STATUS_PENDING
;
6256 /* Set the dispatch vector if required */
6257 Fcb
= Stack
->FileObject
->FsContext
;
6258 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
6260 DispatchVector
= &RxFsdDispatchVector
[0];
6264 DispatchVector
= Fcb
->PrivateDispatchVector
;
6267 /* Device cannot accept such requests */
6268 if (RxDeviceObject
== RxFileSystemDeviceObject
)
6270 IoMarkIrpPending(Irp
);
6271 Irp
->IoStatus
.Information
= 0;
6272 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6273 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6274 return STATUS_PENDING
;
6277 /* Dispatch for real! */
6278 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6286 IN PRX_CONTEXT RxContext
)
6288 /* Initialize posting if required */
6289 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
6291 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
6294 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6295 RxContext
->MinorFunction
, RxContext
,
6296 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6297 RxContext
->SerialNumber
);
6299 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
6300 return STATUS_PENDING
;
6312 WORK_QUEUE_TYPE Queue
;
6313 PRDBSS_DEVICE_OBJECT VolumeDO
;
6314 PRX_CONTEXT RxContext
, EntryContext
;
6318 RxContext
= Context
;
6319 EntryContext
= Context
;
6320 /* Save IRQL at entry for later checking */
6321 EntryIrql
= KeGetCurrentIrql();
6323 /* No FO, deal with device */
6324 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6326 VolumeDO
= RxFileSystemDeviceObject
;
6333 /* Which queue to used for delayed? */
6334 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6336 Queue
= DelayedWorkQueue
;
6340 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6341 Queue
= CriticalWorkQueue
;
6348 BOOLEAN RecursiveCall
;
6349 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6351 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6352 ASSERT(!RxContext
->PostRequest
);
6354 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6355 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6357 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx", RxContext
->MinorFunction
,
6358 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6359 RxContext
->SerialNumber
);
6361 Irp
= RxContext
->CurrentIrp
;
6363 FsRtlEnterFileSystem();
6365 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6366 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6367 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6368 RxContext
->RxDeviceObject
, TRUE
);
6370 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6372 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6374 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6375 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6378 /* Call the resume routine */
6383 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6385 Status
= RxContext
->ResumeRoutine(RxContext
);
6386 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6388 if (Status
!= STATUS_RETRY
)
6390 Status
= RxCompleteRequest(RxContext
, Status
);
6394 while (Status
== STATUS_RETRY
);
6396 RxUnwindTopLevelIrp(&TopLevelContext
);
6397 FsRtlExitFileSystem();
6399 if (VolumeDO
!= NULL
)
6401 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6407 } while (RxContext
!= NULL
);
6409 /* Did we mess with IRQL? */
6410 if (KeGetCurrentIrql() >= APC_LEVEL
)
6412 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6420 RxGetNetworkProviderPriority(
6421 PUNICODE_STRING DeviceName
)
6432 RxGetRegistryParameters(
6433 IN PUNICODE_STRING RegistryPath
)
6437 UCHAR Buffer
[0x400];
6438 HANDLE DriverHandle
, KeyHandle
;
6439 UNICODE_STRING KeyName
, OutString
;
6440 OBJECT_ATTRIBUTES ObjectAttributes
;
6444 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6445 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6446 if (!NT_SUCCESS(Status
))
6451 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6452 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6453 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6454 if (NT_SUCCESS(Status
))
6456 /* The only parameter we deal with is InitialDebugString */
6457 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6458 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6463 Read
= OutString
.Buffer
;
6464 Write
= (PSTR
)OutString
.Buffer
;
6465 for (i
= 0; i
< OutString
.Length
; ++i
)
6473 /* Which is a string we'll just write out */
6474 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6475 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6481 ZwClose(DriverHandle
);
6489 IN PIO_STACK_LOCATION IrpSp
)
6492 PACCESS_TOKEN Token
;
6493 PIO_SECURITY_CONTEXT SecurityContext
;
6497 /* If that's not a prefix claim, not an open request, session id will be 0 */
6498 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6500 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6505 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6509 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6512 /* Query the session id */
6513 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6514 SeQuerySessionIdToken(Token
, &SessionId
);
6524 RxGetStringRegistryParameter(
6525 IN HANDLE KeyHandle
,
6527 OUT PUNICODE_STRING OutString
,
6529 IN ULONG BufferLength
,
6530 IN BOOLEAN LogFailure
)
6534 UNICODE_STRING KeyString
;
6538 RtlInitUnicodeString(&KeyString
, KeyName
);
6539 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6540 OutString
->Length
= 0;
6541 OutString
->Buffer
= 0;
6542 if (!NT_SUCCESS(Status
))
6546 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6552 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6553 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6554 OutString
->MaximumLength
= OutString
->Length
;
6556 return STATUS_SUCCESS
;
6562 PRDBSS_DEVICE_OBJECT
6563 RxGetTopDeviceObjectIfRdbssIrp(
6567 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6569 TopLevelIrp
= IoGetTopLevelIrp();
6570 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6572 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6582 RxGetTopIrpIfRdbssIrp(
6586 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6588 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6589 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6591 Irp
= TopLevel
->Irp
;
6602 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6605 PACCESS_TOKEN Token
;
6609 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6610 SeQueryAuthenticationIdToken(Token
, &Luid
);
6617 RxIndicateChangeOfBufferingStateForSrvOpen(
6618 PMRX_SRV_CALL SrvCall
,
6619 PMRX_SRV_OPEN SrvOpen
,
6628 RxInitializeDebugSupport(
6639 RxInitializeDispatchVectors(
6640 PDRIVER_OBJECT DriverObject
)
6646 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6648 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6651 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6652 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6653 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6655 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6656 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6657 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6658 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6659 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6660 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6661 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6662 RxFastIoDispatch
.FastIoLock
= NULL
;
6663 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6664 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6665 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6666 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6667 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6668 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6669 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6670 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6672 RxInitializeTopLevelIrpPackage();
6674 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6675 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6676 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6677 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6679 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6680 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6681 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6682 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6691 return STATUS_NOT_IMPLEMENTED
;
6698 RxInitializeMinirdrDispatchTable(
6699 IN PDRIVER_OBJECT DriverObject
)
6709 RxInitializeRegistrationStructures(
6714 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6715 RxData
.NumberOfMinirdrsRegistered
= 0;
6716 RxData
.NumberOfMinirdrsStarted
= 0;
6717 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6719 return STATUS_SUCCESS
;
6727 RxInitializeTopLevelIrpPackage(
6730 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6731 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6737 PDRIVER_OBJECT DriverObject
,
6747 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6748 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6751 PLIST_ENTRY NextEntry
;
6752 BOOLEAN Found
= FALSE
;
6753 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6755 /* Browse all the allocated TLC to find ours */
6756 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6757 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6758 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6759 NextEntry
= NextEntry
->Flink
)
6761 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6762 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6763 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6766 if (ListContext
== TopLevelContext
)
6772 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6786 /* No associated SRV_OPEN, it's OK to purge */
6787 if (IsListEmpty(&Fcb
->SrvOpenList
))
6792 /* Only allow to purge if all the associated SRV_OPEN
6793 * - have no outstanding opens ongoing
6794 * - have only read attribute set
6796 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6797 Entry
!= &Fcb
->SrvOpenList
;
6798 Entry
= Entry
->Flink
)
6802 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6804 /* Failing previous needs, don't allow purge */
6805 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6806 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6812 /* All correct, allow purge */
6820 RxIsThisAnRdbssTopLevelContext(
6821 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6823 ULONG_PTR StackTop
, StackBottom
;
6825 /* Bail out for flags */
6826 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6831 /* Is our provided TLC allocated on stack? */
6832 IoGetStackLimits(&StackTop
, &StackBottom
);
6833 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6834 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6836 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6837 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6845 /* No, use the helper function */
6846 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6853 RxIsThisTheTopLevelIrp(
6858 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6859 TopLevelIrp
= IoGetTopLevelIrp();
6860 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6862 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
6865 return (TopLevelIrp
== Irp
);
6870 RxLockOperationCompletion(
6875 return STATUS_NOT_IMPLEMENTED
;
6884 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6885 IN PUNICODE_STRING OriginatorId
,
6890 PUNICODE_STRING Originator
= OriginatorId
;
6891 LARGE_INTEGER LargeLine
;
6893 /* Set optional parameters */
6894 LargeLine
.QuadPart
= Line
;
6895 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
6897 Originator
= (PUNICODE_STRING
)&unknownId
;
6901 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
6906 RxLogEventWithAnnotation(
6907 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6910 IN PVOID DataBuffer
,
6911 IN USHORT DataBufferLength
,
6912 IN PUNICODE_STRING Annotation
,
6913 IN ULONG AnnotationCount
)
6921 PRX_CONTEXT RxContext
)
6924 return STATUS_NOT_IMPLEMENTED
;
6932 RxLowIoIoCtlShellCompletion(
6933 PRX_CONTEXT RxContext
)
6940 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
6942 Irp
= RxContext
->CurrentIrp
;
6943 Status
= RxContext
->IoStatusBlock
.Status
;
6945 /* Set information and status */
6946 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
6948 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6951 Irp
->IoStatus
.Status
= Status
;
6957 RxLowIoLockControlShell(
6958 IN PRX_CONTEXT RxContext
)
6961 return STATUS_NOT_IMPLEMENTED
;
6969 RxLowIoNotifyChangeDirectoryCompletion(
6970 PRX_CONTEXT RxContext
)
6974 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
6976 /* Just copy back the IO_STATUS to the IRP */
6977 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
6978 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
6980 return RxContext
->IoStatusBlock
.Status
;
6988 PRX_CONTEXT RxContext
)
6995 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
6997 Fcb
= (PFCB
)RxContext
->pFcb
;
6998 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7000 return STATUS_MORE_PROCESSING_REQUIRED
;
7003 /* Always update stats for disks */
7004 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7006 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7009 /* And forward the read to the mini-rdr */
7010 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
7011 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
7018 RxLowIoReadShellCompletion(
7019 PRX_CONTEXT RxContext
)
7024 BOOLEAN PagingIo
, IsPipe
;
7025 PIO_STACK_LOCATION Stack
;
7026 PLOWIO_CONTEXT LowIoContext
;
7030 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
7032 Status
= RxContext
->IoStatusBlock
.Status
;
7033 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7035 Irp
= RxContext
->CurrentIrp
;
7036 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7038 /* Set IRP information from the RX_CONTEXT status block */
7039 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7041 /* Fixup status for paging file if nothing was read */
7044 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
7046 Status
= STATUS_END_OF_FILE
;
7050 LowIoContext
= &RxContext
->LowIoContext
;
7051 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7053 /* Check broken cases that should never happen */
7054 Fcb
= (PFCB
)RxContext
->pFcb
;
7055 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
7057 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
7060 return STATUS_RETRY
;
7063 else if (Status
== STATUS_SUCCESS
)
7065 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
7067 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
7068 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
7074 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7080 /* Readahead should go through Cc and not finish here */
7081 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
7083 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7084 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7089 Stack
= RxContext
->CurrentIrpSp
;
7090 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
7091 /* Release lock if required */
7094 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7098 /* Set FastIo if read was a success */
7099 if (NT_SUCCESS(Status
) && !IsPipe
)
7101 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
7104 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7106 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
7110 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7119 /* Final sanity checks */
7120 ASSERT(Status
!= STATUS_RETRY
);
7121 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
7122 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
7132 IN PRX_CONTEXT RxContext
)
7139 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
7141 Fcb
= (PFCB
)RxContext
->pFcb
;
7143 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7144 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7146 /* Always update stats for disks */
7147 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7149 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7152 /* And forward the write to the mini-rdr */
7153 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
7154 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
7161 RxLowIoWriteShellCompletion(
7162 PRX_CONTEXT RxContext
)
7168 PLOWIO_CONTEXT LowIoContext
;
7172 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
7174 Status
= RxContext
->IoStatusBlock
.Status
;
7175 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7177 Irp
= RxContext
->CurrentIrp
;
7179 /* Set IRP information from the RX_CONTEXT status block */
7180 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7182 LowIoContext
= &RxContext
->LowIoContext
;
7183 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7185 /* Perform a few sanity checks */
7186 Fcb
= (PFCB
)RxContext
->pFcb
;
7187 if (Status
== STATUS_SUCCESS
)
7189 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
7191 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7192 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7195 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
7198 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7199 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
7201 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
7204 /* In case of async call, perform last bits not done in RxCommonWrite */
7205 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7207 PFILE_OBJECT FileObject
;
7208 PIO_STACK_LOCATION Stack
;
7210 /* We only succeed if we wrote what was asked for */
7211 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7213 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
7216 /* If write succeed, ,also update FILE_OBJECT flags */
7217 Stack
= RxContext
->CurrentIrpSp
;
7218 FileObject
= Stack
->FileObject
;
7221 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
7224 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
7226 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
7229 /* If VDL was extended, fix attributes */
7230 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
7232 LONGLONG LastOffset
, FileSize
;
7234 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
7235 Irp
->IoStatus
.Information
;
7236 RxGetFileSizeWithLock(Fcb
, &FileSize
);
7238 if (FileSize
< LastOffset
)
7240 LastOffset
= FileSize
;
7243 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
7246 /* One less outstanding write */
7247 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7249 PNON_PAGED_FCB NonPagedFcb
;
7251 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
7252 if (NonPagedFcb
!= NULL
)
7254 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
7255 -1, &RxStrucSupSpinLock
) == 1)
7257 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
7262 /* Release paging resource if acquired */
7263 if (RxContext
->FcbPagingIoResourceAcquired
)
7265 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7268 /* Resume blocked operations for pipes */
7269 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7271 RxResumeBlockedOperations_Serially(RxContext
,
7272 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
7276 /* And release FCB only for files */
7277 if (RxContext
->FcbResourceAcquired
)
7279 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7283 /* Final sanity checks */
7284 ASSERT(Status
!= STATUS_RETRY
);
7285 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
7286 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
7288 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7301 RxNotifyChangeDirectory(
7302 PRX_CONTEXT RxContext
)
7306 PIO_STACK_LOCATION Stack
;
7310 /* The IRP can abviously wait */
7311 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
7313 /* Initialize its lowio */
7314 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
7318 /* Lock user buffer */
7319 Stack
= RxContext
->CurrentIrpSp
;
7320 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
7322 /* Copy parameters from IO_STACK */
7323 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
7324 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7325 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7327 /* If we have an associated MDL */
7328 Irp
= RxContext
->CurrentIrp
;
7329 if (Irp
->MdlAddress
!= NULL
)
7331 /* Then, call mini-rdr */
7332 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7333 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7335 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7339 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7344 Status
= STATUS_INVALID_PARAMETER
;
7357 RxPostStackOverflowRead (
7358 IN PRX_CONTEXT RxContext
)
7363 return STATUS_NOT_IMPLEMENTED
;
7370 RxpPrepareCreateContextForReuse(
7371 PRX_CONTEXT RxContext
)
7373 /* Reuse can only happen for open operations (STATUS_RETRY) */
7374 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7376 /* Release the FCB if it was acquired */
7377 if (RxContext
->Create
.FcbAcquired
)
7379 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7380 RxContext
->Create
.FcbAcquired
= FALSE
;
7383 /* Free the canonical name */
7384 RxFreeCanonicalNameBuffer(RxContext
);
7386 /* If we have a VNetRoot associated */
7387 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7389 /* Remove our link and thus, dereference the VNetRoot */
7390 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7391 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7393 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7394 RxContext
->Create
.pVNetRoot
= NULL
;
7396 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7399 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7406 RxpQueryInfoMiniRdr(
7407 PRX_CONTEXT RxContext
,
7408 FILE_INFORMATION_CLASS FileInfoClass
,
7414 Fcb
= (PFCB
)RxContext
->pFcb
;
7416 /* Set the RX_CONTEXT */
7417 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7418 RxContext
->Info
.Buffer
= Buffer
;
7421 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7431 IN PRX_CONTEXT RxContext
)
7435 NET_ROOT_TYPE NetRootType
;
7436 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7440 Irp
= RxContext
->CurrentIrp
;
7442 /* This has to come from MUP */
7443 if (Irp
->RequestorMode
== UserMode
)
7445 return STATUS_INVALID_DEVICE_REQUEST
;
7448 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7450 PQUERY_PATH_REQUEST QueryRequest
;
7452 /* Get parameters */
7453 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7455 /* Don't overflow allocation */
7456 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7458 return STATUS_INVALID_DEVICE_REQUEST
;
7461 /* Forcefully rewrite IRP MJ */
7462 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7464 /* Fake canon name */
7465 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7466 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7468 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7472 /* Copy the prefix to look for */
7473 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7474 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7475 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7477 /* Zero the create parameters */
7478 RtlZeroMemory(&RxContext
->Create
.NtCreateParameters
,
7479 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7480 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7481 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7485 /* If not devcontrol, it comes from open, name was already copied */
7486 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7487 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7490 /* Canonilize name */
7491 NetRootType
= NET_ROOT_WILD
;
7492 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7493 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7494 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7495 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7496 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7497 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7498 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7499 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7500 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7501 if (NT_SUCCESS(Status
))
7503 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7505 if (Status
== STATUS_PENDING
)
7510 if (NT_SUCCESS(Status
))
7512 PQUERY_PATH_RESPONSE QueryResponse
;
7514 /* We accept the length that was canon (minus netroot) */
7515 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7516 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7520 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7521 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7523 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7525 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7528 RxpPrepareCreateContextForReuse(RxContext
);
7530 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7538 RxPrepareToReparseSymbolicLink(
7539 PRX_CONTEXT RxContext
,
7540 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7541 PUNICODE_STRING NewPath
,
7542 BOOLEAN NewPathIsAbsolute
,
7543 PBOOLEAN ReparseRequired
)
7546 return STATUS_NOT_IMPLEMENTED
;
7557 LOCK_OPERATION Lock
;
7558 PIO_STACK_LOCATION Stack
;
7559 PRX_CONTEXT RxContext
= Context
;
7561 /* NULL IRP is no option */
7567 /* Check whether preparation was really needed */
7568 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7572 /* Mark the context as prepared */
7573 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7575 /* Just lock the user buffer, with the correct length, depending on the MJ */
7576 Lock
= IoReadAccess
;
7577 Stack
= RxContext
->CurrentIrpSp
;
7578 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7580 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7582 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7584 Lock
= IoWriteAccess
;
7586 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7591 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7592 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7594 Lock
= IoWriteAccess
;
7595 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7597 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7599 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7603 /* As it will be posted (async), mark the IRP pending */
7604 IoMarkIrpPending(Irp
);
7612 PRX_CONTEXT RxContext
,
7613 FILE_INFORMATION_CLASS Class
)
7618 /* Initialize parameters in RX_CONTEXT */
7619 RxContext
->Info
.FileInformationClass
= Class
;
7620 RxContext
->Info
.Buffer
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
7621 RxContext
->Info
.Length
= RxContext
->CurrentIrpSp
->Parameters
.SetFile
.Length
;
7623 /* And call mini-rdr */
7624 Fcb
= (PFCB
)RxContext
->pFcb
;
7625 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
7632 RxpUnregisterMinirdr(
7633 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7644 PRX_CONTEXT LocalContext
)
7651 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7653 /* And force close */
7654 RxReleaseFcb(NULL
, Fcb
);
7655 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7656 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7657 ASSERT(Status
== STATUS_SUCCESS
);
7661 RxQueryAlternateNameInfo(
7662 PRX_CONTEXT RxContext
,
7663 PFILE_NAME_INFORMATION AltNameInfo
)
7666 return STATUS_NOT_IMPLEMENTED
;
7674 PRX_CONTEXT RxContext
,
7675 PFILE_BASIC_INFORMATION BasicInfo
)
7679 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7681 /* Simply zero and forward to mini-rdr */
7682 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7683 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7687 RxQueryCompressedInfo(
7688 PRX_CONTEXT RxContext
,
7689 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7692 return STATUS_NOT_IMPLEMENTED
;
7700 PRX_CONTEXT RxContext
)
7707 BOOLEAN LockNotGranted
;
7708 ULONG Length
, FileIndex
;
7709 PUNICODE_STRING FileName
;
7710 PIO_STACK_LOCATION Stack
;
7711 FILE_INFORMATION_CLASS FileInfoClass
;
7715 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7717 /* Get parameters */
7718 Stack
= RxContext
->CurrentIrpSp
;
7719 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7720 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7721 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7722 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7723 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7724 FileName
, FileInfoClass
);
7726 Irp
= RxContext
->CurrentIrp
;
7727 Flags
= Stack
->Flags
;
7728 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7729 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7731 if (FileName
!= NULL
)
7733 DPRINT("FileName: %wZ\n", FileName
);
7736 /* No FOBX: not a standard file/directory */
7737 Fobx
= (PFOBX
)RxContext
->pFobx
;
7740 return STATUS_OBJECT_NAME_INVALID
;
7743 /* We can only deal with a disk */
7744 Fcb
= (PFCB
)RxContext
->pFcb
;
7745 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7747 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7748 return STATUS_INVALID_DEVICE_REQUEST
;
7751 /* Setup RX_CONTEXT related fields */
7752 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7753 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7754 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7755 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7756 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7758 /* We don't support (yet?) a specific index being set */
7759 if (RxContext
->QueryDirectory
.IndexSpecified
)
7761 return STATUS_NOT_IMPLEMENTED
;
7764 /* Try to lock FCB */
7765 LockNotGranted
= TRUE
;
7766 if (RxContext
->QueryDirectory
.InitialQuery
)
7768 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7769 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7771 if (!NT_SUCCESS(Status
))
7776 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7778 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7779 RxConvertToSharedFcb(RxContext
, Fcb
);
7782 LockNotGranted
= FALSE
;
7787 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7788 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7790 if (!NT_SUCCESS(Status
))
7795 LockNotGranted
= FALSE
;
7799 /* If it failed, post request */
7802 return RxFsdPostRequest(RxContext
);
7805 /* This cannot be done on a orphaned directory */
7806 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
7808 RxReleaseFcb(RxContext
, Fcb
);
7809 return STATUS_FILE_CLOSED
;
7815 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
7817 RxContext
->QueryDirectory
.FileIndex
= 0;
7820 /* Assume success */
7821 Status
= STATUS_SUCCESS
;
7822 /* If initial query, prepare FOBX */
7823 if (RxContext
->QueryDirectory
.InitialQuery
)
7825 /* We cannot have a template already! */
7826 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
7828 /* If we have a file name and a correct one, duplicate it in the FOBX */
7829 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
7830 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
7831 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
7832 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
7834 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
7836 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
7837 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7839 /* UNICODE_STRING; length has to be even */
7840 if ((FileName
->Length
& 1) != 0)
7842 Status
= STATUS_INVALID_PARAMETER
;
7843 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
7847 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
7848 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
7849 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
7851 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
7856 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7859 /* No name specified, or a match all wildcard? Match everything */
7862 Fobx
->ContainsWildCards
= TRUE
;
7864 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
7865 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
7866 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
7868 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7871 /* No need for exclusive any longer */
7872 if (NT_SUCCESS(Status
))
7874 RxConvertToSharedFcb(RxContext
, Fcb
);
7878 /* Lock user buffer and forward to mini-rdr */
7879 if (NT_SUCCESS(Status
))
7881 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
7882 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7883 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
7884 RxContext
->Info
.Length
= Length
;
7886 if (RxContext
->Info
.Buffer
!= NULL
)
7888 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
7891 /* Post if mini-rdr asks to */
7892 if (RxContext
->PostRequest
)
7894 RxFsdPostRequest(RxContext
);
7898 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
7904 RxReleaseFcb(RxContext
, Fcb
);
7913 PRX_CONTEXT RxContext
,
7914 PFILE_EA_INFORMATION EaInfo
)
7917 return STATUS_NOT_IMPLEMENTED
;
7921 RxQueryInternalInfo(
7922 PRX_CONTEXT RxContext
,
7923 PFILE_INTERNAL_INFORMATION InternalInfo
)
7926 return STATUS_NOT_IMPLEMENTED
;
7931 PRX_CONTEXT RxContext
,
7932 PFILE_NAME_INFORMATION NameInfo
)
7935 return STATUS_NOT_IMPLEMENTED
;
7940 PRX_CONTEXT RxContext
,
7941 PFILE_PIPE_INFORMATION PipeInfo
)
7944 return STATUS_NOT_IMPLEMENTED
;
7948 RxQueryPositionInfo(
7949 PRX_CONTEXT RxContext
,
7950 PFILE_POSITION_INFORMATION PositionInfo
)
7953 return STATUS_NOT_IMPLEMENTED
;
7960 RxQueryStandardInfo(
7961 PRX_CONTEXT RxContext
,
7962 PFILE_STANDARD_INFORMATION StandardInfo
)
7970 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
7972 /* Zero output buffer */
7973 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
7975 Fcb
= (PFCB
)RxContext
->pFcb
;
7976 Fobx
= (PFOBX
)RxContext
->pFobx
;
7977 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
7978 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
7979 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
7981 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
7984 /* Otherwise, fill what we can already */
7985 Status
= STATUS_SUCCESS
;
7986 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
7987 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
7988 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
7989 if (StandardInfo
->NumberOfLinks
== 0)
7991 StandardInfo
->NumberOfLinks
= 1;
7994 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
7996 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
7997 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
8000 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8001 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
8003 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8007 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
8018 RxReadRegistryParameters(
8025 UNICODE_STRING KeyName
, ParamName
;
8026 OBJECT_ATTRIBUTES ObjectAttributes
;
8027 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
8031 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8032 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
8033 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
8034 if (!NT_SUCCESS(Status
))
8039 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
8040 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
8041 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8042 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8044 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
8047 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
8048 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8049 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8051 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
8053 if (Granularity
> 16)
8058 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
8061 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
8062 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8063 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8065 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
8077 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
8078 IN OUT PDRIVER_OBJECT DriverObject
,
8079 IN PMINIRDR_DISPATCH MrdrDispatch
,
8081 IN PUNICODE_STRING DeviceName
,
8082 IN ULONG DeviceExtensionSize
,
8083 IN DEVICE_TYPE DeviceType
,
8084 IN ULONG DeviceCharacteristics
)
8087 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
8093 return STATUS_INVALID_PARAMETER
;
8096 /* Create device object with provided parameters */
8097 Status
= IoCreateDevice(DriverObject
,
8098 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
8101 DeviceCharacteristics
,
8103 (PDEVICE_OBJECT
*)&RDBSSDevice
);
8104 if (!NT_SUCCESS(Status
))
8109 if (!RxData
.DriverObject
)
8111 return STATUS_UNSUCCESSFUL
;
8114 /* Initialize our DO extension */
8115 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
8116 ++RxFileSystemDeviceObject
->ReferenceCount
;
8117 *DeviceObject
= RDBSSDevice
;
8118 RDBSSDevice
->RdbssExports
= &RxExports
;
8119 RDBSSDevice
->Dispatch
= MrdrDispatch
;
8120 RDBSSDevice
->RegistrationControls
= Controls
;
8121 RDBSSDevice
->DeviceName
= *DeviceName
;
8122 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
8123 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
8124 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
8125 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
8126 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
8127 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
8128 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
8130 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
8132 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
8133 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
8134 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
8136 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8137 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
8139 RxInitializeMinirdrDispatchTable(DriverObject
);
8142 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8143 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
8145 LARGE_INTEGER ScavengerTimeLimit
;
8147 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
8148 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
8149 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
8150 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
8151 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
8152 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
8155 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
8157 return STATUS_SUCCESS
;
8162 RxReleaseFcbFromLazyWrite(
8170 RxReleaseFcbFromReadAhead(
8178 RxReleaseFileForNtCreateSection(
8179 PFILE_OBJECT FileObject
)
8186 RxReleaseForCcFlush(
8187 PFILE_OBJECT FileObject
,
8188 PDEVICE_OBJECT DeviceObject
)
8191 return STATUS_NOT_IMPLEMENTED
;
8198 RxRemoveFromTopLevelIrpAllocatedContextsList(
8199 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8203 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8204 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8205 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8207 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
8208 RemoveEntryList(&TopLevelContext
->ListEntry
);
8209 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
8216 RxRemoveOverflowEntry(
8217 PRDBSS_DEVICE_OBJECT DeviceObject
,
8218 WORK_QUEUE_TYPE Queue
)
8221 PRX_CONTEXT Context
;
8223 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
8224 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
8226 /* No entries left, nothing to return */
8227 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
8234 /* Decrement count */
8235 --DeviceObject
->OverflowQueueCount
[Queue
];
8238 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
8239 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
8240 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
8241 Context
->OverflowListEntry
.Flink
= NULL
;
8243 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
8252 RxRemoveShareAccess(
8253 _Inout_ PFILE_OBJECT FileObject
,
8254 _Inout_ PSHARE_ACCESS ShareAccess
,
8256 _In_ PSZ wherelogtag
)
8260 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8261 IoRemoveShareAccess(FileObject
, ShareAccess
);
8262 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
;
8653 _In_ ACCESS_MASK DesiredAccess
,
8654 _In_ ULONG DesiredShareAccess
,
8655 _Inout_ PFILE_OBJECT FileObject
,
8656 _Out_ PSHARE_ACCESS ShareAccess
,
8658 _In_ PSZ wherelogtag
)
8662 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8663 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8664 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8669 PRX_CONTEXT RxContext
)
8672 return STATUS_NOT_IMPLEMENTED
;
8679 RxSetupNetFileObject(
8680 PRX_CONTEXT RxContext
)
8684 PFILE_OBJECT FileObject
;
8685 PIO_STACK_LOCATION Stack
;
8689 /* Assert FOBX is FOBX or NULL */
8690 Fobx
= (PFOBX
)RxContext
->pFobx
;
8691 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
8693 Fcb
= (PFCB
)RxContext
->pFcb
;
8694 Stack
= RxContext
->CurrentIrpSp
;
8695 FileObject
= Stack
->FileObject
;
8696 /* If it's temporary mark FO as such */
8697 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
8698 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
8700 if (FileObject
== NULL
)
8705 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
8708 /* No FO, nothing to setup */
8709 if (FileObject
== NULL
)
8714 /* Assign FCB & CCB (FOBX) to FO */
8715 FileObject
->FsContext
= Fcb
;
8716 FileObject
->FsContext2
= Fobx
;
8719 ULONG_PTR StackTop
, StackBottom
;
8721 /* If FO is allocated on pool, keep track of it */
8722 IoGetStackLimits(&StackTop
, &StackBottom
);
8723 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
8725 Fobx
->AssociatedFileObject
= FileObject
;
8729 Fobx
->AssociatedFileObject
= NULL
;
8732 /* Make sure to mark FOBX if it's a DFS open */
8733 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
8735 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8739 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8743 /* Set Cc pointers */
8744 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
8746 /* Update access state */
8747 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
8749 PACCESS_STATE AccessState
;
8751 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
8752 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
8753 AccessState
->RemainingDesiredAccess
= 0;
8763 IN PRX_CONTEXT RxContext
,
8764 OUT PBOOLEAN PostToFsp
)
8767 BOOLEAN Wait
, AlreadyStarted
;
8768 PRDBSS_DEVICE_OBJECT DeviceObject
;
8770 /* If we've not been post, then, do it */
8771 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
8773 SECURITY_SUBJECT_CONTEXT SubjectContext
;
8775 SeCaptureSubjectContext(&SubjectContext
);
8776 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
8777 SeReleaseSubjectContext(&SubjectContext
);
8780 return STATUS_PENDING
;
8783 /* Acquire all the required locks */
8784 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8785 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
8788 return STATUS_PENDING
;
8791 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
8793 ExReleaseResourceLite(&RxData
.Resource
);
8795 return STATUS_PENDING
;
8798 AlreadyStarted
= FALSE
;
8799 DeviceObject
= RxContext
->RxDeviceObject
;
8802 /* MUP handle set, means already registered */
8803 if (DeviceObject
->MupHandle
!= NULL
)
8805 AlreadyStarted
= TRUE
;
8806 Status
= STATUS_REDIRECTOR_STARTED
;
8810 /* If we're asked to register to MUP, then do it */
8811 Status
= STATUS_SUCCESS
;
8812 if (DeviceObject
->RegisterUncProvider
)
8814 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
8815 &DeviceObject
->DeviceName
,
8816 DeviceObject
->RegisterMailSlotProvider
);
8818 if (!NT_SUCCESS(Status
))
8820 DeviceObject
->MupHandle
= NULL
;
8824 /* Register as file system */
8825 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
8826 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
8828 /* Inform mini-rdr it has to start */
8829 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
8830 if (NT_SUCCESS(Status
))
8832 ++DeviceObject
->StartStopContext
.Version
;
8833 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
8834 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
8836 Status
= RxInitializeMRxDispatcher(DeviceObject
);
8841 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
8843 if (!AlreadyStarted
)
8845 RxUnstart(RxContext
, DeviceObject
);
8849 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
8850 ExReleaseResourceLite(&RxData
.Resource
);
8860 IN PRX_CONTEXT RxContext
,
8861 OUT PBOOLEAN PostToFsp
)
8864 return STATUS_NOT_IMPLEMENTED
;
8869 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8873 return STATUS_NOT_IMPLEMENTED
;
8880 RxTryToBecomeTheTopLevelIrp(
8881 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
8883 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8884 IN BOOLEAN ForceTopLevel
8887 BOOLEAN FromPool
= FALSE
;
8891 /* If not top level, and not have to be, quit */
8892 if (IoGetTopLevelIrp() && !ForceTopLevel
)
8897 /* If not TLC provider, allocate one */
8898 if (TopLevelContext
== NULL
)
8900 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
8901 if (TopLevelContext
== NULL
)
8910 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
8912 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8915 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8918 /* Make it top level IRP */
8919 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
8927 RxUpdateShareAccess(
8928 _Inout_ PFILE_OBJECT FileObject
,
8929 _Inout_ PSHARE_ACCESS ShareAccess
,
8931 _In_ PSZ wherelogtag
)
8935 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8936 IoUpdateShareAccess(FileObject
, ShareAccess
);
8937 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8944 RxUninitializeCacheMap(
8945 PRX_CONTEXT RxContext
,
8946 PFILE_OBJECT FileObject
,
8947 PLARGE_INTEGER TruncateSize
)
8951 CACHE_UNINITIALIZE_EVENT UninitEvent
;
8955 Fcb
= FileObject
->FsContext
;
8956 ASSERT(NodeTypeIsFcb(Fcb
));
8957 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
8959 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
8960 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
8962 /* Always release the FCB before waiting for the uninit event */
8963 RxReleaseFcb(RxContext
, Fcb
);
8965 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
8967 /* Re-acquire it afterwards */
8968 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
8969 ASSERT(NT_SUCCESS(Status
));
8975 IN PDRIVER_OBJECT DriverObject
)
8984 IN PFILE_LOCK_INFO LockInfo
)
8991 PRX_CONTEXT Context
,
8992 PRDBSS_DEVICE_OBJECT DeviceObject
)
9001 RxUnwindTopLevelIrp(
9002 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
9004 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
9006 /* No TLC provided? Ask the system for ours! */
9007 if (TopLevelContext
== NULL
)
9009 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
9010 if (TopLevelContext
== NULL
)
9015 /* In that case, just assert it's really ours */
9016 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
9017 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9020 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9021 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
9022 /* Restore the previous top level IRP */
9023 IoSetTopLevelIrp(TopLevelContext
->Previous
);
9024 /* If TLC was allocated from pool, remove it from list and release it */
9025 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
9027 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
9028 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
9036 RxUpdateShareAccessPerSrvOpens(
9037 IN PSRV_OPEN SrvOpen
)
9039 ACCESS_MASK DesiredAccess
;
9041 BOOLEAN WriteAccess
;
9042 BOOLEAN DeleteAccess
;
9046 /* If already updated, no need to continue */
9047 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
9052 /* Check if any access wanted */
9053 DesiredAccess
= SrvOpen
->DesiredAccess
;
9054 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
9055 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
9056 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
9058 /* In that case, update it */
9059 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
9062 BOOLEAN SharedWrite
;
9063 BOOLEAN SharedDelete
;
9064 ULONG DesiredShareAccess
;
9065 PSHARE_ACCESS ShareAccess
;
9067 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
9068 DesiredShareAccess
= SrvOpen
->ShareAccess
;
9070 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
9071 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
9072 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
9074 ShareAccess
->OpenCount
++;
9076 ShareAccess
->Readers
+= ReadAccess
;
9077 ShareAccess
->Writers
+= WriteAccess
;
9078 ShareAccess
->Deleters
+= DeleteAccess
;
9079 ShareAccess
->SharedRead
+= SharedRead
;
9080 ShareAccess
->SharedWrite
+= SharedWrite
;
9081 ShareAccess
->SharedDelete
+= SharedDelete
;
9084 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
9091 RxXXXControlFileCallthru(
9092 PRX_CONTEXT Context
)
9098 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
9100 /* No dispatch table? Nothing to dispatch */
9101 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
9103 Context
->pFobx
= NULL
;
9104 return STATUS_INVALID_DEVICE_REQUEST
;
9107 /* Init the lowio context */
9108 Status
= RxLowIoPopulateFsctlInfo(Context
);
9109 if (!NT_SUCCESS(Status
))
9114 /* Check whether we're consistent: a length means a buffer */
9115 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
9116 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
9118 return STATUS_INVALID_PARAMETER
;
9121 /* Forward the call to the mini-rdr */
9122 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
9123 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
9124 if (Status
!= STATUS_PENDING
)
9126 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
9129 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);