3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rdbsslib/rdbss.c
23 * PURPOSE: RDBSS library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
42 (NTAPI
*PRX_FSD_DISPATCH
) (
45 typedef struct _RX_FSD_DISPATCH_VECTOR
47 PRX_FSD_DISPATCH CommonRoutine
;
48 } RX_FSD_DISPATCH_VECTOR
, *PRX_FSD_DISPATCH_VECTOR
;
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject
);
58 PFILE_OBJECT FileObject
,
59 PDEVICE_OBJECT DeviceObject
);
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
89 RxCommonDevFCBCleanup(
100 PRX_CONTEXT Context
);
105 PRX_CONTEXT Context
);
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context
);
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context
);
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context
);
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context
);
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context
);
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context
);
140 PRX_CONTEXT Context
);
145 PRX_CONTEXT Context
);
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context
);
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context
);
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context
);
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context
);
170 PRX_CONTEXT Context
);
175 PRX_CONTEXT Context
);
179 RxCommonSetInformation(
180 PRX_CONTEXT Context
);
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context
);
190 PRX_CONTEXT Context
);
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context
);
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context
);
205 PRX_CONTEXT Context
);
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext
);
214 PUNICODE_STRING NetRootName
);
218 IN PRX_CONTEXT RxContext
);
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject
,
224 PLARGE_INTEGER FileOffset
,
225 ULONG Length
, BOOLEAN Wait
,
226 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
227 PIO_STATUS_BLOCK IoStatus
,
228 PDEVICE_OBJECT DeviceObject
);
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject
,
235 PVOID InputBuffer OPTIONAL
,
236 ULONG InputBufferLength
,
237 PVOID OutputBuffer OPTIONAL
,
238 ULONG OutputBufferLength
,
240 PIO_STATUS_BLOCK IoStatus
,
241 PDEVICE_OBJECT DeviceObject
);
246 PFILE_OBJECT FileObject
,
247 PLARGE_INTEGER FileOffset
,
252 PIO_STATUS_BLOCK IoStatus
,
253 PDEVICE_OBJECT DeviceObject
);
258 PFILE_OBJECT FileObject
,
259 PLARGE_INTEGER FileOffset
,
264 PIO_STATUS_BLOCK IoStatus
,
265 PDEVICE_OBJECT DeviceObject
);
269 PRX_CONTEXT RxContext
,
270 PUNICODE_STRING NetRootName
);
274 PRX_CONTEXT RxContext
,
275 PUNICODE_STRING FileName
,
276 PUNICODE_STRING CanonicalName
,
277 PNET_ROOT_TYPE NetRootType
);
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context
);
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath
);
295 RxGetStringRegistryParameter(
298 OUT PUNICODE_STRING OutString
,
300 IN ULONG BufferLength
,
301 IN BOOLEAN LogFailure
);
305 RxInitializeDebugSupport(
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject
);
315 RxInitializeRegistrationStructures(
320 RxInitializeTopLevelIrpPackage(
326 PDRIVER_OBJECT DriverObject
,
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext
);
340 PRX_CONTEXT RxContext
);
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext
);
349 IN PRX_CONTEXT RxContext
);
353 RxLowIoWriteShellCompletion(
354 PRX_CONTEXT RxContext
);
358 PRX_CONTEXT RxContext
);
361 RxNotifyChangeDirectory(
362 PRX_CONTEXT RxContext
);
366 PRX_CONTEXT RxContext
,
367 FILE_INFORMATION_CLASS FileInfoClass
,
373 PRX_CONTEXT LocalContext
);
376 RxQueryAlternateNameInfo(
377 PRX_CONTEXT RxContext
,
378 PFILE_NAME_INFORMATION AltNameInfo
);
382 PRX_CONTEXT RxContext
,
383 PFILE_BASIC_INFORMATION BasicInfo
);
386 RxQueryCompressedInfo(
387 PRX_CONTEXT RxContext
,
388 PFILE_COMPRESSION_INFORMATION CompressionInfo
);
392 PRX_CONTEXT RxContext
);
396 PRX_CONTEXT RxContext
,
397 PFILE_EA_INFORMATION EaInfo
);
401 PRX_CONTEXT RxContext
,
402 PFILE_INTERNAL_INFORMATION InternalInfo
);
406 PRX_CONTEXT RxContext
,
407 PFILE_NAME_INFORMATION NameInfo
);
411 PRX_CONTEXT RxContext
,
412 PFILE_PIPE_INFORMATION PipeInfo
);
416 PRX_CONTEXT RxContext
,
417 PFILE_POSITION_INFORMATION PositionInfo
);
421 PRX_CONTEXT RxContext
,
422 PFILE_STANDARD_INFORMATION StandardInfo
);
426 RxReadRegistryParameters(
431 RxReleaseFileForNtCreateSection(
432 PFILE_OBJECT FileObject
);
437 PFILE_OBJECT FileObject
,
438 PDEVICE_OBJECT DeviceObject
);
441 RxRemoveOverflowEntry(
442 PRDBSS_DEVICE_OBJECT DeviceObject
,
443 WORK_QUEUE_TYPE Queue
);
446 RxSearchForCollapsibleOpen(
447 PRX_CONTEXT RxContext
,
448 ACCESS_MASK DesiredAccess
,
453 PRX_CONTEXT RxContext
);
457 PRX_CONTEXT RxContext
);
460 RxSetDispositionInfo(
461 PRX_CONTEXT RxContext
);
465 PRX_CONTEXT RxContext
);
469 PRX_CONTEXT RxContext
);
473 PRX_CONTEXT RxContext
);
477 PRX_CONTEXT RxContext
);
481 PRX_CONTEXT RxContext
);
484 RxSetupNetFileObject(
485 PRX_CONTEXT RxContext
);
489 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
493 RxUninitializeCacheMap(
494 PRX_CONTEXT RxContext
,
495 PFILE_OBJECT FileObject
,
496 PLARGE_INTEGER TruncateSize
);
501 PRDBSS_DEVICE_OBJECT DeviceObject
);
504 RxXXXControlFileCallthru(
505 PRX_CONTEXT Context
);
509 _RxAllocatePoolWithTag(
510 _In_ POOL_TYPE PoolType
,
511 _In_ SIZE_T NumberOfBytes
,
525 WCHAR RxStarForTemplate
= '*';
526 WCHAR Rx8QMdot3QM
[] = L
">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles
= FALSE
;
528 BOOLEAN DisableFlushOnCleanup
= FALSE
;
529 ULONG ReadAheadGranularity
= 1 << PAGE_SHIFT
;
530 LIST_ENTRY RxActiveContexts
;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList
;
532 FAST_MUTEX RxContextPerFileSerializationMutex
;
535 BOOLEAN RxLoudLowIoOpsEnabled
= FALSE
;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
538 { RxCommonDispatchProblem
},
539 { RxCommonDispatchProblem
},
540 { RxCommonDevFCBClose
},
541 { RxCommonDispatchProblem
},
542 { RxCommonDispatchProblem
},
543 { RxCommonDispatchProblem
},
544 { RxCommonDispatchProblem
},
545 { RxCommonDispatchProblem
},
546 { RxCommonDispatchProblem
},
547 { RxCommonDispatchProblem
},
548 { RxCommonDevFCBQueryVolInfo
},
549 { RxCommonDispatchProblem
},
550 { RxCommonDispatchProblem
},
551 { RxCommonDevFCBFsCtl
},
552 { RxCommonDevFCBIoCtl
},
553 { RxCommonDevFCBIoCtl
},
554 { RxCommonDispatchProblem
},
555 { RxCommonDispatchProblem
},
556 { RxCommonDevFCBCleanup
},
557 { RxCommonDispatchProblem
},
558 { RxCommonDispatchProblem
},
559 { RxCommonDispatchProblem
},
560 { RxCommonUnimplemented
},
561 { RxCommonUnimplemented
},
562 { RxCommonUnimplemented
},
563 { RxCommonUnimplemented
},
564 { RxCommonUnimplemented
},
565 { RxCommonUnimplemented
},
567 RDBSS_EXPORTS RxExports
;
568 FAST_IO_DISPATCH RxFastIoDispatch
;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject
;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
573 { RxCommonUnimplemented
},
577 { RxCommonQueryInformation
},
578 { RxCommonSetInformation
},
581 { RxCommonFlushBuffers
},
582 { RxCommonQueryVolumeInformation
},
583 { RxCommonSetVolumeInformation
},
584 { RxCommonDirectoryControl
},
585 { RxCommonFileSystemControl
},
586 { RxCommonDeviceControl
},
587 { RxCommonDeviceControl
},
588 { RxCommonUnimplemented
},
589 { RxCommonLockControl
},
591 { RxCommonUnimplemented
},
592 { RxCommonQuerySecurity
},
593 { RxCommonSetSecurity
},
594 { RxCommonUnimplemented
},
595 { RxCommonUnimplemented
},
596 { RxCommonUnimplemented
},
597 { RxCommonQueryQuotaInformation
},
598 { RxCommonSetQuotaInformation
},
599 { RxCommonUnimplemented
},
601 ULONG RxFsdEntryCount
;
602 LIST_ENTRY RxIrpsList
;
603 KSPIN_LOCK RxIrpsListSpinLock
;
604 KMUTEX RxScavengerMutex
;
605 KMUTEX RxSerializationMutex
;
606 UCHAR RxSpaceForTheWrappersDeviceObject
[sizeof(*RxFileSystemDeviceObject
)];
607 KSPIN_LOCK TopLevelIrpSpinLock
;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList
;
609 BOOLEAN RxForceQFIPassThrough
= FALSE
;
610 BOOLEAN RxNoAsync
= FALSE
;
612 DECLARE_CONST_UNICODE_STRING(unknownId
, L
"???");
619 #define ASSERT(exp) \
622 RxAssert(#exp, __FILE__, __LINE__, NULL); \
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
637 /* FUNCTIONS ****************************************************************/
643 CheckForLoudOperations(
644 PRX_CONTEXT RxContext
)
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
650 /* Are loud operations enabled? */
651 if (RxLoudLowIoOpsEnabled
)
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 Fcb
= (PFCB
)RxContext
->pFcb
;
657 if (RtlCompareMemory(Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, (Fcb
->PrivateAlreadyPrefixedName
.Length
- ALLSCR_LENGTH
)),
658 L
"all.scr", ALLSCR_LENGTH
) == ALLSCR_LENGTH
)
660 SetFlag(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
);
670 __RxInitializeTopLevelIrpContext(
671 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
673 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
676 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext
, Irp
, RxDeviceObject
, Flags
);
678 RtlZeroMemory(TopLevelContext
, sizeof(RX_TOPLEVELIRP_CONTEXT
));
679 TopLevelContext
->Irp
= Irp
;
680 TopLevelContext
->Flags
= (Flags
? RX_TOPLEVELCTX_FLAG_FROM_POOL
: 0);
681 TopLevelContext
->Signature
= RX_TOPLEVELIRP_CONTEXT_SIGNATURE
;
682 TopLevelContext
->RxDeviceObject
= RxDeviceObject
;
683 TopLevelContext
->Previous
= IoGetTopLevelIrp();
684 TopLevelContext
->Thread
= PsGetCurrentThread();
686 /* We cannot add to list something that'd come from stack */
687 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
689 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext
);
697 __RxWriteReleaseResources(
698 PRX_CONTEXT RxContext
,
699 BOOLEAN ResourceOwnerSet
,
708 ASSERT(RxContext
!= NULL
);
710 Fcb
= (PFCB
)RxContext
->pFcb
;
713 /* If FCB resource was acquired, release it */
714 if (RxContext
->FcbResourceAcquired
)
716 /* Taking care of owner */
717 if (ResourceOwnerSet
)
719 RxReleaseFcbForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
723 RxReleaseFcb(RxContext
, Fcb
);
726 RxContext
->FcbResourceAcquired
= FALSE
;
729 /* If FCB paging resource was acquired, release it */
730 if (RxContext
->FcbPagingIoResourceAcquired
)
732 /* Taking care of owner */
733 if (ResourceOwnerSet
)
735 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
739 RxReleasePagingIoResource(RxContext
, Fcb
);
742 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
750 RxAddToTopLevelIrpAllocatedContextsList(
751 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
755 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
757 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
758 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
760 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
761 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
762 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
771 IN PRX_CONTEXT RxContext
,
776 WORK_QUEUE_TYPE Queue
;
777 PIO_STACK_LOCATION Stack
;
779 Stack
= RxContext
->CurrentIrpSp
;
780 RxContext
->PostRequest
= FALSE
;
782 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
784 Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
786 Queue
= DelayedWorkQueue
;
787 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
791 Queue
= CriticalWorkQueue
;
792 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
795 /* Check for overflow */
796 if (Stack
->FileObject
!= NULL
)
798 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
800 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
801 /* In case of an overflow, add the new queued call to the overflow list */
804 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
805 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
806 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
808 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
812 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
815 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
816 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
823 RxAdjustFileTimesAndSize(
829 PFILE_OBJECT FileObject
;
830 LARGE_INTEGER CurrentTime
;
831 FILE_BASIC_INFORMATION FileBasicInfo
;
832 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
833 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
837 FileObject
= Context
->CurrentIrpSp
->FileObject
;
838 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839 if (FileObject
->PrivateCacheMap
== NULL
)
845 KeQuerySystemTime(&CurrentTime
);
847 Fobx
= (PFOBX
)Context
->pFobx
;
848 /* Was the file modified? */
849 FileModified
= BooleanFlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
);
850 /* We'll set last write if it was modified and user didn't update yet */
851 SetLastWrite
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
852 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853 SetLastAccess
= SetLastWrite
||
854 (BooleanFlagOn(FileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
855 !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
856 /* We'll set last change if it was modified and user didn't update yet */
857 SetLastChange
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
859 /* Nothing to update? Job done */
860 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
865 Fcb
= (PFCB
)Context
->pFcb
;
866 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
868 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
870 /* Update lastwrite time if required */
874 Fcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
875 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
878 /* Update lastaccess time if required */
882 Fcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
883 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
886 /* Update lastchange time if required */
890 Fcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
891 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
894 /* If one of the date was modified, issue a call to mini-rdr */
897 Context
->Info
.FileInformationClass
= FileBasicInformation
;
898 Context
->Info
.Buffer
= &FileBasicInfo
;
899 Context
->Info
.Length
= sizeof(FileBasicInfo
);
901 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
905 /* If the file was modified, update its EOF */
908 FileEOFInfo
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
910 Context
->Info
.FileInformationClass
= FileEndOfFileInformation
;
911 Context
->Info
.Buffer
= &FileEOFInfo
;
912 Context
->Info
.Length
= sizeof(FileEOFInfo
);
914 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
923 RxAllocateCanonicalNameBuffer(
924 PRX_CONTEXT RxContext
,
925 PUNICODE_STRING CanonicalName
,
926 USHORT CanonicalLength
)
930 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
932 /* Context must be free of any already allocated name */
933 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
935 /* Validate string length */
936 if (CanonicalLength
> USHRT_MAX
- 1)
938 CanonicalName
->Buffer
= NULL
;
939 return STATUS_OBJECT_PATH_INVALID
;
942 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
943 if (CanonicalName
->Buffer
== NULL
)
945 return STATUS_INSUFFICIENT_RESOURCES
;
948 CanonicalName
->Length
= 0;
949 CanonicalName
->MaximumLength
= CanonicalLength
;
951 /* Set the two places - they must always be identical */
952 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
953 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
955 return STATUS_SUCCESS
;
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
968 LIST_ENTRY ContextsToCancel
;
970 /* Init a list for the contexts to cancel */
971 InitializeListHead(&ContextsToCancel
);
973 /* Lock our list lock */
974 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
976 /* Now, browse all the active contexts, to find the associated ones */
977 Entry
= RxActiveContexts
.Flink
;
978 while (Entry
!= &RxActiveContexts
)
980 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
981 Entry
= Entry
->Flink
;
983 /* Not the IRP we're looking for, ignore */
984 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
985 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
990 /* Not the FOBX we're looking for, ignore */
991 if ((PFOBX
)Context
->pFobx
!= Fobx
)
996 /* No cancel routine (can't be cancel, then), ignore */
997 if (Context
->MRxCancelRoutine
== NULL
)
1002 /* Mark our context as cancelled */
1003 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1005 /* Move it to our list */
1006 RemoveEntryList(&Context
->ContextListEntry
);
1007 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1009 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1012 /* Done with the contexts */
1013 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1015 /* Now, handle all our "extracted" contexts */
1016 while (!IsListEmpty(&ContextsToCancel
))
1018 Entry
= RemoveHeadList(&ContextsToCancel
);
1019 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1021 /* If they had an associated IRP (should be always true) */
1022 if (Context
->CurrentIrp
!= NULL
)
1024 /* Then, call cancel routine */
1025 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1026 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1027 Context
->MRxCancelRoutine(Context
);
1030 /* And delete the context */
1031 RxDereferenceAndDeleteRxContext(Context
);
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040 PV_NET_ROOT VNetRoot
,
1041 BOOLEAN ForceFilesClosed
)
1046 PRX_CONTEXT Context
;
1047 LIST_ENTRY ContextsToCancel
;
1049 /* Init a list for the contexts to cancel */
1050 InitializeListHead(&ContextsToCancel
);
1052 /* Lock our list lock */
1053 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1055 /* Assume success */
1056 Status
= STATUS_SUCCESS
;
1058 /* Now, browse all the active contexts, to find the associated ones */
1059 Entry
= RxActiveContexts
.Flink
;
1060 while (Entry
!= &RxActiveContexts
)
1062 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1063 Entry
= Entry
->Flink
;
1065 /* Not the IRP we're looking for, ignore */
1066 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1067 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1072 /* Not the VNetRoot we're looking for, ignore */
1073 if (Context
->pFcb
== NULL
||
1074 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1079 /* No cancel routine (can't be cancel, then), ignore */
1080 if (Context
->MRxCancelRoutine
== NULL
)
1085 /* At that point, we found a matching context
1086 * If we're not asked to force close, then fail - it's still open
1088 if (!ForceFilesClosed
)
1090 Status
= STATUS_FILES_OPEN
;
1094 /* Mark our context as cancelled */
1095 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1097 /* Move it to our list */
1098 RemoveEntryList(&Context
->ContextListEntry
);
1099 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1101 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1104 /* Done with the contexts */
1105 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1107 if (Status
!= STATUS_SUCCESS
)
1112 /* Now, handle all our "extracted" contexts */
1113 while (!IsListEmpty(&ContextsToCancel
))
1115 Entry
= RemoveHeadList(&ContextsToCancel
);
1116 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1118 /* If they had an associated IRP (should be always true) */
1119 if (Context
->CurrentIrp
!= NULL
)
1121 /* Then, call cancel routine */
1122 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1123 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1124 Context
->MRxCancelRoutine(Context
);
1127 /* And delete the context */
1128 RxDereferenceAndDeleteRxContext(Context
);
1137 PDEVICE_OBJECT DeviceObject
,
1147 RxCanonicalizeFileNameByServerSpecs(
1148 PRX_CONTEXT RxContext
,
1149 PUNICODE_STRING NetRootName
)
1151 USHORT NextChar
, CurChar
;
1156 /* Validate file name is not empty */
1157 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1160 return STATUS_MORE_PROCESSING_REQUIRED
;
1163 /* Validate name is correct */
1164 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1168 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1170 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1177 if (CurChar
== NextChar
)
1179 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1186 if (CurChar
>= MaxChars
- 1)
1191 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1193 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1198 if (NetRootName
->Buffer
[1] != ':')
1200 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1206 if ((CurChar
- NextChar
) == 1)
1208 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1213 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1215 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1220 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1221 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1226 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1228 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1234 return STATUS_MORE_PROCESSING_REQUIRED
;
1238 RxCanonicalizeNameAndObtainNetRoot(
1239 PRX_CONTEXT RxContext
,
1240 PUNICODE_STRING FileName
,
1241 PUNICODE_STRING NetRootName
)
1244 NET_ROOT_TYPE NetRootType
;
1245 UNICODE_STRING CanonicalName
;
1249 NetRootType
= NET_ROOT_WILD
;
1251 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1252 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1254 /* if not relative opening, just handle the passed name */
1255 if (RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
== NULL
)
1257 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1258 if (!NT_SUCCESS(Status
))
1267 /* Make sure we have a valid FCB and a FOBX */
1268 Fcb
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1270 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1272 return STATUS_INVALID_PARAMETER
;
1275 if (!NodeTypeIsFcb(Fcb
))
1277 return STATUS_INVALID_PARAMETER
;
1283 /* Get/Create the associated VNetRoot for opening */
1284 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1285 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1286 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1288 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1290 RxFreeCanonicalNameBuffer(RxContext
);
1291 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1292 if (NT_SUCCESS(Status
))
1294 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1298 /* Filename cannot contain wildcards */
1299 if (FsRtlDoesNameContainWildCards(NetRootName
))
1301 Status
= STATUS_OBJECT_NAME_INVALID
;
1304 /* Make sure file name is correct */
1305 if (NT_SUCCESS(Status
))
1307 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1310 /* Give the mini-redirector a chance to prepare the name */
1311 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1313 if (RxContext
->Create
.pNetRoot
!= NULL
)
1315 NTSTATUS IgnoredStatus
;
1317 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1318 MRxPreparseName
, (RxContext
, NetRootName
));
1319 (void)IgnoredStatus
;
1331 RxCheckFcbStructuresForAlignment(
1340 _In_ ACCESS_MASK DesiredAccess
,
1341 _In_ ULONG DesiredShareAccess
,
1342 _Inout_ PFILE_OBJECT FileObject
,
1343 _Inout_ PSHARE_ACCESS ShareAccess
,
1344 _In_ BOOLEAN Update
,
1346 _In_ PSZ wherelogtag
)
1350 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1351 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1353 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1361 RxCheckShareAccessPerSrvOpens(
1363 IN ACCESS_MASK DesiredAccess
,
1364 IN ULONG DesiredShareAccess
)
1367 BOOLEAN WriteAccess
;
1368 BOOLEAN DeleteAccess
;
1369 PSHARE_ACCESS ShareAccess
;
1373 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1375 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1376 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1378 /* Check if any access wanted */
1379 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1380 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1381 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1383 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1385 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1386 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1387 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1389 /* Check whether there's a violation */
1391 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1393 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1395 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1396 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1397 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1398 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1400 return STATUS_SHARING_VIOLATION
;
1404 return STATUS_SUCCESS
;
1408 RxCleanupPipeQueues(
1409 PRX_CONTEXT Context
)
1418 RxCloseAssociatedSrvOpen(
1420 IN PRX_CONTEXT RxContext OPTIONAL
)
1425 BOOLEAN CloseSrvOpen
;
1426 PRX_CONTEXT LocalContext
;
1430 /* Assume SRV_OPEN is already closed */
1431 CloseSrvOpen
= FALSE
;
1432 /* If we have a FOBX, we'll have to close it */
1435 /* If the FOBX isn't closed yet */
1436 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1438 SrvOpen
= Fobx
->SrvOpen
;
1439 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1440 /* Check whether we've to close SRV_OPEN first */
1441 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1443 CloseSrvOpen
= TRUE
;
1447 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1449 /* Not much to do */
1450 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1452 if (SrvOpen
->OpenCount
> 0)
1454 --SrvOpen
->OpenCount
;
1459 /* No need to close SRV_OPEN, so close FOBX */
1462 RxMarkFobxOnClose(Fobx
);
1464 return STATUS_SUCCESS
;
1469 /* No FOBX? No RX_CONTEXT, ok, job done! */
1470 if (RxContext
== NULL
)
1472 return STATUS_SUCCESS
;
1475 /* Get the FCB from RX_CONTEXT */
1476 Fcb
= (PFCB
)RxContext
->pFcb
;
1480 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1481 if (RxContext
== NULL
)
1483 ASSERT(Fobx
!= NULL
);
1485 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1486 if (LocalContext
== NULL
)
1488 return STATUS_INSUFFICIENT_RESOURCES
;
1491 LocalContext
->MajorFunction
= 2;
1492 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1493 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1494 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1498 LocalContext
= RxContext
;
1501 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1503 /* Now, close the FOBX */
1506 RxMarkFobxOnClose(Fobx
);
1510 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1513 /* If not a "standard" file, SRV_OPEN can be null */
1514 if (SrvOpen
== NULL
)
1516 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1517 RxDereferenceNetFcb(Fcb
);
1519 if (LocalContext
!= RxContext
)
1521 RxDereferenceAndDeleteRxContext(LocalContext
);
1524 return STATUS_SUCCESS
;
1527 /* If SRV_OPEN isn't in a good condition, nothing to close */
1528 if (SrvOpen
->Condition
!= Condition_Good
)
1530 if (LocalContext
!= RxContext
)
1532 RxDereferenceAndDeleteRxContext(LocalContext
);
1535 return STATUS_SUCCESS
;
1538 /* Decrease open count */
1539 if (SrvOpen
->OpenCount
> 0)
1541 --SrvOpen
->OpenCount
;
1544 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1545 if (SrvOpen
->OpenCount
== 1)
1547 if (!IsListEmpty(&SrvOpen
->FobxList
))
1549 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1551 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1556 /* Nothing left, purge FCB */
1557 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1559 RxPurgeNetFcb(Fcb
, LocalContext
);
1562 /* Already closed? Job done! */
1563 SrvOpen
= Fobx
->SrvOpen
;
1564 if (SrvOpen
== NULL
||
1565 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1566 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1568 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1569 if (LocalContext
!= RxContext
)
1571 RxDereferenceAndDeleteRxContext(LocalContext
);
1574 return STATUS_SUCCESS
;
1577 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1579 /* Inform mini-rdr about closing */
1580 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1581 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1582 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1584 /* And mark as such */
1585 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1586 SrvOpen
->Key
= (PVOID
)-1;
1588 /* If we were delayed, we're not! */
1589 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1591 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1595 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1596 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1599 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1601 /* Mark the FOBX closed as well */
1602 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1604 if (LocalContext
!= RxContext
)
1606 RxDereferenceAndDeleteRxContext(LocalContext
);
1616 RxCollapseOrCreateSrvOpen(
1617 PRX_CONTEXT RxContext
)
1624 PIO_STACK_LOCATION Stack
;
1625 ACCESS_MASK DesiredAccess
;
1626 RX_BLOCK_CONDITION FcbCondition
;
1630 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1632 Fcb
= (PFCB
)RxContext
->pFcb
;
1633 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1634 ++Fcb
->UncleanCount
;
1636 Stack
= RxContext
->CurrentIrpSp
;
1637 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1638 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1640 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1642 /* Try to find a reusable SRV_OPEN */
1643 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1644 if (Status
== STATUS_NOT_FOUND
)
1646 /* If none found, create one */
1647 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1648 if (SrvOpen
== NULL
)
1650 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1654 SrvOpen
->DesiredAccess
= DesiredAccess
;
1655 SrvOpen
->ShareAccess
= ShareAccess
;
1656 Status
= STATUS_SUCCESS
;
1659 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1661 if (Status
!= STATUS_SUCCESS
)
1663 FcbCondition
= Condition_Bad
;
1667 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1669 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1670 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1671 /* Inform the mini-rdr we're handling a create */
1672 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1673 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1675 DPRINT("MRxCreate returned: %x\n", Status
);
1676 if (Status
== STATUS_SUCCESS
)
1678 /* In case of overwrite, reset file size */
1679 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1681 RxAcquirePagingIoResource(RxContext
, Fcb
);
1682 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1683 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1684 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1685 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1686 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1687 RxReleasePagingIoResource(RxContext
, Fcb
);
1691 /* Otherwise, adjust sizes */
1692 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1693 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1695 RxAdjustAllocationSizeforCC(Fcb
);
1697 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1701 /* Set the IoStatus with information returned by mini-rdr */
1702 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1704 SrvOpen
->OpenStatus
= Status
;
1705 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1706 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1708 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1710 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1712 if (Status
== STATUS_SUCCESS
)
1714 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1716 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1718 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1719 FcbCondition
= Condition_Good
;
1723 FcbCondition
= Condition_Bad
;
1724 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1725 RxContext
->pRelevantSrvOpen
= NULL
;
1727 if (RxContext
->pFobx
!= NULL
)
1729 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1730 RxContext
->pFobx
= NULL
;
1735 /* Set FCB state - good or bad - depending on whether create succeed */
1736 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1737 RxTransitionNetFcb(Fcb
, FcbCondition
);
1739 else if (Status
== STATUS_SUCCESS
)
1741 BOOLEAN IsGood
, ExtraOpen
;
1743 /* A reusable SRV_OPEN was found */
1744 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1747 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1749 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1750 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1751 if (!StableCondition(SrvOpen
->Condition
))
1753 RxReferenceSrvOpen(SrvOpen
);
1754 ++SrvOpen
->OpenCount
;
1757 RxReleaseFcb(RxContext
, Fcb
);
1758 RxContext
->Create
.FcbAcquired
= FALSE
;
1760 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1762 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1764 RxContext
->Create
.FcbAcquired
= TRUE
;
1767 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1770 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1773 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1775 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1779 Status
= SrvOpen
->OpenStatus
;
1784 --SrvOpen
->OpenCount
;
1785 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1789 --Fcb
->UncleanCount
;
1791 DPRINT("Status: %x\n", Status
);
1801 PRX_CONTEXT Context
)
1803 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1809 PFILE_OBJECT FileObject
;
1810 LARGE_INTEGER TruncateSize
;
1811 PLARGE_INTEGER TruncateSizePtr
;
1812 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1816 Fcb
= (PFCB
)Context
->pFcb
;
1817 Fobx
= (PFOBX
)Context
->pFobx
;
1818 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1820 /* File system closing, it's OK */
1823 if (Fcb
->UncleanCount
> 0)
1825 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1828 return STATUS_SUCCESS
;
1831 /* Check we have a correct FCB type */
1832 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1833 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1834 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1835 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1837 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1838 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1841 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1842 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1844 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1846 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1847 if (!NT_SUCCESS(Status
))
1854 Fobx
->AssociatedFileObject
= NULL
;
1856 /* In case it was already orphaned */
1857 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
1859 ASSERT(Fcb
->UncleanCount
!= 0);
1860 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1862 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1864 --Fcb
->UncachedUncleanCount
;
1867 /* Inform mini-rdr */
1868 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1870 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1871 --Fobx
->SrvOpen
->UncleanFobxCount
;
1873 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1875 RxReleaseFcb(Context
, Fcb
);
1877 return STATUS_SUCCESS
;
1880 /* Report the fact that file could be set as delete on close */
1881 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1883 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1886 /* Cancel any pending notification */
1887 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1889 /* Backup open count before we start playing with it */
1890 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1892 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1893 FcbTableAcquired
= FALSE
;
1894 LeftForDelete
= FALSE
;
1895 OneLeft
= (Fcb
->UncleanCount
== 1);
1899 /* Unclean count and delete on close? Verify whether we're the one */
1900 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1902 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1904 FcbTableAcquired
= TRUE
;
1908 RxReleaseFcb(Context
, Fcb
);
1910 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1912 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1913 if (Status
!= STATUS_SUCCESS
)
1915 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1919 FcbTableAcquired
= TRUE
;
1922 /* That means we'll perform the delete on close! */
1923 if (Fcb
->UncleanCount
== 1)
1925 LeftForDelete
= TRUE
;
1929 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1930 FcbTableAcquired
= FALSE
;
1935 TruncateSizePtr
= NULL
;
1936 /* Handle cleanup for pipes and printers */
1937 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1939 RxCleanupPipeQueues(Context
);
1941 /* Handle cleanup for files */
1942 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1944 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1945 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1948 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1950 /* If there are still locks to release, proceed */
1951 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1953 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1954 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1955 Status
= RxLowIoLockControlShell(Context
);
1958 /* Fix times and size */
1959 RxAdjustFileTimesAndSize(Context
);
1961 /* If we're the only one left... */
1964 /* And if we're supposed to delete on close */
1967 /* Update the sizes */
1968 RxAcquirePagingIoResource(Context
, Fcb
);
1969 Fcb
->Header
.FileSize
.QuadPart
= 0;
1970 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1971 RxReleasePagingIoResource(Context
, Fcb
);
1973 /* Otherwise, call the mini-rdr to adjust sizes */
1976 /* File got grown up, fill with zeroes */
1977 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1978 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1980 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1981 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1984 /* File was truncated, let mini-rdr proceed */
1985 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1987 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1988 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1990 /* Keep track of file change for Cc uninit */
1991 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1992 TruncateSizePtr
= &TruncateSize
;
1997 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2005 /* Otherwise, try to see whether we can purge */
2008 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2015 /* We have to still be there! */
2016 ASSERT(Fcb
->UncleanCount
!= 0);
2017 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2019 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2021 --Fcb
->UncachedUncleanCount
;
2024 /* Inform mini-rdr about ongoing cleanup */
2025 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2027 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2028 --Fobx
->SrvOpen
->UncleanFobxCount
;
2031 if (DisableFlushOnCleanup
)
2033 /* Only if we're the last standing */
2034 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2035 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2037 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2038 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2044 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2046 DPRINT("Flushing %p on cleanup\n", Context
);
2047 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2051 /* If only remaining uncached & unclean, then flush and purge */
2052 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2054 if (Fcb
->UncachedUncleanCount
!= 0)
2056 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2057 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2059 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2060 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2065 /* If purge required, and not about to delete, flush */
2066 if (!LeftForDelete
&& NeedPurge
)
2068 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2069 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2072 /* If it was a file, drop cache */
2075 DPRINT("Uninit cache map for file\n");
2076 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2079 /* If that's the one left for deletion, or if it needs purge, flush */
2080 if (LeftForDelete
|| NeedPurge
)
2082 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2083 /* If that's for deletion, also remove from FCB table */
2086 RxRemoveNameNetFcb(Fcb
);
2087 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2088 FcbTableAcquired
= FALSE
;
2092 /* Remove any share access */
2093 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2095 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2098 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2099 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2100 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2102 NTSTATUS InternalStatus
;
2103 PRX_CONTEXT InternalContext
;
2105 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2106 InternalStatus
= STATUS_UNSUCCESSFUL
;
2107 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2108 Fcb
->RxDeviceObject
,
2109 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2110 if (InternalContext
!= NULL
)
2112 FILE_END_OF_FILE_INFORMATION FileEOF
;
2114 InternalStatus
= STATUS_SUCCESS
;
2116 /* Initialize the context for file information set */
2117 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2118 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2119 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2121 /* Get EOF from the FCB */
2122 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2123 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2124 InternalContext
->Info
.Buffer
= &FileEOF
;
2125 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2127 /* Call the mini-rdr */
2128 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2131 RxDereferenceAndDeleteRxContext(InternalContext
);
2134 /* We tried, so, clean the FOBX flag */
2135 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2136 /* If it failed, then, disable collapsing on the FCB */
2137 if (!NT_SUCCESS(InternalStatus
))
2139 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2144 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2146 FcbAcquired
= FALSE
;
2147 RxReleaseFcb(Context
, Fcb
);
2153 RxReleaseFcb(Context
, Fcb
);
2156 if (FcbTableAcquired
)
2158 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2164 #undef BugCheckFileId
2170 PRX_CONTEXT Context
)
2172 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2176 PFILE_OBJECT FileObject
;
2177 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2181 Fcb
= (PFCB
)Context
->pFcb
;
2182 Fobx
= (PFOBX
)Context
->pFobx
;
2183 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2184 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2186 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2187 if (!NT_SUCCESS(Status
))
2197 /* Check our FCB type is expected */
2198 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2199 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2200 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2202 RxBugCheck(NodeType(Fcb
), 0, 0);
2205 RxReferenceNetFcb(Fcb
);
2207 DereferenceFobx
= FALSE
;
2208 /* If we're not closing FS */
2214 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2215 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2216 /* Handle delayed close */
2217 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2219 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2221 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2223 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2225 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2227 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2229 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2233 DereferenceFobx
= TRUE
;
2234 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2241 /* If we reach maximum of delayed close/or if there are no delayed close */
2242 if (!DereferenceFobx
)
2246 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2247 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2249 /* Delete if asked */
2250 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2252 RxScavengeRelatedFobxs(Fcb
);
2253 RxSynchronizeWithScavenger(Context
);
2255 RxReleaseFcb(Context
, Fcb
);
2257 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2258 RxOrphanThisFcb(Fcb
);
2259 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2261 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2262 ASSERT(NT_SUCCESS(Status
));
2267 RxMarkFobxOnClose(Fobx
);
2270 if (DereferenceFobx
)
2272 ASSERT(Fobx
!= NULL
);
2273 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2277 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2280 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2284 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2285 AcquiredFcb
= !Freed
;
2287 FileObject
->FsContext
= (PVOID
)-1;
2291 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2295 RxReleaseFcb(Context
, Fcb
);
2296 AcquiredFcb
= FALSE
;
2301 if (_SEH2_AbnormalTermination())
2305 RxReleaseFcb(Context
, Fcb
);
2310 ASSERT(!AcquiredFcb
);
2315 DPRINT("Status: %x\n", Status
);
2317 #undef BugCheckFileId
2326 PRX_CONTEXT Context
)
2330 PFILE_OBJECT FileObject
;
2331 PIO_STACK_LOCATION Stack
;
2335 DPRINT("RxCommonCreate(%p)\n", Context
);
2337 Irp
= Context
->CurrentIrp
;
2338 Stack
= Context
->CurrentIrpSp
;
2339 FileObject
= Stack
->FileObject
;
2341 /* Check whether that's a device opening */
2342 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2344 FileObject
->FsContext
= &RxDeviceFCB
;
2345 FileObject
->FsContext2
= NULL
;
2347 ++RxDeviceFCB
.NodeReferenceCount
;
2348 ++RxDeviceFCB
.OpenCount
;
2350 Irp
->IoStatus
.Information
= FILE_OPENED
;
2351 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2353 Status
= STATUS_SUCCESS
;
2357 PFCB RelatedFcb
= NULL
;
2359 /* Make sure caller is consistent */
2360 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2361 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2363 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2364 return STATUS_INVALID_PARAMETER
;
2367 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2368 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2369 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2370 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2372 if (FileObject
->RelatedFileObject
!= NULL
)
2374 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2375 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2378 /* Going to rename? */
2379 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2381 DPRINT("TargetDir!\n");
2384 /* Copy create parameters to the context */
2385 RxCopyCreateParameters(Context
);
2387 /* If the caller wants to establish a connection, go ahead */
2388 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2390 Status
= RxCreateTreeConnect(Context
);
2394 /* Validate file name */
2395 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2396 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2397 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2399 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2400 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2401 FileObject
->FileName
.Length
);
2403 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2404 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2405 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2407 return STATUS_OBJECT_NAME_INVALID
;
2411 /* Attempt to open the file */
2414 UNICODE_STRING NetRootName
;
2416 /* Strip last \ if required */
2417 if (FileObject
->FileName
.Length
!= 0 &&
2418 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2420 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2422 return STATUS_OBJECT_NAME_INVALID
;
2425 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2426 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2429 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2431 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2434 /* Get the associated net root to opening */
2435 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2436 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2441 /* And attempt to open */
2442 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2443 if (Status
== STATUS_SHARING_VIOLATION
)
2445 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2447 /* If that happens for file creation, fail for real */
2448 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2450 Status
= STATUS_OBJECT_NAME_COLLISION
;
2454 /* Otherwise, if possible, attempt to scavenger current FOBX
2455 * to check whether a dormant FOBX is the reason for sharing violation
2457 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2458 !Context
->Create
.ScavengingAlreadyTried
)
2460 /* Only doable with a VNetRoot */
2461 if (Context
->Create
.pVNetRoot
!= NULL
)
2463 PV_NET_ROOT VNetRoot
;
2464 NT_CREATE_PARAMETERS SavedParameters
;
2466 /* Save create parameters */
2467 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2469 /* Reference the VNetRoot for the scavenging time */
2470 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2471 RxReferenceVNetRoot(VNetRoot
);
2473 /* Prepare the RX_CONTEXT for reuse */
2474 RxpPrepareCreateContextForReuse(Context
);
2475 RxReinitializeContext(Context
);
2477 /* Copy what we saved */
2478 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2480 /* And recopy what can be */
2481 RxCopyCreateParameters(Context
);
2483 /* And start purging, then scavenging FOBX */
2484 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2485 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2486 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2489 /* Ask for a second round */
2490 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2492 /* Keep track we already scavenged */
2493 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2495 /* Reference our SRV_CALL for CBS handling */
2496 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2497 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2499 /* Drop our extra reference */
2500 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2505 else if (Status
== STATUS_REPARSE
)
2507 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2511 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2514 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2517 if (Status
== STATUS_RETRY
)
2519 RxpPrepareCreateContextForReuse(Context
);
2521 ASSERT(Status
!= STATUS_PENDING
);
2524 DPRINT("Status: %lx\n", Status
);
2533 RxCommonDevFCBCleanup(
2534 PRX_CONTEXT Context
)
2541 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2543 Fcb
= Context
->pFcb
;
2544 Status
= STATUS_SUCCESS
;
2545 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2547 /* Our FOBX if set, has to be a VNetRoot */
2548 if (Context
->pFobx
!= NULL
)
2550 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2551 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2553 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2555 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2559 --Fcb
->UncleanCount
;
2570 RxCommonDevFCBClose(
2571 PRX_CONTEXT Context
)
2575 PMRX_V_NET_ROOT NetRoot
;
2579 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2581 Fcb
= Context
->pFcb
;
2582 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2583 Status
= STATUS_SUCCESS
;
2584 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2586 /* Our FOBX if set, has to be a VNetRoot */
2587 if (NetRoot
!= NULL
)
2589 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2590 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2592 --NetRoot
->NumberOfOpens
;
2593 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2597 Status
= STATUS_NOT_IMPLEMENTED
;
2599 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2611 RxCommonDevFCBFsCtl(
2612 PRX_CONTEXT Context
)
2615 return STATUS_NOT_IMPLEMENTED
;
2623 RxCommonDevFCBIoCtl(
2624 PRX_CONTEXT Context
)
2630 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2632 if (Context
->pFobx
!= NULL
)
2634 return STATUS_INVALID_HANDLE
;
2637 /* Is that a prefix claim from MUP? */
2638 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2640 return RxPrefixClaim(Context
);
2643 /* Otherwise, pass through the mini-rdr */
2644 Status
= RxXXXControlFileCallthru(Context
);
2645 if (Status
!= STATUS_PENDING
)
2647 if (Context
->PostRequest
)
2649 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2650 Status
= RxFsdPostRequest(Context
);
2654 DPRINT("Status: %lx\n", Status
);
2660 RxCommonDevFCBQueryVolInfo(
2661 PRX_CONTEXT Context
)
2664 return STATUS_NOT_IMPLEMENTED
;
2672 RxCommonDeviceControl(
2673 PRX_CONTEXT Context
)
2679 /* Prefix claim is only allowed for device, not files */
2680 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2682 return STATUS_INVALID_DEVICE_REQUEST
;
2685 /* Submit to mini-rdr */
2686 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2687 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2688 if (Status
== STATUS_PENDING
)
2690 RxDereferenceAndDeleteRxContext_Real(Context
);
2701 RxCommonDirectoryControl(
2702 PRX_CONTEXT Context
)
2707 PIO_STACK_LOCATION Stack
;
2711 Fcb
= (PFCB
)Context
->pFcb
;
2712 Fobx
= (PFOBX
)Context
->pFobx
;
2713 Stack
= Context
->CurrentIrpSp
;
2714 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2716 /* Call the appropriate helper */
2717 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2719 Status
= RxQueryDirectory(Context
);
2721 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2723 Status
= RxNotifyChangeDirectory(Context
);
2724 if (Status
== STATUS_PENDING
)
2726 RxDereferenceAndDeleteRxContext_Real(Context
);
2731 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2739 RxCommonDispatchProblem(
2740 PRX_CONTEXT Context
)
2743 return STATUS_NOT_IMPLEMENTED
;
2748 RxCommonFileSystemControl(
2749 PRX_CONTEXT Context
)
2753 PIO_STACK_LOCATION Stack
;
2757 Irp
= Context
->CurrentIrp
;
2758 Stack
= Context
->CurrentIrpSp
;
2759 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2761 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2764 return STATUS_NOT_IMPLEMENTED
;
2769 RxCommonFlushBuffers(
2770 PRX_CONTEXT Context
)
2773 return STATUS_NOT_IMPLEMENTED
;
2778 RxCommonLockControl(
2779 PRX_CONTEXT Context
)
2782 return STATUS_NOT_IMPLEMENTED
;
2788 PRX_CONTEXT Context
)
2791 return STATUS_NOT_IMPLEMENTED
;
2799 RxCommonQueryInformation(
2800 PRX_CONTEXT Context
)
2802 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2803 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2804 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2811 PIO_STACK_LOCATION Stack
;
2812 FILE_INFORMATION_CLASS FileInfoClass
;
2816 Fcb
= (PFCB
)Context
->pFcb
;
2817 Fobx
= (PFOBX
)Context
->pFobx
;
2818 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2820 Irp
= Context
->CurrentIrp
;
2821 Stack
= Context
->CurrentIrpSp
;
2822 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2823 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2825 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2826 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2833 /* Get a writable buffer */
2834 Buffer
= RxMapSystemBuffer(Context
);
2837 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2841 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2843 /* Validate file type */
2844 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2846 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2848 Status
= STATUS_INVALID_PARAMETER
;
2851 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2853 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2855 Status
= STATUS_NOT_IMPLEMENTED
;
2859 Status
= STATUS_INVALID_PARAMETER
;
2866 /* Acquire the right lock */
2867 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2868 FileInfoClass
!= FileNameInformation
)
2870 if (FileInfoClass
== FileCompressionInformation
)
2872 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2876 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2879 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2881 Status
= STATUS_PENDING
;
2884 else if (!NT_SUCCESS(Status
))
2892 /* Dispatch to the right helper */
2893 switch (FileInfoClass
)
2895 case FileBasicInformation
:
2896 Status
= RxQueryBasicInfo(Context
, Buffer
);
2899 case FileStandardInformation
:
2900 Status
= RxQueryStandardInfo(Context
, Buffer
);
2903 case FileInternalInformation
:
2904 Status
= RxQueryInternalInfo(Context
, Buffer
);
2907 case FileEaInformation
:
2908 Status
= RxQueryEaInfo(Context
, Buffer
);
2911 case FileNameInformation
:
2912 Status
= RxQueryNameInfo(Context
, Buffer
);
2915 case FileAllInformation
:
2916 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2917 if (!NT_SUCCESS(Status
))
2922 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2923 if (!NT_SUCCESS(Status
))
2928 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2929 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2930 if (!NT_SUCCESS(Status
))
2935 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2936 sizeof(FILE_STANDARD_INFORMATION
) +
2937 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2938 if (!NT_SUCCESS(Status
))
2943 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2944 sizeof(FILE_STANDARD_INFORMATION
) +
2945 sizeof(FILE_INTERNAL_INFORMATION
) +
2946 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2947 if (!NT_SUCCESS(Status
))
2952 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2953 sizeof(FILE_STANDARD_INFORMATION
) +
2954 sizeof(FILE_INTERNAL_INFORMATION
) +
2955 sizeof(FILE_EA_INFORMATION
) +
2956 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2959 case FileAlternateNameInformation
:
2960 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2963 case FilePipeInformation
:
2964 case FilePipeLocalInformation
:
2965 case FilePipeRemoteInformation
:
2966 Status
= RxQueryPipeInfo(Context
, Buffer
);
2969 case FileCompressionInformation
:
2970 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2974 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2975 Status
= Context
->IoStatusBlock
.Status
;
2979 if (Context
->Info
.Length
< 0)
2981 Status
= STATUS_BUFFER_OVERFLOW
;
2982 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2985 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2991 RxReleaseFcb(Context
, Fcb
);
2996 DPRINT("Status: %x\n", Status
);
2999 #undef SET_SIZE_AND_QUERY
3004 RxCommonQueryQuotaInformation(
3005 PRX_CONTEXT Context
)
3008 return STATUS_NOT_IMPLEMENTED
;
3013 RxCommonQuerySecurity(
3014 PRX_CONTEXT Context
)
3017 return STATUS_NOT_IMPLEMENTED
;
3025 RxCommonQueryVolumeInformation(
3026 PRX_CONTEXT Context
)
3032 PIO_STACK_LOCATION Stack
;
3036 Fcb
= (PFCB
)Context
->pFcb
;
3037 Fobx
= (PFOBX
)Context
->pFobx
;
3039 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3041 Irp
= Context
->CurrentIrp
;
3042 Stack
= Context
->CurrentIrpSp
;
3043 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3044 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3046 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3047 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3048 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3050 /* Forward to mini-rdr */
3051 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3053 /* Post request if mini-rdr asked to */
3054 if (Context
->PostRequest
)
3056 Status
= RxFsdPostRequest(Context
);
3060 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3063 DPRINT("Status: %x\n", Status
);
3070 PRX_CONTEXT RxContext
)
3078 PFILE_OBJECT FileObject
;
3079 LARGE_INTEGER ByteOffset
;
3080 PIO_STACK_LOCATION Stack
;
3081 PLOWIO_CONTEXT LowIoContext
;
3082 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3083 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3084 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3088 Fcb
= (PFCB
)RxContext
->pFcb
;
3089 Fobx
= (PFOBX
)RxContext
->pFobx
;
3090 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3092 /* Get some parameters */
3093 Irp
= RxContext
->CurrentIrp
;
3094 Stack
= RxContext
->CurrentIrpSp
;
3095 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3096 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3097 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3098 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3099 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3100 ReadLength
= Stack
->Parameters
.Read
.Length
;
3101 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3102 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3103 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3105 RxItsTheSameContext();
3107 Irp
->IoStatus
.Information
= 0;
3109 /* Should the read be loud - so far, it's just ignored on ReactOS:
3110 * s/DPRINT/DPRINT1/g will make it loud
3112 LowIoContext
= &RxContext
->LowIoContext
;
3113 CheckForLoudOperations(RxContext
);
3114 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3116 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3117 ByteOffset
, ReadLength
,
3118 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3121 RxDeviceObject
= RxContext
->RxDeviceObject
;
3123 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3125 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3127 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3129 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3131 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3135 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3139 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3143 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3147 /* A pagefile cannot be a pipe */
3148 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3149 if (IsPipe
&& PagingIo
)
3151 return STATUS_INVALID_DEVICE_REQUEST
;
3154 /* Null-length read is no-op */
3155 if (ReadLength
== 0)
3157 return STATUS_SUCCESS
;
3160 /* Validate FCB type */
3161 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3163 return STATUS_INVALID_DEVICE_REQUEST
;
3166 /* Init the lowio context for possible forward */
3167 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3169 PostRequest
= FALSE
;
3170 ReadCachingDisabled
= FALSE
;
3172 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3173 FileObject
= Stack
->FileObject
;
3174 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3179 /* If no caching, make sure current Cc data have been flushed */
3180 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3182 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3183 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3188 else if (Status
!= STATUS_SUCCESS
)
3193 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3194 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3195 RxReleasePagingIoResource(RxContext
, Fcb
);
3197 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3199 Status
= Irp
->IoStatus
.Status
;
3203 RxAcquirePagingIoResource(RxContext
, Fcb
);
3204 RxReleasePagingIoResource(RxContext
, Fcb
);
3207 /* Acquire the appropriate lock */
3208 if (PagingIo
&& !ReadCachingEnabled
)
3212 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3220 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3225 if (!ReadCachingEnabled
)
3227 if (!CanWait
&& NoCache
)
3229 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3230 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3232 DPRINT1("RdAsyLNG %x\n", RxContext
);
3236 if (Status
!= STATUS_SUCCESS
)
3238 DPRINT1("RdAsyOthr %x\n", RxContext
);
3242 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3244 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3254 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3255 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3260 else if (Status
!= STATUS_SUCCESS
)
3268 RxItsTheSameContext();
3270 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3276 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3278 /* Make sure FLOCK doesn't conflict */
3281 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3283 Status
= STATUS_FILE_LOCK_CONFLICT
;
3288 /* Validate byteoffset vs length */
3289 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3291 if (ByteOffset
.QuadPart
>= FileSize
)
3293 Status
= STATUS_END_OF_FILE
;
3297 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3299 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3304 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3305 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3307 /* File was not cached yet, do it */
3308 if (FileObject
->PrivateCacheMap
== NULL
)
3310 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3312 Status
= STATUS_FILE_CLOSED
;
3316 RxAdjustAllocationSizeforCC(Fcb
);
3318 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3319 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3321 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3323 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3327 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3328 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3331 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3334 /* This should never happen - fix your RDR */
3335 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3340 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3341 Status
= Irp
->IoStatus
.Status
;
3342 ASSERT(NT_SUCCESS(Status
));
3347 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3348 if (SystemBuffer
== NULL
)
3350 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3354 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3356 RxItsTheSameContext();
3358 /* Perform the read */
3359 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3361 if (!ReadCachingEnabled
)
3363 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3366 RxItsTheSameContext();
3372 if (!ReadCachingEnabled
)
3374 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3377 Status
= Irp
->IoStatus
.Status
;
3378 ASSERT(NT_SUCCESS(Status
));
3383 /* Validate the reading */
3384 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3385 ByteOffset
.QuadPart
>= 4096)
3387 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3388 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3391 /* If it's consistent, forward to mini-rdr */
3392 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3393 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3395 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3396 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3398 RxItsTheSameContext();
3400 if (InFsp
&& ReadCachingDisabled
)
3402 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3403 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3407 Status
= RxLowIoReadShell(RxContext
);
3409 RxItsTheSameContext();
3413 if (ByteOffset
.QuadPart
> FileSize
)
3416 Irp
->IoStatus
.Information
= ReadLength
;
3420 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3422 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3425 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3426 RtlZeroMemory(SystemBuffer
, ReadLength
);
3427 Irp
->IoStatus
.Information
= ReadLength
;
3433 RxItsTheSameContext();
3435 /* Post if required */
3438 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3439 Status
= RxFsdPostRequest(RxContext
);
3443 /* Update FO in case of sync IO */
3444 if (!IsPipe
&& !PagingIo
)
3446 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3448 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3453 /* Set FastIo if read was a success */
3454 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3456 if (!IsPipe
&& !PagingIo
)
3458 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3462 /* In case we're done (not expected any further processing */
3463 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3465 /* Release everything that can be */
3466 if (ReadCachingDisabled
)
3472 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3476 RxReleasePagingIoResource(RxContext
, Fcb
);
3483 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3487 RxReleaseFcb(RxContext
, Fcb
);
3492 /* Dereference/Delete context */
3495 RxDereferenceAndDeleteRxContext(RxContext
);
3499 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3501 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3505 /* We cannot return more than asked */
3506 if (Status
== STATUS_SUCCESS
)
3508 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3515 RxDereferenceAndDeleteRxContext(RxContext
);
3526 PRX_CONTEXT Context
)
3529 return STATUS_NOT_IMPLEMENTED
;
3537 RxCommonSetInformation(
3538 PRX_CONTEXT Context
)
3545 PIO_STACK_LOCATION Stack
;
3546 FILE_INFORMATION_CLASS Class
;
3547 BOOLEAN CanWait
, FcbTableAcquired
, FcbAcquired
;
3551 Fcb
= (PFCB
)Context
->pFcb
;
3552 Fobx
= (PFOBX
)Context
->pFobx
;
3553 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3555 Irp
= Context
->CurrentIrp
;
3556 Stack
= Context
->CurrentIrpSp
;
3557 Class
= Stack
->Parameters
.SetFile
.FileInformationClass
;
3558 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3559 Irp
->AssociatedIrp
.SystemBuffer
, Stack
->Parameters
.SetFile
.Length
,
3560 Class
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
3562 Status
= STATUS_SUCCESS
;
3563 CanWait
= BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3564 FcbTableAcquired
= FALSE
;
3565 FcbAcquired
= FALSE
;
3566 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3568 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3572 /* Valide the node type first */
3573 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3574 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3576 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
3578 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3580 Status
= STATUS_SUCCESS
;
3583 else if (NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
3585 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
3587 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3591 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb
));
3592 _SEH2_TRY_RETURN(Status
= STATUS_INVALID_PARAMETER
);
3597 /* We don't autorize advance operation */
3598 if (Class
== FileEndOfFileInformation
&& Stack
->Parameters
.SetFile
.AdvanceOnly
)
3600 DPRINT1("Not allowed\n");
3602 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3605 /* For these to classes, we'll have to deal with the FCB table (removal)
3606 * We thus need the exclusive FCB table lock
3608 if (Class
== FileDispositionInformation
|| Class
== FileRenameInformation
)
3610 RxPurgeRelatedFobxs(NetRoot
, Context
, TRUE
, Fcb
);
3611 RxScavengeFobxsForNetRoot(NetRoot
, Fcb
, TRUE
);
3613 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, CanWait
))
3615 Context
->PostRequest
= TRUE
;
3616 _SEH2_TRY_RETURN(Status
= STATUS_PENDING
);
3619 FcbTableAcquired
= TRUE
;
3622 /* Finally, if not paging file, we need exclusive FCB lock */
3623 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3625 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
3626 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3628 Context
->PostRequest
= TRUE
;
3629 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3631 else if (Status
!= STATUS_SUCCESS
)
3639 Status
= STATUS_SUCCESS
;
3641 /* And now, perform the job! */
3644 case FileBasicInformation
:
3645 Status
= RxSetBasicInfo(Context
);
3648 case FileDispositionInformation
:
3650 PFILE_DISPOSITION_INFORMATION FDI
;
3652 /* Check whether user wants deletion */
3653 FDI
= Irp
->AssociatedIrp
.SystemBuffer
;
3654 if (FDI
->DeleteFile
)
3656 /* If so, check whether it's doable */
3657 if (!MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForDelete
))
3659 Status
= STATUS_CANNOT_DELETE
;
3662 /* And if doable, already remove from FCB table */
3663 if (Status
== STATUS_SUCCESS
)
3665 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3666 RxRemoveNameNetFcb(Fcb
);
3668 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3669 FcbTableAcquired
= FALSE
;
3673 /* If it succeed, perform the operation */
3674 if (Status
== STATUS_SUCCESS
)
3676 Status
= RxSetDispositionInfo(Context
);
3682 case FilePositionInformation
:
3683 Status
= RxSetPositionInfo(Context
);
3686 case FileAllocationInformation
:
3687 Status
= RxSetAllocationInfo(Context
);
3690 case FileEndOfFileInformation
:
3691 Status
= RxSetEndOfFileInfo(Context
);
3694 case FilePipeInformation
:
3695 case FilePipeLocalInformation
:
3696 case FilePipeRemoteInformation
:
3697 Status
= RxSetPipeInfo(Context
);
3700 case FileRenameInformation
:
3701 case FileLinkInformation
:
3702 case FileMoveClusterInformation
:
3703 /* If we can wait, try to perform the operation right now */
3706 /* Of course, collapsing is not doable anymore, file is
3707 * in an inbetween state
3709 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
3711 /* Set the information */
3712 Status
= RxSetRenameInfo(Context
);
3713 /* If it succeed, drop the current entry from FCB table */
3714 if (Status
== STATUS_SUCCESS
&& Class
== FileRenameInformation
)
3716 ASSERT(FcbAcquired
&& FcbTableAcquired
);
3717 RxRemoveNameNetFcb(Fcb
);
3719 _SEH2_TRY_RETURN(Status
);
3721 /* Can't wait? Post for async retry */
3724 Status
= RxFsdPostRequest(Context
);
3725 _SEH2_TRY_RETURN(Status
);
3729 case FileValidDataLengthInformation
:
3730 if (!MmCanFileBeTruncated(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
))
3732 Status
= STATUS_USER_MAPPED_FILE
;
3736 case FileShortNameInformation
:
3737 Status
= RxSetSimpleInfo(Context
);
3741 DPRINT1("Insupported class: %x\n", Class
);
3742 Status
= STATUS_INVALID_PARAMETER
;
3748 /* If mini-rdr was OK and wants a re-post on this, do it */
3749 if (Status
== STATUS_SUCCESS
)
3751 if (Context
->PostRequest
)
3753 Status
= RxFsdPostRequest(Context
);
3759 /* Release any acquired lock */
3762 RxReleaseFcb(Context
, Fcb
);
3765 if (FcbTableAcquired
)
3767 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
3772 #undef _SEH2_TRY_RETURN
3779 RxCommonSetQuotaInformation(
3780 PRX_CONTEXT Context
)
3783 return STATUS_NOT_IMPLEMENTED
;
3788 RxCommonSetSecurity(
3789 PRX_CONTEXT Context
)
3792 return STATUS_NOT_IMPLEMENTED
;
3797 RxCommonSetVolumeInformation(
3798 PRX_CONTEXT Context
)
3801 return STATUS_NOT_IMPLEMENTED
;
3806 RxCommonUnimplemented(
3807 PRX_CONTEXT Context
)
3810 return STATUS_NOT_IMPLEMENTED
;
3816 PRX_CONTEXT RxContext
)
3824 PFILE_OBJECT FileObject
;
3825 PIO_STACK_LOCATION Stack
;
3826 LARGE_INTEGER ByteOffset
;
3827 NODE_TYPE_CODE NodeTypeCode
;
3828 PLOWIO_CONTEXT LowIoContext
;
3829 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3830 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3831 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3832 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3836 Fcb
= (PFCB
)RxContext
->pFcb
;
3837 NodeTypeCode
= NodeType(Fcb
);
3838 /* Validate FCB type */
3839 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3840 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3842 return STATUS_INVALID_DEVICE_REQUEST
;
3845 /* We'll write to file, keep track of it */
3846 Fcb
->IsFileWritten
= TRUE
;
3848 Stack
= RxContext
->CurrentIrpSp
;
3849 /* Set write through if asked */
3850 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3852 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3855 Fobx
= (PFOBX
)RxContext
->pFobx
;
3856 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3858 /* Get some parameters */
3859 Irp
= RxContext
->CurrentIrp
;
3860 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3861 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3862 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3863 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3864 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3865 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3866 WriteLength
= Stack
->Parameters
.Write
.Length
;
3867 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3868 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3869 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3871 RxItsTheSameContext();
3873 RxContext
->FcbResourceAcquired
= FALSE
;
3874 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3876 LowIoContext
= &RxContext
->LowIoContext
;
3877 CheckForLoudOperations(RxContext
);
3878 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3880 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3881 ByteOffset
, WriteLength
,
3882 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3885 RxDeviceObject
= RxContext
->RxDeviceObject
;
3887 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3889 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3891 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3893 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3895 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3899 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3903 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3907 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3911 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3912 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3913 /* Keep track for normal writes */
3914 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3923 /* Zero-length write is immediate success */
3924 if (NormalFile
&& WriteLength
== 0)
3926 return STATUS_SUCCESS
;
3929 /* Check whether we have input data */
3930 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3932 return STATUS_INVALID_PARAMETER
;
3935 /* Are we writting to EOF? */
3936 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3937 /* FIXME: validate length/offset */
3939 /* Get our SRV_OPEN in case of normal write */
3942 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3949 FileObject
= Stack
->FileObject
;
3951 /* If we have caching enabled, check whether we have to defer write */
3954 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3956 if (!CcCanIWrite(FileObject
, WriteLength
,
3957 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3958 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
3962 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3964 RxPrePostIrp(RxContext
, Irp
);
3966 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3968 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
3970 return STATUS_PENDING
;
3975 /* Initialize the low IO context for write */
3976 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
3978 /* Initialize our (many) booleans */
3979 RecursiveWriteThrough
= FALSE
;
3980 CalledByLazyWriter
= FALSE
;
3981 SwitchBackToAsync
= FALSE
;
3982 ExtendingFile
= FALSE
;
3983 ExtendingValidData
= FALSE
;
3984 UnwindOutstandingAsync
= FALSE
;
3985 ResourceOwnerSet
= FALSE
;
3987 ContextReferenced
= FALSE
;
3989 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3993 /* No volume FCB here! */
3994 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
3995 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
3996 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
3998 /* Writing to EOF on a paging file is non sense */
3999 ASSERT(!(WriteToEof
&& PagingIo
));
4001 RxItsTheSameContext();
4003 /* Start locking stuff */
4004 if (!PagingIo
&& !NoPreposting
)
4006 /* If it's already acquired, all fine */
4007 if (RxContext
->FcbResourceAcquired
)
4013 /* Otherwise, try to acquire shared (excepted for pipes) */
4016 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4019 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
4021 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
4025 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
4028 /* We'll post IRP to retry */
4029 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4032 DPRINT1("Failed to acquire lock!\n");
4033 _SEH2_TRY_RETURN(Status
);
4036 /* We'll just fail */
4037 if (Status
!= STATUS_SUCCESS
)
4039 _SEH2_TRY_RETURN(Status
);
4042 /* Resource acquired */
4043 RxContext
->FcbResourceAcquired
= TRUE
;
4046 /* At that point, resource is acquired */
4049 ASSERT(RxContext
->FcbResourceAcquired
);
4055 /* Now, check whether we have to promote shared lock */
4056 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4058 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
4065 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4066 if (RxIsFcbAcquiredShared(Fcb
) &&
4067 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
4071 RxReleaseFcb(RxContext
, Fcb
);
4072 RxContext
->FcbResourceAcquired
= FALSE
;
4074 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4075 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4078 DPRINT1("Failed to acquire lock!\n");
4079 _SEH2_TRY_RETURN(Status
);
4082 if (Status
!= STATUS_SUCCESS
)
4084 _SEH2_TRY_RETURN(Status
);
4087 RxContext
->FcbResourceAcquired
= TRUE
;
4091 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4092 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
4095 if (RxIsFcbAcquiredExclusive(Fcb
))
4097 RxConvertToSharedFcb(RxContext
, Fcb
);
4102 /* We're extending file, disable collapsing */
4103 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
4105 DPRINT("Disabling collapsing\n");
4107 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
4109 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
4113 ASSERT(RxContext
->FcbResourceAcquired
);
4116 /* Keep track of the acquired resource */
4117 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
4124 /* Lock the paging resource */
4125 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
4127 /* Keep track of the acquired resource */
4128 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
4134 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
4137 /* If it's a non cached write, or if caching is disallowed */
4138 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4140 /* If cache was previously enabled, we'll have to flush before writing */
4141 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
4143 LARGE_INTEGER FlushOffset
;
4146 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
4148 /* If shared, we'll have to relock exclusive */
4149 if (!RxIsFcbAcquiredExclusive(Fcb
))
4151 /* Release and retry exclusive */
4152 RxReleaseFcb(RxContext
, Fcb
);
4153 RxContext
->FcbResourceAcquired
= FALSE
;
4155 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4156 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4159 DPRINT1("Failed to acquire lock for flush!\n");
4160 _SEH2_TRY_RETURN(Status
);
4163 if (Status
!= STATUS_SUCCESS
)
4165 _SEH2_TRY_RETURN(Status
);
4168 RxContext
->FcbResourceAcquired
= TRUE
;
4171 /* Get the length to flush */
4174 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
4178 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
4181 /* Perform the flushing */
4182 RxAcquirePagingIoResource(RxContext
, Fcb
);
4183 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
4184 WriteLength
, &Irp
->IoStatus
);
4185 RxReleasePagingIoResource(RxContext
, Fcb
);
4187 /* Cannot continue if flushing failed */
4188 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
4190 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
4194 RxAcquirePagingIoResource(RxContext
, Fcb
);
4195 RxReleasePagingIoResource(RxContext
, Fcb
);
4198 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
4199 &FlushOffset
, WriteLength
, FALSE
);
4203 /* If not paging IO, check if write is allowed */
4206 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4208 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4212 /* Get file sizes */
4213 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4214 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4215 ASSERT(ValidDataLength
<= FileSize
);
4217 /* If paging IO, we cannot write past file size
4218 * so fix write length if needed
4222 if (ByteOffset
.QuadPart
>= FileSize
)
4224 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4227 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4229 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4233 /* If we're being called by the lazywrite */
4234 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4236 CalledByLazyWriter
= TRUE
;
4238 /* Fail if we're beyong VDL */
4239 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4241 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4242 (ByteOffset
.QuadPart
< FileSize
))
4244 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4246 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4252 /* If that's a recursive synchronous page write */
4253 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4254 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4258 /* Check the top level IRP on the FastIO path */
4259 TopIrp
= RxGetTopIrpIfRdbssIrp();
4260 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4262 PIO_STACK_LOCATION IrpStack
;
4264 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4266 /* If the top level IRP was a cached write for this file, keep track */
4267 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4268 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4269 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4271 RecursiveWriteThrough
= TRUE
;
4272 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4277 /* Now, deal with file size and VDL */
4278 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4279 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4281 /* Not sync? Let's make it sync, just the time we extended */
4285 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4286 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4289 /* Keep track we'll have to switch back to async */
4292 SwitchBackToAsync
= TRUE
;
4296 /* Release all the locks */
4297 RxWriteReleaseResources(RxContext
, 0);
4299 /* Acquire exclusive */
4300 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4301 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4304 DPRINT1("Failed to acquire lock for extension!\n");
4305 _SEH2_TRY_RETURN(Status
);
4308 if (Status
!= STATUS_SUCCESS
)
4310 _SEH2_TRY_RETURN(Status
);
4313 RxContext
->FcbResourceAcquired
= TRUE
;
4315 RxItsTheSameContext();
4317 /* Get the sizes again, to be sure they didn't change in the meantime */
4318 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4319 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4320 ASSERT(ValidDataLength
<= FileSize
);
4322 /* Check we can switch back to async? */
4323 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4324 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4326 SwitchBackToAsync
= FALSE
;
4329 /* If paging IO, check we don't try to extend the file */
4332 if (ByteOffset
.QuadPart
>= FileSize
)
4334 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4337 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4339 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4344 /* Save our initial sizes for potential rollback */
4345 InitialFileSize
= FileSize
;
4346 InitialValidDataLength
= ValidDataLength
;
4347 /* If writing to EOF, update byte offset with file size */
4350 ByteOffset
.QuadPart
= FileSize
;
4353 /* Check again whether we're allowed to write */
4356 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4358 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4361 /* Do we have to extend? */
4362 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4364 DPRINT("Need to extend file\n");
4365 ExtendingFile
= TRUE
;
4366 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4370 /* Let's start to extend */
4373 /* If we're past allocating, inform mini-rdr */
4374 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4375 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4377 LARGE_INTEGER NewAllocationSize
;
4379 DPRINT("Extending %p\n", RxContext
);
4383 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4384 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4385 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4389 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4390 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4391 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4394 if (!NT_SUCCESS(Status
))
4396 _SEH2_TRY_RETURN(Status
);
4399 if (FileSize
> NewAllocationSize
.QuadPart
)
4401 NewAllocationSize
.QuadPart
= FileSize
;
4404 /* And update FCB */
4405 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4408 /* Set the new sizes */
4409 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4410 RxAdjustAllocationSizeforCC(Fcb
);
4413 if (CcIsFileCached(FileObject
))
4415 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4419 /* Do we have to extend VDL? */
4420 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4422 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4424 ExtendingValidData
= TRUE
;
4425 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4429 /* If none cached write */
4430 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4432 /* Switch back to async, if asked to */
4433 if (SwitchBackToAsync
)
4438 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4439 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4442 /* If not synchronous, keep track of writes to be finished */
4445 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4447 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4448 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4449 NotificationEvent
, FALSE
);
4452 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4454 &RxStrucSupSpinLock
) == 0)
4456 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4459 UnwindOutstandingAsync
= TRUE
;
4460 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4463 /* Set our LOWIO_CONTEXT information */
4464 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4465 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4467 RxItsTheSameContext();
4469 /* We have to be locked */
4470 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4472 /* Update thread ID if we're in FSP */
4475 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4477 if (RxContext
->FcbResourceAcquired
)
4479 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4482 if (RxContext
->FcbPagingIoResourceAcquired
)
4484 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4487 ResourceOwnerSet
= TRUE
;
4490 /* And perform the write */
4491 Status
= RxLowIoWriteShell(RxContext
);
4493 RxItsTheSameContext();
4495 /* Not outstanding write anymore */
4496 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4498 UnwindOutstandingAsync
= FALSE
;
4504 /* If cache wasn't enabled yet, do it */
4505 if (FileObject
->PrivateCacheMap
== NULL
)
4507 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4509 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4512 RxAdjustAllocationSizeforCC(Fcb
);
4514 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4515 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4517 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4520 /* If that's a MDL backed write */
4521 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4523 /* Shouldn't happen */
4527 /* Perform it, though */
4528 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4529 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4531 Status
= Irp
->IoStatus
.Status
;
4536 ULONG BreakpointsSave
;
4538 /* Map the user buffer */
4539 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4540 if (SystemBuffer
== NULL
)
4542 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4545 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4547 RxItsTheSameContext();
4549 /* And deal with Cc */
4550 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4553 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4555 RxItsTheSameContext();
4557 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4558 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4564 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4565 Irp
->IoStatus
.Information
= WriteLength
;
4567 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4569 RxItsTheSameContext();
4571 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4572 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4579 /* If we've to post the IRP */
4582 /* Reset the file size if required */
4583 if (ExtendingFile
&& !IsPipe
)
4585 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4586 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4588 RxAcquirePagingIoResource(RxContext
, Fcb
);
4589 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4590 RxReleasePagingIoResource(RxContext
, Fcb
);
4592 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4594 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4598 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4599 ContextReferenced
= TRUE
;
4602 ASSERT(!ResourceOwnerSet
);
4603 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4605 #ifdef RDBSS_TRACKER
4606 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4609 /* And post the request */
4610 Status
= RxFsdPostRequest(RxContext
);
4616 /* Update FILE_OBJECT if synchronous write succeed */
4619 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4621 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4625 /* If write succeed, ,also update FILE_OBJECT flags */
4626 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4628 /* File was modified */
4631 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4634 /* If was even extended */
4637 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4640 /* If VDL was extended, update FCB and inform Cc */
4641 if (ExtendingValidData
)
4643 LONGLONG LastOffset
;
4645 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4646 if (FileSize
< LastOffset
)
4648 LastOffset
= FileSize
;
4651 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4653 if (NoCache
&& CcIsFileCached(FileObject
))
4655 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4664 /* Finally, if we failed while extension was required */
4665 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4670 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4672 RxAcquirePagingIoResource(RxContext
, Fcb
);
4673 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4674 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4675 RxReleasePagingIoResource(RxContext
, Fcb
);
4677 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4679 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4684 /* One async write less */
4685 if (UnwindOutstandingAsync
)
4689 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4690 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4693 /* And now, cleanup everything */
4694 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4696 /* If we didn't post, release every lock (for posting, it's already done) */
4699 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4702 /* If the context was referenced - posting, dereference it */
4703 if (ContextReferenced
)
4705 RxDereferenceAndDeleteRxContext(RxContext
);
4708 /* If that's a pipe operation, resume any blocked one */
4711 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4713 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4717 /* Sanity check for write */
4718 if (Status
== STATUS_SUCCESS
)
4720 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4723 /* Just dereference our context */
4727 RxDereferenceAndDeleteRxContext(RxContext
);
4732 #undef _SEH2_TRY_RETURN
4743 IN PRX_CONTEXT RxContext
)
4746 PFILE_OBJECT FileObject
;
4747 PIO_STACK_LOCATION Stack
;
4749 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4753 Irp
= RxContext
->CurrentIrp
;
4754 Stack
= RxContext
->CurrentIrpSp
;
4755 FileObject
= Stack
->FileObject
;
4757 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4758 switch (RxContext
->MajorFunction
)
4760 /* Call the Cc function */
4762 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4766 /* If here, we can wait */
4767 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4769 /* Call the Cc function */
4770 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4772 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4776 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4777 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4782 Irp
->MdlAddress
= NULL
;
4784 /* And complete the IRP */
4785 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4787 #undef BugCheckFileId
4789 return STATUS_SUCCESS
;
4796 RxConjureOriginalName(
4799 PULONG ActualNameLength
,
4800 PWCHAR OriginalName
,
4801 PLONG LengthRemaining
,
4802 RX_NAME_CONJURING_METHODS NameConjuringMethod
)
4805 PV_NET_ROOT VNetRoot
;
4806 USHORT PrefixLength
, NameLength
, ToCopy
;
4810 VNetRoot
= Fcb
->VNetRoot
;
4811 /* We will use the prefix contained in NET_ROOT, if we don't have
4812 * a V_NET_ROOT, or if it wasn't null deviced or if we already have
4814 if (VNetRoot
== NULL
|| VNetRoot
->PrefixEntry
.Prefix
.Buffer
[1] != L
';' ||
4815 BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_UNC_NAME
))
4817 Prefix
= ((PNET_ROOT
)Fcb
->pNetRoot
)->PrefixEntry
.Prefix
.Buffer
;
4818 PrefixLength
= ((PNET_ROOT
)Fcb
->pNetRoot
)->PrefixEntry
.Prefix
.Length
;
4821 /* In that case, keep track that we will have a prefix as buffer */
4822 NameConjuringMethod
= VNetRoot_As_Prefix
;
4826 ASSERT(NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
4828 /* Otherwise, return the prefix from our V_NET_ROOT */
4829 Prefix
= VNetRoot
->PrefixEntry
.Prefix
.Buffer
;
4830 PrefixLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
;
4831 NameLength
= VNetRoot
->NamePrefix
.Length
;
4833 /* If we want a UNC path, skip potential device */
4834 if (NameConjuringMethod
== VNetRoot_As_UNC_Name
)
4839 PrefixLength
-= sizeof(WCHAR
);
4840 } while (PrefixLength
> 0 && Prefix
[0] != L
'\\');
4844 /* If we added an extra backslash, skip it */
4845 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ADDEDBACKSLASH
))
4847 NameLength
+= sizeof(WCHAR
);
4850 /* If we're asked for a drive letter, skip the prefix */
4851 if (NameConjuringMethod
== VNetRoot_As_DriveLetter
)
4855 /* And make sure we arrive at a backslash */
4856 if (Fcb
->FcbTableEntry
.Path
.Length
> NameLength
&&
4857 Fcb
->FcbTableEntry
.Path
.Buffer
[NameLength
/ sizeof(WCHAR
)] != L
'\\')
4859 NameLength
-= sizeof(WCHAR
);
4864 /* Prepare to copy the prefix, make sure not to overflow */
4865 if (*LengthRemaining
>= PrefixLength
)
4867 /* Copy everything */
4868 ToCopy
= PrefixLength
;
4869 *LengthRemaining
= *LengthRemaining
- PrefixLength
;
4873 /* Copy as much as we can */
4874 ToCopy
= *LengthRemaining
;
4875 /* And return failure */
4876 *LengthRemaining
= -1;
4879 /* Copy the prefix */
4880 RtlCopyMemory(OriginalName
, Prefix
, ToCopy
);
4883 /* Do we have a name to copy now? */
4884 if (Fcb
->FcbTableEntry
.Path
.Length
> NameLength
)
4886 ToCopy
= Fcb
->FcbTableEntry
.Path
.Length
- NameLength
;
4887 Name
= Fcb
->FcbTableEntry
.Path
.Buffer
;
4891 /* Just use slash for now */
4892 ToCopy
= sizeof(WCHAR
);
4897 /* Total length we will have in the output buffer (if everything is alright) */
4898 *ActualNameLength
= ToCopy
+ PrefixLength
;
4899 /* If we still have room to write data */
4900 if (*LengthRemaining
!= -1)
4902 /* If we can copy everything, it's fine! */
4903 if (*LengthRemaining
> ToCopy
)
4905 *LengthRemaining
= *LengthRemaining
- ToCopy
;
4907 /* Otherwise, copy as much as possible, and return failure */
4910 ToCopy
= *LengthRemaining
;
4911 *LengthRemaining
= -1;
4914 /* Copy name after the prefix */
4915 RtlCopyMemory(Add2Ptr(OriginalName
, PrefixLength
),
4916 Add2Ptr(Name
, NameLength
), ToCopy
);
4924 RxCopyCreateParameters(
4925 IN PRX_CONTEXT RxContext
)
4929 PFILE_OBJECT FileObject
;
4930 PIO_STACK_LOCATION Stack
;
4931 PDFS_NAME_CONTEXT DfsNameContext
;
4932 PIO_SECURITY_CONTEXT SecurityContext
;
4934 Irp
= RxContext
->CurrentIrp
;
4935 Stack
= RxContext
->CurrentIrpSp
;
4936 FileObject
= Stack
->FileObject
;
4937 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4939 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4940 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4942 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4943 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4944 RxContext
->Create
.SdLength
);
4946 if (SecurityContext
->SecurityQos
!= NULL
)
4948 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4952 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4954 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4956 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4957 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4958 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4959 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4960 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4962 DfsContext
= FileObject
->FsContext2
;
4963 DfsNameContext
= FileObject
->FsContext
;
4964 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4965 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4966 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4967 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4968 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4969 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4970 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4971 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4972 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4973 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4974 FileObject
->FsContext2
= NULL
;
4975 FileObject
->FsContext
= NULL
;
4977 RxContext
->pFcb
= NULL
;
4978 RxContext
->Create
.ReturnedCreateInformation
= 0;
4980 /* if we stripped last \, it has to be a directory! */
4981 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4983 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4986 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4987 if (RxContext
->Create
.EaLength
== 0)
4989 RxContext
->Create
.EaBuffer
= NULL
;
4993 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4994 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4999 RxCreateFromNetRoot(
5000 PRX_CONTEXT Context
,
5001 PUNICODE_STRING NetRootName
)
5006 PFILE_OBJECT FileObject
;
5007 PIO_STACK_LOCATION Stack
;
5008 ACCESS_MASK DesiredAccess
;
5009 USHORT DesiredShareAccess
;
5013 /* Validate that the context is consistent */
5014 if (Context
->Create
.pNetRoot
== NULL
)
5016 return STATUS_BAD_NETWORK_PATH
;
5019 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
5020 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
5022 return STATUS_BAD_NETWORK_PATH
;
5025 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
5026 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
5028 return STATUS_DFS_UNAVAILABLE
;
5031 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
5032 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
5034 return STATUS_OBJECT_TYPE_MISMATCH
;
5037 Stack
= Context
->CurrentIrpSp
;
5038 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
5039 if (NetRoot
->Type
== NET_ROOT_PRINT
)
5041 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
5044 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
5046 /* Get file object */
5047 FileObject
= Stack
->FileObject
;
5049 /* Do we have to open target directory for renaming? */
5050 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
5052 DPRINT("Opening target directory\n");
5054 /* If we have been asked for delete, try to purge first */
5055 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
))
5057 RxPurgeRelatedFobxs((PNET_ROOT
)Context
->Create
.pVNetRoot
->pNetRoot
, Context
,
5058 ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
5061 /* Create the FCB */
5062 Fcb
= RxCreateNetFcb(Context
, (PV_NET_ROOT
)Context
->Create
.pVNetRoot
, NetRootName
);
5065 return STATUS_INSUFFICIENT_RESOURCES
;
5068 /* Fake it: it will be used only renaming */
5069 NodeType(Fcb
) = RDBSS_NTC_OPENTARGETDIR_FCB
;
5070 Context
->Create
.FcbAcquired
= FALSE
;
5071 Context
->Create
.NetNamePrefixEntry
= NULL
;
5073 /* Assign it to the FO */
5074 FileObject
->FsContext
= Fcb
;
5076 /* If we have a FOBX already, check whether it's for DFS opening */
5077 if (Context
->pFobx
!= NULL
)
5079 /* If so, reflect this in the FOBX */
5080 if (FileObject
->FsContext2
== UIntToPtr(DFS_OPEN_CONTEXT
))
5082 SetFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
5086 ClearFlag(Context
->pFobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
5090 /* Acquire the FCB */
5091 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
5092 if (Status
!= STATUS_SUCCESS
)
5097 /* Reference the FCB and release */
5098 RxReferenceNetFcb(Fcb
);
5099 RxReleaseFcb(Context
, Fcb
);
5102 return STATUS_SUCCESS
;
5105 /* Try to find (or create) the FCB for the file */
5106 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
5107 Fcb
= (PFCB
)Context
->pFcb
;
5110 ASSERT(!NT_SUCCESS(Status
));
5112 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
5117 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
5119 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
5123 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
5126 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
5127 if (NT_SUCCESS(Status
))
5129 RxTransitionNetFcb(Fcb
, Condition_Good
);
5130 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
5132 RxSetupNetFileObject(Context
);
5133 return STATUS_SUCCESS
;
5137 /* Check SA for conflict */
5138 if (Fcb
->OpenCount
> 0)
5140 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5141 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
5142 if (!NT_SUCCESS(Status
))
5144 RxDereferenceNetFcb(Fcb
);
5149 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
5150 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
5157 /* Find a SRV_OPEN that suits the opening */
5158 Status
= RxCollapseOrCreateSrvOpen(Context
);
5159 if (Status
== STATUS_SUCCESS
)
5164 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
5165 Fobx
= (PFOBX
)Context
->pFobx
;
5166 /* There are already opens, check for conflict */
5167 if (Fcb
->OpenCount
!= 0)
5169 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
5170 FileObject
, &Fcb
->ShareAccess
,
5171 FALSE
, "second check per useropens",
5174 ++SrvOpen
->UncleanFobxCount
;
5175 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
5182 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
5184 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
5185 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
5189 RxSetupNetFileObject(Context
);
5191 /* No conflict? Set up SA */
5192 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
5194 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
5197 ++Fcb
->UncleanCount
;
5198 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
5200 ++Fcb
->UncachedUncleanCount
;
5203 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
5204 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
5206 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
5209 /* No pending close, we're active */
5210 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
5213 ++SrvOpen
->UncleanFobxCount
;
5214 ++SrvOpen
->OpenCount
;
5215 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
5217 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
5219 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
5220 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
5222 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
5223 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
5225 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5228 /* Now, update SA for the SRV_OPEN */
5229 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
5231 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
5233 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
5236 /* Update the FOBX info */
5239 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5241 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
5244 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
5245 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
5247 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
5249 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
5250 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
5252 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
5253 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
5254 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
5256 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
5257 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
5261 Status
= STATUS_SUCCESS
;
5266 if (Fcb
->OpenCount
== 0)
5268 if (Context
->Create
.FcbAcquired
)
5270 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
5274 if (!Context
->Create
.FcbAcquired
)
5276 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
5282 RxDereferenceNetFcb(Fcb
);
5294 RxCreateTreeConnect(
5295 IN PRX_CONTEXT RxContext
)
5298 PV_NET_ROOT VNetRoot
;
5299 PFILE_OBJECT FileObject
;
5300 PIO_STACK_LOCATION Stack
;
5301 NET_ROOT_TYPE NetRootType
;
5302 UNICODE_STRING CanonicalName
, RemainingName
;
5306 Stack
= RxContext
->CurrentIrpSp
;
5307 FileObject
= Stack
->FileObject
;
5309 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
5310 /* As long as we don't know connection type, mark it wild */
5311 NetRootType
= NET_ROOT_WILD
;
5312 /* Get the type by parsing the name */
5313 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
5314 if (!NT_SUCCESS(Status
))
5319 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
5320 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
5321 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
5322 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
5323 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
5324 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
5326 /* We don't handle EA - they come from DFS, don't care */
5327 if (Stack
->Parameters
.Create
.EaLength
> 0)
5332 /* Mount if required */
5333 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5334 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
5336 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
5337 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
5340 if (!NT_SUCCESS(Status
))
5345 /* Validate the rest of the name with mini-rdr */
5346 if (RemainingName
.Length
> 0)
5348 MINIRDR_CALL(Status
, RxContext
,
5349 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5350 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
5353 if (!NT_SUCCESS(Status
))
5358 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5359 RxReferenceVNetRoot(VNetRoot
);
5360 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
5362 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
5365 FileObject
->FsContext
= &RxDeviceFCB
;
5366 FileObject
->FsContext2
= VNetRoot
;
5368 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
5369 ++VNetRoot
->NumberOfOpens
;
5371 /* Create is over - clear context */
5372 RxContext
->Create
.pSrvCall
= NULL
;
5373 RxContext
->Create
.pNetRoot
= NULL
;
5374 RxContext
->Create
.pVNetRoot
= NULL
;
5381 RxDebugControlCommand(
5382 _In_ PSTR ControlString
)
5390 IN PDRIVER_OBJECT DriverObject
,
5391 IN PUNICODE_STRING RegistryPath
)
5394 USHORT i
, State
= 0;
5396 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
5400 RxCheckFcbStructuresForAlignment();
5402 RtlZeroMemory(&RxData
, sizeof(RxData
));
5403 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
5404 RxData
.NodeByteSize
= sizeof(RxData
);
5405 RxData
.DriverObject
= DriverObject
;
5407 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
5408 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
5409 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5411 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5412 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5414 RxInitializeDebugSupport();
5416 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5417 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5422 RxGetRegistryParameters(RegistryPath
);
5423 RxReadRegistryParameters();
5425 Status
= RxInitializeRegistrationStructures();
5426 if (!NT_SUCCESS(Status
))
5432 RxInitializeDispatcher();
5434 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5436 InitializeListHead(&RxIrpsList
);
5437 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5439 InitializeListHead(&RxActiveContexts
);
5440 InitializeListHead(&RxSrvCalldownList
);
5442 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5443 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5444 KeInitializeMutex(&RxScavengerMutex
, 1);
5445 KeInitializeMutex(&RxSerializationMutex
, 1);
5447 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5449 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5450 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5451 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5454 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5456 RxInitializeDispatchVectors(DriverObject
);
5458 ExInitializeResourceLite(&RxData
.Resource
);
5459 RxData
.OurProcess
= IoGetCurrentProcess();
5461 RxInitializeRxTimer();
5465 if (!NT_SUCCESS(Status
))
5467 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5468 RxInitUnwind(DriverObject
, State
);
5472 /* There are still bits to init - be consider it's fine for now */
5475 return STATUS_NOT_IMPLEMENTED
;
5477 return STATUS_SUCCESS
;
5486 RxDumpCurrentAccess(
5489 _In_ PSZ wherelogtag
,
5490 _In_ PSHARE_ACCESS ShareAccess
)
5502 _In_ PSZ wherelogtag
,
5503 _In_ ACCESS_MASK DesiredAccess
,
5504 _In_ ULONG DesiredShareAccess
)
5515 RxFastIoCheckIfPossible(
5516 PFILE_OBJECT FileObject
,
5517 PLARGE_INTEGER FileOffset
,
5518 ULONG Length
, BOOLEAN Wait
,
5519 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5520 PIO_STATUS_BLOCK IoStatus
,
5521 PDEVICE_OBJECT DeviceObject
)
5525 LARGE_INTEGER LargeLength
;
5529 /* Get the FCB to validate it */
5530 Fcb
= FileObject
->FsContext
;
5531 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5533 DPRINT1("Not a file, FastIO not possible!\n");
5537 if (FileObject
->DeletePending
)
5539 DPRINT1("File delete pending\n");
5543 /* If there's a pending write operation, deny fast operation */
5544 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5546 DPRINT1("Write operations to be completed\n");
5550 /* Deny read on orphaned node */
5551 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5552 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5554 DPRINT1("SRV_OPEN orphaned\n");
5558 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5560 DPRINT1("FCB orphaned\n");
5564 /* If there's a buffering state change pending, deny fast operation (it might change
5567 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5569 DPRINT1("Buffering change pending\n");
5573 /* File got renamed/deleted, deny operation */
5574 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5575 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5577 DPRINT1("File renamed/deleted\n");
5581 /* Process pending change buffering state operations */
5582 FsRtlEnterFileSystem();
5583 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5584 FsRtlExitFileSystem();
5586 LargeLength
.QuadPart
= Length
;
5588 /* If operation to come is a read operation */
5589 if (CheckForReadOperation
)
5591 /* Check that read cache is enabled */
5592 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5594 DPRINT1("Read caching disabled\n");
5598 /* Check whether there's a lock conflict */
5599 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5604 PsGetCurrentProcess()))
5606 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5613 /* Check that write cache is enabled */
5614 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
))
5616 DPRINT1("Write caching disabled\n");
5620 /* Check whether there's a lock conflict */
5621 if (!FsRtlFastCheckLockForWrite(&Fcb
->Specific
.Fcb
.FileLock
,
5626 PsGetCurrentProcess()))
5628 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5637 RxFastIoDeviceControl(
5638 PFILE_OBJECT FileObject
,
5640 PVOID InputBuffer OPTIONAL
,
5641 ULONG InputBufferLength
,
5642 PVOID OutputBuffer OPTIONAL
,
5643 ULONG OutputBufferLength
,
5644 ULONG IoControlCode
,
5645 PIO_STATUS_BLOCK IoStatus
,
5646 PDEVICE_OBJECT DeviceObject
)
5648 /* Only supported IOCTL */
5649 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5666 PFILE_OBJECT FileObject
,
5667 PLARGE_INTEGER FileOffset
,
5672 PIO_STATUS_BLOCK IoStatus
,
5673 PDEVICE_OBJECT DeviceObject
)
5676 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5680 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5681 FileObject
->FsContext2
);
5682 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5684 /* Prepare a TLI context */
5685 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5686 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5687 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5689 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5690 IoStatus
, DeviceObject
, &TopLevelContext
);
5693 DPRINT("Read OK\n");
5697 DPRINT1("Read failed!\n");
5709 PFILE_OBJECT FileObject
,
5710 PLARGE_INTEGER FileOffset
,
5715 PIO_STATUS_BLOCK IoStatus
,
5716 PDEVICE_OBJECT DeviceObject
)
5720 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5724 Fobx
= (PFOBX
)FileObject
->FsContext2
;
5725 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_BAD_HANDLE
))
5730 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5731 FileObject
->FsContext2
);
5732 DPRINT("Writing %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5734 /* Prepare a TLI context */
5735 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5736 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5737 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5739 Ret
= FsRtlCopyWrite2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5740 IoStatus
, DeviceObject
, &TopLevelContext
);
5743 DPRINT("Write OK\n");
5747 DPRINT1("Write failed!\n");
5755 PRX_CONTEXT RxContext
,
5756 PUNICODE_STRING NetRootName
)
5762 PV_NET_ROOT VNetRoot
;
5763 BOOLEAN TableAcquired
, AcquiredExclusive
;
5767 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5768 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5769 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5771 Status
= STATUS_SUCCESS
;
5772 AcquiredExclusive
= FALSE
;
5774 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5775 TableAcquired
= TRUE
;
5776 Version
= NetRoot
->FcbTable
.Version
;
5778 /* Look for a cached FCB */
5779 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5782 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5786 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5787 /* If FCB was to be orphaned, consider it as not suitable */
5788 if (Fcb
->fShouldBeOrphaned
)
5790 RxDereferenceNetFcb(Fcb
);
5791 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5793 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5794 TableAcquired
= TRUE
;
5795 AcquiredExclusive
= TRUE
;
5797 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5798 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5800 RxOrphanThisFcb(Fcb
);
5801 RxDereferenceNetFcb(Fcb
);
5807 /* If FCB was not found or is not covering full path, prepare for more work */
5808 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5812 DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb
->FcbTableEntry
.Path
, NetRootName
);
5815 if (!AcquiredExclusive
)
5817 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5818 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5819 TableAcquired
= TRUE
;
5822 /* If FCB table was updated in between, re-attempt a lookup */
5823 if (NetRoot
->FcbTable
.Version
!= Version
)
5825 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5826 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5833 /* Allocate the FCB */
5838 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5841 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5845 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5846 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5852 if (_SEH2_AbnormalTermination())
5854 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5855 TableAcquired
= FALSE
;
5859 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5861 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5862 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5864 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5873 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5876 if (!NT_SUCCESS(Status
))
5881 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5882 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5884 if (!RxContext
->Create
.FcbAcquired
)
5886 RxWaitForStableNetFcb(Fcb
, RxContext
);
5887 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5888 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5895 RxFirstCanonicalize(
5896 PRX_CONTEXT RxContext
,
5897 PUNICODE_STRING FileName
,
5898 PUNICODE_STRING CanonicalName
,
5899 PNET_ROOT_TYPE NetRootType
)
5903 BOOLEAN UncName
, PrependString
, IsSpecial
;
5904 USHORT CanonicalLength
;
5905 UNICODE_STRING SessionIdString
;
5906 WCHAR SessionIdBuffer
[16];
5910 Type
= NET_ROOT_WILD
;
5911 PrependString
= FALSE
;
5914 Status
= STATUS_SUCCESS
;
5916 /* Name has to contain at least \\ */
5917 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5919 return STATUS_OBJECT_NAME_INVALID
;
5922 /* First easy check, is that a path with a name? */
5923 CanonicalLength
= FileName
->Length
;
5924 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5926 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5928 if (FileName
->Buffer
[3] == ':')
5930 Type
= NET_ROOT_DISK
;
5934 Type
= NET_ROOT_PRINT
;
5939 /* Nope, attempt deeper parsing */
5940 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5943 PWSTR FirstSlash
, EndOfString
;
5945 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5948 /* The lack of drive letter will be replaced by session ID */
5949 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5950 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5951 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5953 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5954 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5956 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5962 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5964 Status
= STATUS_OBJECT_NAME_INVALID
;
5969 DPRINT1("WARNING: Assuming not special + disk!\n");
5970 Type
= NET_ROOT_DISK
;
5971 Status
= STATUS_SUCCESS
;
5972 //Status = STATUS_NOT_IMPLEMENTED;
5973 /* Should be check against IPC, mailslot, and so on */
5977 /* Update net root type with our deduced one */
5978 *NetRootType
= Type
;
5979 DPRINT("Returning type: %x\n", Type
);
5981 if (!NT_SUCCESS(Status
))
5986 /* Do we have to prepend session ID? */
5991 PrependString
= TRUE
;
5992 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5996 /* If not UNC path, we should preprend stuff */
5997 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5999 return STATUS_OBJECT_PATH_INVALID
;
6002 /* Allocate the buffer */
6003 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
6004 if (!NT_SUCCESS(Status
))
6009 /* We don't support that case, we always return disk */
6012 ASSERT(CanonicalName
->Length
== CanonicalLength
);
6014 Status
= STATUS_NOT_IMPLEMENTED
;
6018 /* If we have to prepend, go ahead */
6021 CanonicalName
->Buffer
[0] = '\\';
6022 CanonicalName
->Buffer
[1] = ';';
6023 CanonicalName
->Buffer
[2] = ':';
6024 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
6025 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
6026 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
6028 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
6030 /* Otherwise, that's a simple copy */
6033 RtlCopyUnicodeString(CanonicalName
, FileName
);
6044 RxFreeCanonicalNameBuffer(
6045 PRX_CONTEXT Context
)
6047 /* These two buffers are always the same */
6048 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
6050 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
6052 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
6053 Context
->Create
.CanonicalNameBuffer
= NULL
;
6054 Context
->AlsoCanonicalNameBuffer
= NULL
;
6057 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
6061 RxFsdCommonDispatch(
6062 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
6063 UCHAR MajorFunction
,
6064 PIO_STACK_LOCATION Stack
,
6065 PFILE_OBJECT FileObject
,
6067 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
6071 PRX_CONTEXT Context
;
6072 UCHAR MinorFunction
;
6073 PFILE_OBJECT StackFileObject
;
6074 PRX_FSD_DISPATCH DispatchFunc
;
6075 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6076 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
6078 Status
= STATUS_SUCCESS
;
6080 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
6082 FsRtlEnterFileSystem();
6084 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
6090 PostRequest
= FALSE
;
6091 SetCancelRoutine
= TRUE
;
6092 MinorFunction
= Stack
->MinorFunction
;
6094 switch (MajorFunction
)
6096 case IRP_MJ_FILE_SYSTEM_CONTROL
:
6097 if (FileObject
!= NULL
)
6099 CanWait
= IoIsOperationSynchronous(Irp
);
6109 case IRP_MJ_QUERY_INFORMATION
:
6110 case IRP_MJ_SET_INFORMATION
:
6111 case IRP_MJ_QUERY_EA
:
6113 case IRP_MJ_FLUSH_BUFFERS
:
6114 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
6115 case IRP_MJ_SET_VOLUME_INFORMATION
:
6116 case IRP_MJ_DIRECTORY_CONTROL
:
6117 case IRP_MJ_DEVICE_CONTROL
:
6118 case IRP_MJ_LOCK_CONTROL
:
6119 case IRP_MJ_QUERY_SECURITY
:
6120 case IRP_MJ_SET_SECURITY
:
6121 CanWait
= IoIsOperationSynchronous(Irp
);
6125 case IRP_MJ_CLEANUP
:
6127 SetCancelRoutine
= FALSE
;
6134 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
6135 /* Should we stop it right now, or mini-rdr deserves to know? */
6136 PassToDriver
= TRUE
;
6137 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
6139 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
6141 PassToDriver
= FALSE
;
6142 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6143 DPRINT1("Not started!\n");
6148 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
6150 PassToDriver
= FALSE
;
6151 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
6152 DPRINT1("Not started!\n");
6155 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
6157 StackFileObject
= Stack
->FileObject
;
6158 /* Make sure we don't deal with orphaned stuff */
6159 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
6161 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
6162 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
6163 StackFileObject
->FsContext
!= &RxDeviceFCB
)
6168 Fcb
= StackFileObject
->FsContext
;
6169 Fobx
= StackFileObject
->FsContext2
;
6171 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
6172 ((Fobx
!= NULL
) && BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
)))
6176 PassToDriver
= TRUE
;
6180 PassToDriver
= FALSE
;
6181 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
6182 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
6188 /* Did we receive a close request whereas we're stopping? */
6189 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
6193 Fcb
= StackFileObject
->FsContext
;
6195 DPRINT1("Close received after stop\n");
6196 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6197 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
6199 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
6202 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6203 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
6207 /* Should we stop the whole thing now? */
6210 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
6212 IoMarkIrpPending(Irp
);
6213 Irp
->IoStatus
.Status
= Status
;
6214 Irp
->IoStatus
.Information
= 0;
6215 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6216 Status
= STATUS_PENDING
;
6220 Irp
->IoStatus
.Status
= Status
;
6221 Irp
->IoStatus
.Information
= 0;
6222 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6228 /* No? Allocate a context to deal with the mini-rdr */
6229 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
6230 if (Context
== NULL
)
6232 Status
= STATUS_INSUFFICIENT_RESOURCES
;
6233 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
6237 /* Set cancel routine if required */
6238 if (SetCancelRoutine
)
6240 IoAcquireCancelSpinLock(&OldIrql
);
6241 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
6245 IoAcquireCancelSpinLock(&OldIrql
);
6246 IoSetCancelRoutine(Irp
, NULL
);
6248 IoReleaseCancelSpinLock(OldIrql
);
6250 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6252 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6253 Irp
->IoStatus
.Information
= 0;
6254 /* Get the dispatch routine */
6255 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
6257 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
6259 /* Handle the complete MDL case */
6260 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
6262 DispatchFunc
= RxCompleteMdl
;
6266 /* Do we have to post request? */
6267 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
6273 /* Our read function needs stack, make sure we won't overflow,
6274 * otherwise, post the request
6276 if (MajorFunction
== IRP_MJ_READ
)
6278 if (IoGetRemainingStackSize() < 0xE00)
6280 Context
->PendingReturned
= TRUE
;
6281 Status
= RxPostStackOverflowRead(Context
);
6282 if (Status
!= STATUS_PENDING
)
6284 Context
->PendingReturned
= FALSE
;
6285 RxCompleteAsynchronousRequest(Context
, Status
);
6295 Context
->ResumeRoutine
= DispatchFunc
;
6296 /* There's a dispatch routine? Time to dispatch! */
6297 if (DispatchFunc
!= NULL
)
6299 Context
->PendingReturned
= TRUE
;
6302 Status
= RxFsdPostRequest(Context
);
6306 /* Retry as long as we have */
6309 Status
= DispatchFunc(Context
);
6311 while (Status
== STATUS_RETRY
);
6313 if (Status
== STATUS_PENDING
)
6318 /* Sanity check: did someone mess with our context? */
6319 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
6320 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
6322 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
6323 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
6324 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
6325 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
6326 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
6328 Context
->PendingReturned
= FALSE
;
6329 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
6334 Status
= STATUS_NOT_IMPLEMENTED
;
6341 RxUnwindTopLevelIrp(&TopLevelContext
);
6344 FsRtlExitFileSystem();
6348 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
6358 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
6362 PIO_STACK_LOCATION Stack
;
6363 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
6367 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
6369 Stack
= IoGetCurrentIrpStackLocation(Irp
);
6371 /* Dispatch easy case */
6372 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
6374 return RxSystemControl(RxDeviceObject
, Irp
);
6377 /* Bail out broken cases */
6378 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
6379 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
6381 IoMarkIrpPending(Irp
);
6382 Irp
->IoStatus
.Information
= 0;
6383 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
6384 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6385 return STATUS_PENDING
;
6388 /* Immediately handle create */
6389 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
6391 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6394 /* If not a creation, we must have at least a FO with a FCB */
6395 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
6397 IoMarkIrpPending(Irp
);
6398 Irp
->IoStatus
.Information
= 0;
6399 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6400 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6401 return STATUS_PENDING
;
6404 /* Set the dispatch vector if required */
6405 Fcb
= Stack
->FileObject
->FsContext
;
6406 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
6408 DispatchVector
= &RxFsdDispatchVector
[0];
6412 DispatchVector
= Fcb
->PrivateDispatchVector
;
6415 /* Device cannot accept such requests */
6416 if (RxDeviceObject
== RxFileSystemDeviceObject
)
6418 IoMarkIrpPending(Irp
);
6419 Irp
->IoStatus
.Information
= 0;
6420 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6421 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6422 return STATUS_PENDING
;
6425 /* Dispatch for real! */
6426 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
6434 IN PRX_CONTEXT RxContext
)
6436 /* Initialize posting if required */
6437 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
6439 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
6442 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6443 RxContext
->MinorFunction
, RxContext
,
6444 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6445 RxContext
->SerialNumber
);
6447 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
6448 return STATUS_PENDING
;
6460 WORK_QUEUE_TYPE Queue
;
6461 PRDBSS_DEVICE_OBJECT VolumeDO
;
6462 PRX_CONTEXT RxContext
, EntryContext
;
6466 RxContext
= Context
;
6467 EntryContext
= Context
;
6468 /* Save IRQL at entry for later checking */
6469 EntryIrql
= KeGetCurrentIrql();
6471 /* No FO, deal with device */
6472 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6474 VolumeDO
= RxFileSystemDeviceObject
;
6481 /* Which queue to used for delayed? */
6482 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6484 Queue
= DelayedWorkQueue
;
6488 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6489 Queue
= CriticalWorkQueue
;
6496 BOOLEAN RecursiveCall
;
6497 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6499 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6500 ASSERT(!RxContext
->PostRequest
);
6502 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6503 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6505 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext
->MinorFunction
,
6506 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6507 RxContext
->SerialNumber
);
6509 Irp
= RxContext
->CurrentIrp
;
6511 FsRtlEnterFileSystem();
6513 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6514 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6515 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6516 RxContext
->RxDeviceObject
, TRUE
);
6518 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6520 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6522 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6523 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6526 /* Call the resume routine */
6531 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6533 Status
= RxContext
->ResumeRoutine(RxContext
);
6534 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6536 if (Status
!= STATUS_RETRY
)
6538 Status
= RxCompleteRequest(RxContext
, Status
);
6542 while (Status
== STATUS_RETRY
);
6544 RxUnwindTopLevelIrp(&TopLevelContext
);
6545 FsRtlExitFileSystem();
6547 if (VolumeDO
!= NULL
)
6549 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6555 } while (RxContext
!= NULL
);
6557 /* Did we mess with IRQL? */
6558 if (KeGetCurrentIrql() >= APC_LEVEL
)
6560 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6568 RxGetNetworkProviderPriority(
6569 PUNICODE_STRING DeviceName
)
6580 RxGetRegistryParameters(
6581 IN PUNICODE_STRING RegistryPath
)
6585 UCHAR Buffer
[0x400];
6586 HANDLE DriverHandle
, KeyHandle
;
6587 UNICODE_STRING KeyName
, OutString
;
6588 OBJECT_ATTRIBUTES ObjectAttributes
;
6592 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6593 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6594 if (!NT_SUCCESS(Status
))
6599 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6600 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6601 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6602 if (NT_SUCCESS(Status
))
6604 /* The only parameter we deal with is InitialDebugString */
6605 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6606 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6611 Read
= OutString
.Buffer
;
6612 Write
= (PSTR
)OutString
.Buffer
;
6613 for (i
= 0; i
< OutString
.Length
; ++i
)
6621 /* Which is a string we'll just write out */
6622 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6623 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6629 ZwClose(DriverHandle
);
6637 IN PIO_STACK_LOCATION IrpSp
)
6640 PACCESS_TOKEN Token
;
6641 PIO_SECURITY_CONTEXT SecurityContext
;
6645 /* If that's not a prefix claim, not an open request, session id will be 0 */
6646 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6648 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6653 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6657 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6660 /* Query the session id */
6661 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6662 SeQuerySessionIdToken(Token
, &SessionId
);
6672 RxGetStringRegistryParameter(
6673 IN HANDLE KeyHandle
,
6675 OUT PUNICODE_STRING OutString
,
6677 IN ULONG BufferLength
,
6678 IN BOOLEAN LogFailure
)
6682 UNICODE_STRING KeyString
;
6686 RtlInitUnicodeString(&KeyString
, KeyName
);
6687 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6688 OutString
->Length
= 0;
6689 OutString
->Buffer
= 0;
6690 if (!NT_SUCCESS(Status
))
6694 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6700 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6701 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6702 OutString
->MaximumLength
= OutString
->Length
;
6704 return STATUS_SUCCESS
;
6710 PRDBSS_DEVICE_OBJECT
6711 RxGetTopDeviceObjectIfRdbssIrp(
6715 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6717 TopLevelIrp
= IoGetTopLevelIrp();
6718 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6720 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6730 RxGetTopIrpIfRdbssIrp(
6734 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6736 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6737 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6739 Irp
= TopLevel
->Irp
;
6750 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6753 PACCESS_TOKEN Token
;
6757 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6758 SeQueryAuthenticationIdToken(Token
, &Luid
);
6765 RxIndicateChangeOfBufferingStateForSrvOpen(
6766 PMRX_SRV_CALL SrvCall
,
6767 PMRX_SRV_OPEN SrvOpen
,
6779 RxInitializeDispatchVectors(
6780 PDRIVER_OBJECT DriverObject
)
6786 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6788 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6791 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6792 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6793 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6795 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6796 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6797 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6798 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6799 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6800 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6801 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6802 RxFastIoDispatch
.FastIoLock
= NULL
;
6803 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6804 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6805 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6806 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6807 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6808 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6809 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6810 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6812 RxInitializeTopLevelIrpPackage();
6814 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6815 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6816 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6817 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6819 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6820 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6821 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6822 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6831 return STATUS_NOT_IMPLEMENTED
;
6838 RxInitializeMinirdrDispatchTable(
6839 IN PDRIVER_OBJECT DriverObject
)
6849 RxInitializeRegistrationStructures(
6854 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6855 RxData
.NumberOfMinirdrsRegistered
= 0;
6856 RxData
.NumberOfMinirdrsStarted
= 0;
6857 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6859 return STATUS_SUCCESS
;
6867 RxInitializeTopLevelIrpPackage(
6870 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6871 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6877 PDRIVER_OBJECT DriverObject
,
6887 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6888 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6891 PLIST_ENTRY NextEntry
;
6892 BOOLEAN Found
= FALSE
;
6893 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6895 /* Browse all the allocated TLC to find ours */
6896 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6897 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6898 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6899 NextEntry
= NextEntry
->Flink
)
6901 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6902 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6903 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6906 if (ListContext
== TopLevelContext
)
6912 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6926 /* No associated SRV_OPEN, it's OK to purge */
6927 if (IsListEmpty(&Fcb
->SrvOpenList
))
6932 /* Only allow to purge if all the associated SRV_OPEN
6933 * - have no outstanding opens ongoing
6934 * - have only read attribute set
6936 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6937 Entry
!= &Fcb
->SrvOpenList
;
6938 Entry
= Entry
->Flink
)
6942 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6944 /* Failing previous needs, don't allow purge */
6945 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6946 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6952 /* All correct, allow purge */
6960 RxIsThisAnRdbssTopLevelContext(
6961 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6963 ULONG_PTR StackTop
, StackBottom
;
6965 /* Bail out for flags */
6966 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6971 /* Is our provided TLC allocated on stack? */
6972 IoGetStackLimits(&StackTop
, &StackBottom
);
6973 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6974 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6976 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6977 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6985 /* No, use the helper function */
6986 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6993 RxIsThisTheTopLevelIrp(
6998 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6999 TopLevelIrp
= IoGetTopLevelIrp();
7000 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
7002 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
7005 return (TopLevelIrp
== Irp
);
7010 RxLockOperationCompletion(
7015 return STATUS_NOT_IMPLEMENTED
;
7024 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
7025 IN PUNICODE_STRING OriginatorId
,
7030 PUNICODE_STRING Originator
= OriginatorId
;
7031 LARGE_INTEGER LargeLine
;
7033 /* Set optional parameters */
7034 LargeLine
.QuadPart
= Line
;
7035 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
7037 Originator
= (PUNICODE_STRING
)&unknownId
;
7041 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
7046 RxLogEventWithAnnotation(
7047 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
7050 IN PVOID DataBuffer
,
7051 IN USHORT DataBufferLength
,
7052 IN PUNICODE_STRING Annotation
,
7053 IN ULONG AnnotationCount
)
7061 PRX_CONTEXT RxContext
)
7064 return STATUS_NOT_IMPLEMENTED
;
7072 RxLowIoIoCtlShellCompletion(
7073 PRX_CONTEXT RxContext
)
7080 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
7082 Irp
= RxContext
->CurrentIrp
;
7083 Status
= RxContext
->IoStatusBlock
.Status
;
7085 /* Set information and status */
7086 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
7088 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7091 Irp
->IoStatus
.Status
= Status
;
7097 RxLowIoLockControlShell(
7098 IN PRX_CONTEXT RxContext
)
7101 return STATUS_NOT_IMPLEMENTED
;
7109 RxLowIoNotifyChangeDirectoryCompletion(
7110 PRX_CONTEXT RxContext
)
7114 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
7116 /* Just copy back the IO_STATUS to the IRP */
7117 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
7118 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
7120 return RxContext
->IoStatusBlock
.Status
;
7128 PRX_CONTEXT RxContext
)
7135 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
7137 Fcb
= (PFCB
)RxContext
->pFcb
;
7138 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7140 return STATUS_MORE_PROCESSING_REQUIRED
;
7143 /* Always update stats for disks */
7144 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7146 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7149 /* And forward the read to the mini-rdr */
7150 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
7151 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
7158 RxLowIoReadShellCompletion(
7159 PRX_CONTEXT RxContext
)
7164 BOOLEAN PagingIo
, IsPipe
;
7165 PIO_STACK_LOCATION Stack
;
7166 PLOWIO_CONTEXT LowIoContext
;
7170 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
7172 Status
= RxContext
->IoStatusBlock
.Status
;
7173 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7175 Irp
= RxContext
->CurrentIrp
;
7176 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7178 /* Set IRP information from the RX_CONTEXT status block */
7179 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7181 /* Fixup status for paging file if nothing was read */
7184 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
7186 Status
= STATUS_END_OF_FILE
;
7190 LowIoContext
= &RxContext
->LowIoContext
;
7191 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7193 /* Check broken cases that should never happen */
7194 Fcb
= (PFCB
)RxContext
->pFcb
;
7195 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
7197 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
7200 return STATUS_RETRY
;
7203 else if (Status
== STATUS_SUCCESS
)
7205 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
7207 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
7208 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
7214 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
7220 /* Readahead should go through Cc and not finish here */
7221 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
7223 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7224 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7229 Stack
= RxContext
->CurrentIrpSp
;
7230 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
7231 /* Release lock if required */
7234 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7238 /* Set FastIo if read was a success */
7239 if (NT_SUCCESS(Status
) && !IsPipe
)
7241 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
7244 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7246 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
7250 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7259 /* Final sanity checks */
7260 ASSERT(Status
!= STATUS_RETRY
);
7261 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
7262 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
7272 IN PRX_CONTEXT RxContext
)
7279 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
7281 Fcb
= (PFCB
)RxContext
->pFcb
;
7283 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7284 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7286 /* Always update stats for disks */
7287 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
7289 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
7292 /* And forward the write to the mini-rdr */
7293 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
7294 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
7301 RxLowIoWriteShellCompletion(
7302 PRX_CONTEXT RxContext
)
7308 PLOWIO_CONTEXT LowIoContext
;
7312 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
7314 Status
= RxContext
->IoStatusBlock
.Status
;
7315 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
7317 Irp
= RxContext
->CurrentIrp
;
7319 /* Set IRP information from the RX_CONTEXT status block */
7320 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
7322 LowIoContext
= &RxContext
->LowIoContext
;
7323 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
7325 /* Perform a few sanity checks */
7326 Fcb
= (PFCB
)RxContext
->pFcb
;
7327 if (Status
== STATUS_SUCCESS
)
7329 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
7331 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
7332 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
7335 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
7338 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
7339 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
7341 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
7344 /* In case of async call, perform last bits not done in RxCommonWrite */
7345 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
7347 PFILE_OBJECT FileObject
;
7348 PIO_STACK_LOCATION Stack
;
7350 /* We only succeed if we wrote what was asked for */
7351 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7353 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
7356 /* If write succeed, ,also update FILE_OBJECT flags */
7357 Stack
= RxContext
->CurrentIrpSp
;
7358 FileObject
= Stack
->FileObject
;
7361 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
7364 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
7366 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
7369 /* If VDL was extended, fix attributes */
7370 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
7372 LONGLONG LastOffset
, FileSize
;
7374 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
7375 Irp
->IoStatus
.Information
;
7376 RxGetFileSizeWithLock(Fcb
, &FileSize
);
7378 if (FileSize
< LastOffset
)
7380 LastOffset
= FileSize
;
7383 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
7386 /* One less outstanding write */
7387 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7389 PNON_PAGED_FCB NonPagedFcb
;
7391 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
7392 if (NonPagedFcb
!= NULL
)
7394 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
7395 -1, &RxStrucSupSpinLock
) == 1)
7397 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
7402 /* Release paging resource if acquired */
7403 if (RxContext
->FcbPagingIoResourceAcquired
)
7405 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7408 /* Resume blocked operations for pipes */
7409 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7411 RxResumeBlockedOperations_Serially(RxContext
,
7412 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
7416 /* And release FCB only for files */
7417 if (RxContext
->FcbResourceAcquired
)
7419 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
7423 /* Final sanity checks */
7424 ASSERT(Status
!= STATUS_RETRY
);
7425 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
7426 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
7428 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
7441 RxNotifyChangeDirectory(
7442 PRX_CONTEXT RxContext
)
7446 PIO_STACK_LOCATION Stack
;
7450 /* The IRP can abviously wait */
7451 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
7453 /* Initialize its lowio */
7454 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
7458 /* Lock user buffer */
7459 Stack
= RxContext
->CurrentIrpSp
;
7460 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
7462 /* Copy parameters from IO_STACK */
7463 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
7464 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7465 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7467 /* If we have an associated MDL */
7468 Irp
= RxContext
->CurrentIrp
;
7469 if (Irp
->MdlAddress
!= NULL
)
7471 /* Then, call mini-rdr */
7472 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7473 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7475 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7479 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7484 Status
= STATUS_INVALID_PARAMETER
;
7497 RxPostStackOverflowRead (
7498 IN PRX_CONTEXT RxContext
)
7503 return STATUS_NOT_IMPLEMENTED
;
7510 RxpPrepareCreateContextForReuse(
7511 PRX_CONTEXT RxContext
)
7513 /* Reuse can only happen for open operations (STATUS_RETRY) */
7514 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7516 /* Release the FCB if it was acquired */
7517 if (RxContext
->Create
.FcbAcquired
)
7519 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7520 RxContext
->Create
.FcbAcquired
= FALSE
;
7523 /* Free the canonical name */
7524 RxFreeCanonicalNameBuffer(RxContext
);
7526 /* If we have a VNetRoot associated */
7527 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7529 /* Remove our link and thus, dereference the VNetRoot */
7530 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7531 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7533 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7534 RxContext
->Create
.pVNetRoot
= NULL
;
7536 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7539 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7546 RxpQueryInfoMiniRdr(
7547 PRX_CONTEXT RxContext
,
7548 FILE_INFORMATION_CLASS FileInfoClass
,
7554 Fcb
= (PFCB
)RxContext
->pFcb
;
7556 /* Set the RX_CONTEXT */
7557 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7558 RxContext
->Info
.Buffer
= Buffer
;
7561 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7571 IN PRX_CONTEXT RxContext
)
7575 NET_ROOT_TYPE NetRootType
;
7576 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7580 Irp
= RxContext
->CurrentIrp
;
7582 /* This has to come from MUP */
7583 if (Irp
->RequestorMode
== UserMode
)
7585 return STATUS_INVALID_DEVICE_REQUEST
;
7588 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7590 PQUERY_PATH_REQUEST QueryRequest
;
7592 /* Get parameters */
7593 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7595 /* Don't overflow allocation */
7596 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7598 return STATUS_INVALID_DEVICE_REQUEST
;
7601 /* Forcefully rewrite IRP MJ */
7602 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7604 /* Fake canon name */
7605 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7606 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7608 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7612 /* Copy the prefix to look for */
7613 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7614 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7615 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7617 /* Zero the create parameters */
7618 RtlZeroMemory(&RxContext
->Create
,
7619 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7620 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7621 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7625 /* If not devcontrol, it comes from open, name was already copied */
7626 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7627 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7630 /* Canonilize name */
7631 NetRootType
= NET_ROOT_WILD
;
7632 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7633 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7634 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7635 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7636 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7637 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7638 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7639 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7640 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7641 if (NT_SUCCESS(Status
))
7643 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7645 if (Status
== STATUS_PENDING
)
7650 if (NT_SUCCESS(Status
))
7652 PQUERY_PATH_RESPONSE QueryResponse
;
7654 /* We accept the length that was canon (minus netroot) */
7655 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7656 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7660 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7661 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7663 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7665 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7668 RxpPrepareCreateContextForReuse(RxContext
);
7670 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7681 RxPrepareToReparseSymbolicLink(
7682 PRX_CONTEXT RxContext
,
7683 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7684 PUNICODE_STRING NewPath
,
7685 BOOLEAN NewPathIsAbsolute
,
7686 PBOOLEAN ReparseRequired
)
7690 PFILE_OBJECT FileObject
;
7692 /* Assume no reparse is required first */
7693 *ReparseRequired
= FALSE
;
7695 /* Only supported for IRP_MJ_CREATE */
7696 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
)
7698 return STATUS_INVALID_PARAMETER
;
7701 /* If symbolic link is not embedded, and DELETE is specified, fail */
7702 if (!SymbolicLinkEmbeddedInOldPath
)
7704 /* Excepted if DELETE is the only flag specified, then, open has to succeed
7705 * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7707 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, DELETE
) &&
7708 BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.DesiredAccess
, ~DELETE
))
7710 return STATUS_ACCESS_DENIED
;
7714 /* At that point, assume reparse will be required */
7715 *ReparseRequired
= TRUE
;
7717 /* If new path isn't absolute, it's up to us to make it absolute */
7718 if (!NewPathIsAbsolute
)
7720 /* The prefix will be \Device\Mup */
7721 NewLength
= NewPath
->Length
+ (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
));
7722 NewBuffer
= ExAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, NewLength
,
7724 if (NewBuffer
== NULL
)
7726 return STATUS_INSUFFICIENT_RESOURCES
;
7729 /* Copy data for the new path */
7730 RtlMoveMemory(NewBuffer
, L
"\\Device\\Mup", (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
)));
7731 RtlMoveMemory(Add2Ptr(NewBuffer
, (sizeof(L
"\\Device\\Mup") - sizeof(UNICODE_NULL
))),
7732 NewPath
->Buffer
, NewPath
->Length
);
7734 /* Otherwise, use caller path as it */
7737 NewLength
= NewPath
->Length
;
7738 NewBuffer
= NewPath
->Buffer
;
7741 /* Get the FILE_OBJECT we'll modify */
7742 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
7744 /* Free old path first */
7745 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
7746 /* And setup new one */
7747 FileObject
->FileName
.Length
= NewLength
;
7748 FileObject
->FileName
.MaximumLength
= NewLength
;
7749 FileObject
->FileName
.Buffer
= NewBuffer
;
7751 /* And set reparse flag */
7752 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
);
7755 return STATUS_SUCCESS
;
7766 LOCK_OPERATION Lock
;
7767 PIO_STACK_LOCATION Stack
;
7768 PRX_CONTEXT RxContext
= Context
;
7770 /* NULL IRP is no option */
7776 /* Check whether preparation was really needed */
7777 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7781 /* Mark the context as prepared */
7782 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7784 /* Just lock the user buffer, with the correct length, depending on the MJ */
7785 Lock
= IoReadAccess
;
7786 Stack
= RxContext
->CurrentIrpSp
;
7787 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7789 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7791 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7793 Lock
= IoWriteAccess
;
7795 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7800 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7801 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7803 Lock
= IoWriteAccess
;
7804 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7806 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7808 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7812 /* As it will be posted (async), mark the IRP pending */
7813 IoMarkIrpPending(Irp
);
7821 PRX_CONTEXT RxContext
,
7822 FILE_INFORMATION_CLASS Class
)
7827 /* Initialize parameters in RX_CONTEXT */
7828 RxContext
->Info
.FileInformationClass
= Class
;
7829 RxContext
->Info
.Buffer
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
7830 RxContext
->Info
.Length
= RxContext
->CurrentIrpSp
->Parameters
.SetFile
.Length
;
7832 /* And call mini-rdr */
7833 Fcb
= (PFCB
)RxContext
->pFcb
;
7834 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
7841 RxpUnregisterMinirdr(
7842 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7853 PRX_CONTEXT LocalContext
)
7860 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7862 /* And force close */
7863 RxReleaseFcb(NULL
, Fcb
);
7864 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7865 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7866 ASSERT(Status
== STATUS_SUCCESS
);
7870 RxQueryAlternateNameInfo(
7871 PRX_CONTEXT RxContext
,
7872 PFILE_NAME_INFORMATION AltNameInfo
)
7875 return STATUS_NOT_IMPLEMENTED
;
7883 PRX_CONTEXT RxContext
,
7884 PFILE_BASIC_INFORMATION BasicInfo
)
7888 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7890 /* Simply zero and forward to mini-rdr */
7891 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7892 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7896 RxQueryCompressedInfo(
7897 PRX_CONTEXT RxContext
,
7898 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7901 return STATUS_NOT_IMPLEMENTED
;
7909 PRX_CONTEXT RxContext
)
7916 BOOLEAN LockNotGranted
;
7917 ULONG Length
, FileIndex
;
7918 PUNICODE_STRING FileName
;
7919 PIO_STACK_LOCATION Stack
;
7920 FILE_INFORMATION_CLASS FileInfoClass
;
7924 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7926 /* Get parameters */
7927 Stack
= RxContext
->CurrentIrpSp
;
7928 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7929 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7930 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7931 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7932 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7933 FileName
, FileInfoClass
);
7935 Irp
= RxContext
->CurrentIrp
;
7936 Flags
= Stack
->Flags
;
7937 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7938 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7940 if (FileName
!= NULL
)
7942 DPRINT("FileName: %wZ\n", FileName
);
7945 /* No FOBX: not a standard file/directory */
7946 Fobx
= (PFOBX
)RxContext
->pFobx
;
7949 return STATUS_OBJECT_NAME_INVALID
;
7952 /* We can only deal with a disk */
7953 Fcb
= (PFCB
)RxContext
->pFcb
;
7954 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7956 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7957 return STATUS_INVALID_DEVICE_REQUEST
;
7960 /* Setup RX_CONTEXT related fields */
7961 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7962 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7963 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7964 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7965 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7967 /* We don't support (yet?) a specific index being set */
7968 if (RxContext
->QueryDirectory
.IndexSpecified
)
7970 return STATUS_NOT_IMPLEMENTED
;
7973 /* Try to lock FCB */
7974 LockNotGranted
= TRUE
;
7975 if (RxContext
->QueryDirectory
.InitialQuery
)
7977 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7978 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7980 if (!NT_SUCCESS(Status
))
7985 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7987 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7988 RxConvertToSharedFcb(RxContext
, Fcb
);
7991 LockNotGranted
= FALSE
;
7996 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7997 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7999 if (!NT_SUCCESS(Status
))
8004 LockNotGranted
= FALSE
;
8008 /* If it failed, post request */
8011 return RxFsdPostRequest(RxContext
);
8014 /* This cannot be done on a orphaned directory */
8015 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
8017 RxReleaseFcb(RxContext
, Fcb
);
8018 return STATUS_FILE_CLOSED
;
8024 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
8026 RxContext
->QueryDirectory
.FileIndex
= 0;
8029 /* Assume success */
8030 Status
= STATUS_SUCCESS
;
8031 /* If initial query, prepare FOBX */
8032 if (RxContext
->QueryDirectory
.InitialQuery
)
8034 /* We cannot have a template already! */
8035 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
8037 /* If we have a file name and a correct one, duplicate it in the FOBX */
8038 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
8039 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
8040 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
8041 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
8043 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
8045 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
8046 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
8048 /* UNICODE_STRING; length has to be even */
8049 if ((FileName
->Length
& 1) != 0)
8051 Status
= STATUS_INVALID_PARAMETER
;
8052 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
8056 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
8057 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
8058 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
8060 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
8065 Status
= STATUS_INSUFFICIENT_RESOURCES
;
8068 /* No name specified, or a match all wildcard? Match everything */
8071 Fobx
->ContainsWildCards
= TRUE
;
8073 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
8074 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
8075 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
8077 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
8080 /* No need for exclusive any longer */
8081 if (NT_SUCCESS(Status
))
8083 RxConvertToSharedFcb(RxContext
, Fcb
);
8087 /* Lock user buffer and forward to mini-rdr */
8088 if (NT_SUCCESS(Status
))
8090 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
8091 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
8092 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
8093 RxContext
->Info
.Length
= Length
;
8095 if (RxContext
->Info
.Buffer
!= NULL
)
8097 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
8100 /* Post if mini-rdr asks to */
8101 if (RxContext
->PostRequest
)
8103 RxFsdPostRequest(RxContext
);
8107 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
8113 RxReleaseFcb(RxContext
, Fcb
);
8122 PRX_CONTEXT RxContext
,
8123 PFILE_EA_INFORMATION EaInfo
)
8126 return STATUS_NOT_IMPLEMENTED
;
8130 RxQueryInternalInfo(
8131 PRX_CONTEXT RxContext
,
8132 PFILE_INTERNAL_INFORMATION InternalInfo
)
8135 return STATUS_NOT_IMPLEMENTED
;
8143 PRX_CONTEXT RxContext
,
8144 PFILE_NAME_INFORMATION NameInfo
)
8150 DPRINT("RxQueryNameInfo(%p, %p)\n", RxContext
, NameInfo
);
8152 /* Check we can at least copy name size */
8153 if (RxContext
->Info
.LengthRemaining
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
))
8155 DPRINT1("Buffer too small: %d\n", RxContext
->Info
.LengthRemaining
);
8156 RxContext
->Info
.Length
= 0;
8157 return STATUS_BUFFER_OVERFLOW
;
8160 Fcb
= (PFCB
)RxContext
->pFcb
;
8161 Fobx
= (PFOBX
)RxContext
->pFobx
;
8162 /* Get the UNC name */
8163 RxConjureOriginalName(Fcb
, Fobx
, &NameInfo
->FileNameLength
, &NameInfo
->FileName
[0],
8164 &RxContext
->Info
.Length
, VNetRoot_As_UNC_Name
);
8166 /* If RxConjureOriginalName returned a negative len (-1) then output buffer
8167 * was too small, return the appropriate length & status.
8169 if (RxContext
->Info
.LengthRemaining
< 0)
8171 DPRINT1("Buffer too small!\n");
8172 RxContext
->Info
.Length
= 0;
8173 return STATUS_BUFFER_OVERFLOW
;
8177 return STATUS_SUCCESS
;
8182 PRX_CONTEXT RxContext
,
8183 PFILE_PIPE_INFORMATION PipeInfo
)
8186 return STATUS_NOT_IMPLEMENTED
;
8190 RxQueryPositionInfo(
8191 PRX_CONTEXT RxContext
,
8192 PFILE_POSITION_INFORMATION PositionInfo
)
8195 return STATUS_NOT_IMPLEMENTED
;
8202 RxQueryStandardInfo(
8203 PRX_CONTEXT RxContext
,
8204 PFILE_STANDARD_INFORMATION StandardInfo
)
8212 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
8214 /* Zero output buffer */
8215 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
8217 Fcb
= (PFCB
)RxContext
->pFcb
;
8218 Fobx
= (PFOBX
)RxContext
->pFobx
;
8219 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8220 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
8221 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8223 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8226 /* Otherwise, fill what we can already */
8227 Status
= STATUS_SUCCESS
;
8228 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
8229 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8230 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
8231 if (StandardInfo
->NumberOfLinks
== 0)
8233 StandardInfo
->NumberOfLinks
= 1;
8236 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
8238 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
8239 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
8242 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8243 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
8245 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
8249 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
8260 RxReadRegistryParameters(
8267 UNICODE_STRING KeyName
, ParamName
;
8268 OBJECT_ATTRIBUTES ObjectAttributes
;
8269 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
8273 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8274 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
8275 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
8276 if (!NT_SUCCESS(Status
))
8281 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
8282 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
8283 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8284 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8286 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
8289 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
8290 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8291 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8293 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
8295 if (Granularity
> 16)
8300 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
8303 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
8304 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
8305 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
8307 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
8319 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
8320 IN OUT PDRIVER_OBJECT DriverObject
,
8321 IN PMINIRDR_DISPATCH MrdrDispatch
,
8323 IN PUNICODE_STRING DeviceName
,
8324 IN ULONG DeviceExtensionSize
,
8325 IN DEVICE_TYPE DeviceType
,
8326 IN ULONG DeviceCharacteristics
)
8329 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
8335 return STATUS_INVALID_PARAMETER
;
8338 /* Create device object with provided parameters */
8339 Status
= IoCreateDevice(DriverObject
,
8340 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
8343 DeviceCharacteristics
,
8345 (PDEVICE_OBJECT
*)&RDBSSDevice
);
8346 if (!NT_SUCCESS(Status
))
8351 if (!RxData
.DriverObject
)
8353 return STATUS_UNSUCCESSFUL
;
8356 /* Initialize our DO extension */
8357 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
8358 ++RxFileSystemDeviceObject
->ReferenceCount
;
8359 *DeviceObject
= RDBSSDevice
;
8360 RDBSSDevice
->RdbssExports
= &RxExports
;
8361 RDBSSDevice
->Dispatch
= MrdrDispatch
;
8362 RDBSSDevice
->RegistrationControls
= Controls
;
8363 RDBSSDevice
->DeviceName
= *DeviceName
;
8364 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
8365 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
8366 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
8367 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
8368 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
8369 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
8370 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
8372 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
8374 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
8375 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
8376 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
8378 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8379 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
8381 RxInitializeMinirdrDispatchTable(DriverObject
);
8384 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8385 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
8387 LARGE_INTEGER ScavengerTimeLimit
;
8389 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
8390 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
8391 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
8392 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
8393 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
8394 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
8397 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
8399 return STATUS_SUCCESS
;
8406 RxRemoveFromTopLevelIrpAllocatedContextsList(
8407 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8411 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8412 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8413 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8415 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
8416 RemoveEntryList(&TopLevelContext
->ListEntry
);
8417 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
8424 RxRemoveOverflowEntry(
8425 PRDBSS_DEVICE_OBJECT DeviceObject
,
8426 WORK_QUEUE_TYPE Queue
)
8429 PRX_CONTEXT Context
;
8431 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
8432 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
8434 /* No entries left, nothing to return */
8435 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
8442 /* Decrement count */
8443 --DeviceObject
->OverflowQueueCount
[Queue
];
8446 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
8447 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
8448 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
8449 Context
->OverflowListEntry
.Flink
= NULL
;
8451 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
8461 RxRemoveShareAccess(
8462 _Inout_ PFILE_OBJECT FileObject
,
8463 _Inout_ PSHARE_ACCESS ShareAccess
,
8465 _In_ PSZ wherelogtag
)
8469 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8470 IoRemoveShareAccess(FileObject
, ShareAccess
);
8471 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8479 RxRemoveShareAccessPerSrvOpens(
8480 IN OUT PSRV_OPEN SrvOpen
)
8482 ACCESS_MASK DesiredAccess
;
8484 BOOLEAN WriteAccess
;
8485 BOOLEAN DeleteAccess
;
8489 /* Get access that were granted to SRV_OPEN */
8490 DesiredAccess
= SrvOpen
->DesiredAccess
;
8491 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
8492 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
8493 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
8495 /* If any, drop them */
8496 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
8499 BOOLEAN SharedWrite
;
8500 BOOLEAN SharedDelete
;
8501 ULONG DesiredShareAccess
;
8502 PSHARE_ACCESS ShareAccess
;
8504 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
8505 DesiredShareAccess
= SrvOpen
->ShareAccess
;
8507 ShareAccess
->Readers
-= ReadAccess
;
8508 ShareAccess
->Writers
-= WriteAccess
;
8509 ShareAccess
->Deleters
-= DeleteAccess
;
8511 ShareAccess
->OpenCount
--;
8513 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
8514 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
8515 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
8516 ShareAccess
->SharedRead
-= SharedRead
;
8517 ShareAccess
->SharedWrite
-= SharedWrite
;
8518 ShareAccess
->SharedDelete
-= SharedDelete
;
8523 RxSearchForCollapsibleOpen(
8524 PRX_CONTEXT RxContext
,
8525 ACCESS_MASK DesiredAccess
,
8530 PLIST_ENTRY ListEntry
;
8531 BOOLEAN ShouldTry
, Purged
, Scavenged
;
8535 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext
, DesiredAccess
, ShareAccess
);
8537 Fcb
= (PFCB
)RxContext
->pFcb
;
8539 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8540 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
8542 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8544 RxScavengeRelatedFobxs(Fcb
);
8545 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8547 return STATUS_NOT_FOUND
;
8550 /* If basic open, ask the mini-rdr if we should try to collapse */
8551 if (RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN
||
8552 RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN_IF
)
8556 if (Fcb
->MRxDispatch
!= NULL
)
8558 ASSERT(RxContext
->pRelevantSrvOpen
== NULL
);
8559 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8561 ShouldTry
= NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
));
8569 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
))
8574 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8577 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
)))
8579 return STATUS_NOT_FOUND
;
8582 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8584 RxScavengeRelatedFobxs(Fcb
);
8585 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8587 return STATUS_NOT_FOUND
;
8590 /* Only collapse for matching NET_ROOT & disks */
8591 if (Fcb
->pNetRoot
!= RxContext
->Create
.pNetRoot
||
8592 Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
8594 return STATUS_NOT_FOUND
;
8599 Status
= STATUS_NOT_FOUND
;
8601 /* Browse all our SRV_OPEN to find the matching one */
8602 for (ListEntry
= Fcb
->SrvOpenList
.Flink
;
8603 ListEntry
!= &Fcb
->SrvOpenList
;
8604 ListEntry
= ListEntry
->Flink
)
8608 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
8609 /* Not the same VNET_ROOT, move to the next one */
8610 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8612 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8616 /* Is there a sharing violation? */
8617 if (SrvOpen
->DesiredAccess
!= DesiredAccess
|| SrvOpen
->ShareAccess
!= ShareAccess
||
8618 BooleanFlagOn(SrvOpen
->Flags
, (SRVOPEN_FLAG_CLOSED
| SRVOPEN_FLAG_COLLAPSING_DISABLED
| SRVOPEN_FLAG_FILE_DELETED
| SRVOPEN_FLAG_FILE_RENAMED
)))
8620 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8622 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8626 /* Check against the SRV_OPEN */
8627 Status
= RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
);
8628 if (!NT_SUCCESS(Status
))
8635 /* Don't allow collaspse for reparse point opening */
8636 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
^ SrvOpen
->CreateOptions
, FILE_OPEN_REPARSE_POINT
))
8640 Status
= STATUS_NOT_FOUND
;
8644 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8645 if (DisableByteRangeLockingOnReadOnlyFiles
|| !BooleanFlagOn(SrvOpen
->pFcb
->Attributes
, FILE_ATTRIBUTE_READONLY
))
8647 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
8649 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8650 if (NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
)))
8652 /* Is close delayed - great reuse*/
8653 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
8655 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen
);
8656 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
8657 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
8660 return STATUS_SUCCESS
;
8663 Status
= STATUS_NOT_FOUND
;
8668 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8669 if (ListEntry
== &Fcb
->SrvOpenList
)
8671 Status
= STATUS_NOT_FOUND
;
8674 /* Only required access: read attributes? Don't reuse */
8675 if ((DesiredAccess
& 0xFFEFFFFF) == FILE_READ_ATTRIBUTES
)
8677 return STATUS_NOT_FOUND
;
8680 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8683 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8685 RxScavengeRelatedFobxs(Fcb
);
8689 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8690 if (!Purged
&& RxIsOkToPurgeFcb(Fcb
))
8692 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8697 /* If sharing violation, keep track of it */
8698 if (Status
== STATUS_SHARING_VIOLATION
)
8700 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8703 DPRINT("Status: %x\n", Status
);
8708 RxSetAllocationInfo(
8709 PRX_CONTEXT RxContext
)
8712 return STATUS_NOT_IMPLEMENTED
;
8720 PRX_CONTEXT RxContext
)
8726 #define FILE_ATTRIBUTE_VOLUME 0x8
8727 #define VALID_FILE_ATTRIBUTES ( \
8728 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8729 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8730 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8731 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8732 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8733 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8734 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8735 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8737 /* First of all, call the mini-rdr */
8738 Status
= RxpSetInfoMiniRdr(RxContext
, FileBasicInformation
);
8739 /* If it succeed, perform last bits */
8740 if (NT_SUCCESS(Status
))
8745 PFILE_OBJECT FileObject
;
8746 ULONG Attributes
, CleanAttr
;
8747 PFILE_BASIC_INFORMATION BasicInfo
;
8749 Fcb
= (PFCB
)RxContext
->pFcb
;
8750 Fobx
= (PFOBX
)RxContext
->pFobx
;
8751 Irp
= RxContext
->CurrentIrp
;
8752 BasicInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
8753 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8755 /* If caller provided flags, handle the change */
8756 Attributes
= BasicInfo
->FileAttributes
;
8757 if (Attributes
!= 0)
8759 /* Clean our flags first, with only stuff we support */
8760 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
8762 CleanAttr
= (Attributes
& VALID_DIR_ATTRIBUTES
) | FILE_ATTRIBUTE_DIRECTORY
;
8766 CleanAttr
= Attributes
& VALID_FILE_ATTRIBUTES
;
8769 /* Handle the temporary mark (set/unset depending on caller) */
8770 if (BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_TEMPORARY
))
8772 SetFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8773 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8777 ClearFlag(Fcb
->FcbState
, FCB_STATE_TEMPORARY
);
8778 ClearFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
8781 /* And set new attributes */
8782 Fcb
->Attributes
= CleanAttr
;
8785 /* If caller provided a creation time, set it */
8786 if (BasicInfo
->CreationTime
.QuadPart
!= 0LL)
8788 Fcb
->CreationTime
.QuadPart
= BasicInfo
->CreationTime
.QuadPart
;
8789 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_CREATION
);
8792 /* If caller provided a last access time, set it */
8793 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0LL)
8795 Fcb
->LastAccessTime
.QuadPart
= BasicInfo
->LastAccessTime
.QuadPart
;
8796 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
);
8799 /* If caller provided a last write time, set it */
8800 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0LL)
8802 Fcb
->LastWriteTime
.QuadPart
= BasicInfo
->LastWriteTime
.QuadPart
;
8803 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
8806 /* If caller provided a last change time, set it */
8807 if (BasicInfo
->ChangeTime
.QuadPart
!= 0LL)
8809 Fcb
->LastChangeTime
.QuadPart
= BasicInfo
->ChangeTime
.QuadPart
;
8810 SetFlag(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
8822 RxSetDispositionInfo(
8823 PRX_CONTEXT RxContext
)
8829 /* First, make the mini-rdr work! */
8830 Status
= RxpSetInfoMiniRdr(RxContext
, FileDispositionInformation
);
8831 /* If it succeed, we'll keep track of the change */
8832 if (NT_SUCCESS(Status
))
8835 PFILE_OBJECT FileObject
;
8836 PFILE_DISPOSITION_INFORMATION FileDispo
;
8838 Fcb
= (PFCB
)RxContext
->pFcb
;
8839 FileObject
= RxContext
->CurrentIrpSp
->FileObject
;
8840 FileDispo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8841 /* Caller asks for deletion: mark as delete on close */
8842 if (FileDispo
->DeleteFile
)
8844 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8845 FileObject
->DeletePending
= TRUE
;
8847 /* Otherwise, clear it */
8850 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
8851 FileObject
->DeletePending
= FALSE
;
8854 /* Sanitize output */
8855 Status
= STATUS_SUCCESS
;
8863 PRX_CONTEXT RxContext
)
8866 return STATUS_NOT_IMPLEMENTED
;
8871 PRX_CONTEXT RxContext
)
8874 return STATUS_NOT_IMPLEMENTED
;
8879 PRX_CONTEXT RxContext
)
8882 return STATUS_NOT_IMPLEMENTED
;
8890 PRX_CONTEXT RxContext
)
8894 PFCB RenameFcb
, Fcb
;
8895 PIO_STACK_LOCATION Stack
;
8896 PFILE_RENAME_INFORMATION RenameInfo
, UserInfo
;
8900 DPRINT("RxSetRenameInfo(%p)\n", RxContext
);
8902 Stack
= RxContext
->CurrentIrpSp
;
8903 DPRINT("FO: %p, Replace: %d\n", Stack
->Parameters
.SetFile
.FileObject
, Stack
->Parameters
.SetFile
.ReplaceIfExists
);
8905 /* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
8906 RxContext
->Info
.ReplaceIfExists
= Stack
->Parameters
.SetFile
.ReplaceIfExists
;
8907 if (Stack
->Parameters
.SetFile
.FileObject
== NULL
)
8909 return RxpSetInfoMiniRdr(RxContext
, Stack
->Parameters
.SetFile
.FileInformationClass
);
8912 Fcb
= (PFCB
)RxContext
->pFcb
;
8913 RenameFcb
= Stack
->Parameters
.SetFile
.FileObject
->FsContext
;
8914 /* First, validate the received file object */
8915 ASSERT(NodeType(RenameFcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
);
8916 if (Fcb
->pNetRoot
!= RenameFcb
->pNetRoot
)
8918 DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb
, Fcb
->pNetRoot
, Fcb
->pNetRoot
->pNetRootName
, RenameFcb
, RenameFcb
->pNetRoot
, RenameFcb
->pNetRoot
->pNetRootName
);
8919 return STATUS_NOT_SAME_DEVICE
;
8922 /* We'll reallocate a safe buffer */
8923 Length
= Fcb
->pNetRoot
->DiskParameters
.RenameInfoOverallocationSize
+ RenameFcb
->FcbTableEntry
.Path
.Length
+ FIELD_OFFSET(FILE_RENAME_INFORMATION
, FileName
);
8924 RenameInfo
= RxAllocatePoolWithTag(PagedPool
, Length
, '??xR');
8925 if (RenameInfo
== NULL
)
8927 return STATUS_INSUFFICIENT_RESOURCES
;
8933 UserInfo
= RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
8934 RenameInfo
->ReplaceIfExists
= UserInfo
->ReplaceIfExists
;
8935 RenameInfo
->RootDirectory
= UserInfo
->RootDirectory
;
8936 RenameInfo
->FileNameLength
= RenameFcb
->FcbTableEntry
.Path
.Length
;
8937 RtlMoveMemory(&RenameInfo
->FileName
[0], RenameFcb
->FcbTableEntry
.Path
.Buffer
, RenameFcb
->FcbTableEntry
.Path
.Length
);
8939 /* Set them in the RX_CONTEXT */
8940 RxContext
->Info
.FileInformationClass
= Stack
->Parameters
.SetFile
.FileInformationClass
;
8941 RxContext
->Info
.Buffer
= RenameInfo
;
8942 RxContext
->Info
.Length
= Length
;
8944 /* And call the mini-rdr */
8945 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (RxContext
));
8950 RxFreePoolWithTag(RenameInfo
, '??xR');
8964 _In_ ACCESS_MASK DesiredAccess
,
8965 _In_ ULONG DesiredShareAccess
,
8966 _Inout_ PFILE_OBJECT FileObject
,
8967 _Out_ PSHARE_ACCESS ShareAccess
,
8969 _In_ PSZ wherelogtag
)
8973 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8974 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8975 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8981 PRX_CONTEXT RxContext
)
8984 return STATUS_NOT_IMPLEMENTED
;
8991 RxSetupNetFileObject(
8992 PRX_CONTEXT RxContext
)
8996 PFILE_OBJECT FileObject
;
8997 PIO_STACK_LOCATION Stack
;
9001 /* Assert FOBX is FOBX or NULL */
9002 Fobx
= (PFOBX
)RxContext
->pFobx
;
9003 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
9005 Fcb
= (PFCB
)RxContext
->pFcb
;
9006 Stack
= RxContext
->CurrentIrpSp
;
9007 FileObject
= Stack
->FileObject
;
9008 /* If it's temporary mark FO as such */
9009 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
9010 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
9012 if (FileObject
== NULL
)
9017 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
9020 /* No FO, nothing to setup */
9021 if (FileObject
== NULL
)
9026 /* Assign FCB & CCB (FOBX) to FO */
9027 FileObject
->FsContext
= Fcb
;
9028 FileObject
->FsContext2
= Fobx
;
9031 ULONG_PTR StackTop
, StackBottom
;
9033 /* If FO is allocated on pool, keep track of it */
9034 IoGetStackLimits(&StackTop
, &StackBottom
);
9035 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
9037 Fobx
->AssociatedFileObject
= FileObject
;
9041 Fobx
->AssociatedFileObject
= NULL
;
9044 /* Make sure to mark FOBX if it's a DFS open */
9045 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
9047 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
9051 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
9055 /* Set Cc pointers */
9056 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
9058 /* Update access state */
9059 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
9061 PACCESS_STATE AccessState
;
9063 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
9064 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
9065 AccessState
->RemainingDesiredAccess
= 0;
9075 IN PRX_CONTEXT RxContext
,
9076 OUT PBOOLEAN PostToFsp
)
9079 BOOLEAN Wait
, AlreadyStarted
;
9080 PRDBSS_DEVICE_OBJECT DeviceObject
;
9082 /* If we've not been post, then, do it */
9083 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
9085 SECURITY_SUBJECT_CONTEXT SubjectContext
;
9087 SeCaptureSubjectContext(&SubjectContext
);
9088 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
9089 SeReleaseSubjectContext(&SubjectContext
);
9092 return STATUS_PENDING
;
9095 /* Acquire all the required locks */
9096 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
9097 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
9100 return STATUS_PENDING
;
9103 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
9105 ExReleaseResourceLite(&RxData
.Resource
);
9107 return STATUS_PENDING
;
9110 AlreadyStarted
= FALSE
;
9111 DeviceObject
= RxContext
->RxDeviceObject
;
9114 /* MUP handle set, means already registered */
9115 if (DeviceObject
->MupHandle
!= NULL
)
9117 AlreadyStarted
= TRUE
;
9118 Status
= STATUS_REDIRECTOR_STARTED
;
9122 /* If we're asked to register to MUP, then do it */
9123 Status
= STATUS_SUCCESS
;
9124 if (DeviceObject
->RegisterUncProvider
)
9126 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
9127 &DeviceObject
->DeviceName
,
9128 DeviceObject
->RegisterMailSlotProvider
);
9130 if (!NT_SUCCESS(Status
))
9132 DeviceObject
->MupHandle
= NULL
;
9136 /* Register as file system */
9137 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
9138 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
9140 /* Inform mini-rdr it has to start */
9141 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
9142 if (NT_SUCCESS(Status
))
9144 ++DeviceObject
->StartStopContext
.Version
;
9145 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
9146 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
9148 Status
= RxInitializeMRxDispatcher(DeviceObject
);
9153 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
9155 if (!AlreadyStarted
)
9157 RxUnstart(RxContext
, DeviceObject
);
9161 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
9162 ExReleaseResourceLite(&RxData
.Resource
);
9172 IN PRX_CONTEXT RxContext
,
9173 OUT PBOOLEAN PostToFsp
)
9176 return STATUS_NOT_IMPLEMENTED
;
9181 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9185 return STATUS_NOT_IMPLEMENTED
;
9192 RxTryToBecomeTheTopLevelIrp(
9193 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
9195 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
9196 IN BOOLEAN ForceTopLevel
9199 BOOLEAN FromPool
= FALSE
;
9203 /* If not top level, and not have to be, quit */
9204 if (IoGetTopLevelIrp() && !ForceTopLevel
)
9209 /* If not TLC provider, allocate one */
9210 if (TopLevelContext
== NULL
)
9212 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
9213 if (TopLevelContext
== NULL
)
9222 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
9224 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9227 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9230 /* Make it top level IRP */
9231 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
9240 RxUpdateShareAccess(
9241 _Inout_ PFILE_OBJECT FileObject
,
9242 _Inout_ PSHARE_ACCESS ShareAccess
,
9244 _In_ PSZ wherelogtag
)
9248 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
9249 IoUpdateShareAccess(FileObject
, ShareAccess
);
9250 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
9258 RxUninitializeCacheMap(
9259 PRX_CONTEXT RxContext
,
9260 PFILE_OBJECT FileObject
,
9261 PLARGE_INTEGER TruncateSize
)
9265 CACHE_UNINITIALIZE_EVENT UninitEvent
;
9269 Fcb
= FileObject
->FsContext
;
9270 ASSERT(NodeTypeIsFcb(Fcb
));
9271 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
9273 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
9274 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
9276 /* Always release the FCB before waiting for the uninit event */
9277 RxReleaseFcb(RxContext
, Fcb
);
9279 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
9281 /* Re-acquire it afterwards */
9282 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
9283 ASSERT(NT_SUCCESS(Status
));
9289 IN PDRIVER_OBJECT DriverObject
)
9298 IN PFILE_LOCK_INFO LockInfo
)
9305 PRX_CONTEXT Context
,
9306 PRDBSS_DEVICE_OBJECT DeviceObject
)
9315 RxUnwindTopLevelIrp(
9316 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
9318 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
9320 /* No TLC provided? Ask the system for ours! */
9321 if (TopLevelContext
== NULL
)
9323 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
9324 if (TopLevelContext
== NULL
)
9329 /* In that case, just assert it's really ours */
9330 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
9331 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
9334 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
9335 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
9336 /* Restore the previous top level IRP */
9337 IoSetTopLevelIrp(TopLevelContext
->Previous
);
9338 /* If TLC was allocated from pool, remove it from list and release it */
9339 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
9341 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
9342 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
9350 RxUpdateShareAccessPerSrvOpens(
9351 IN PSRV_OPEN SrvOpen
)
9353 ACCESS_MASK DesiredAccess
;
9355 BOOLEAN WriteAccess
;
9356 BOOLEAN DeleteAccess
;
9360 /* If already updated, no need to continue */
9361 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
9366 /* Check if any access wanted */
9367 DesiredAccess
= SrvOpen
->DesiredAccess
;
9368 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
9369 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
9370 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
9372 /* In that case, update it */
9373 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
9376 BOOLEAN SharedWrite
;
9377 BOOLEAN SharedDelete
;
9378 ULONG DesiredShareAccess
;
9379 PSHARE_ACCESS ShareAccess
;
9381 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
9382 DesiredShareAccess
= SrvOpen
->ShareAccess
;
9384 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
9385 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
9386 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
9388 ShareAccess
->OpenCount
++;
9390 ShareAccess
->Readers
+= ReadAccess
;
9391 ShareAccess
->Writers
+= WriteAccess
;
9392 ShareAccess
->Deleters
+= DeleteAccess
;
9393 ShareAccess
->SharedRead
+= SharedRead
;
9394 ShareAccess
->SharedWrite
+= SharedWrite
;
9395 ShareAccess
->SharedDelete
+= SharedDelete
;
9398 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
9405 RxXXXControlFileCallthru(
9406 PRX_CONTEXT Context
)
9412 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
9414 /* No dispatch table? Nothing to dispatch */
9415 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
9417 Context
->pFobx
= NULL
;
9418 return STATUS_INVALID_DEVICE_REQUEST
;
9421 /* Init the lowio context */
9422 Status
= RxLowIoPopulateFsctlInfo(Context
);
9423 if (!NT_SUCCESS(Status
))
9428 /* Check whether we're consistent: a length means a buffer */
9429 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
9430 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
9432 return STATUS_INVALID_PARAMETER
;
9435 /* Forward the call to the mini-rdr */
9436 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
9437 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
9438 if (Status
!= STATUS_PENDING
)
9440 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
9443 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);