3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rdbsslib/rdbss.c
23 * PURPOSE: RDBSS library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
42 (NTAPI
*PRX_FSD_DISPATCH
) (
45 typedef struct _RX_FSD_DISPATCH_VECTOR
47 PRX_FSD_DISPATCH CommonRoutine
;
48 } RX_FSD_DISPATCH_VECTOR
, *PRX_FSD_DISPATCH_VECTOR
;
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject
);
58 PFILE_OBJECT FileObject
,
59 PDEVICE_OBJECT DeviceObject
);
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
89 RxCommonDevFCBCleanup(
100 PRX_CONTEXT Context
);
105 PRX_CONTEXT Context
);
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context
);
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context
);
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context
);
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context
);
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context
);
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context
);
140 PRX_CONTEXT Context
);
145 PRX_CONTEXT Context
);
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context
);
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context
);
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context
);
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context
);
170 PRX_CONTEXT Context
);
175 PRX_CONTEXT Context
);
179 RxCommonSetInformation(
180 PRX_CONTEXT Context
);
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context
);
190 PRX_CONTEXT Context
);
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context
);
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context
);
205 PRX_CONTEXT Context
);
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext
);
214 PUNICODE_STRING NetRootName
);
218 IN PRX_CONTEXT RxContext
);
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject
,
224 PLARGE_INTEGER FileOffset
,
225 ULONG Length
, BOOLEAN Wait
,
226 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
227 PIO_STATUS_BLOCK IoStatus
,
228 PDEVICE_OBJECT DeviceObject
);
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject
,
235 PVOID InputBuffer OPTIONAL
,
236 ULONG InputBufferLength
,
237 PVOID OutputBuffer OPTIONAL
,
238 ULONG OutputBufferLength
,
240 PIO_STATUS_BLOCK IoStatus
,
241 PDEVICE_OBJECT DeviceObject
);
246 PFILE_OBJECT FileObject
,
247 PLARGE_INTEGER FileOffset
,
252 PIO_STATUS_BLOCK IoStatus
,
253 PDEVICE_OBJECT DeviceObject
);
258 PFILE_OBJECT FileObject
,
259 PLARGE_INTEGER FileOffset
,
264 PIO_STATUS_BLOCK IoStatus
,
265 PDEVICE_OBJECT DeviceObject
);
269 PRX_CONTEXT RxContext
,
270 PUNICODE_STRING NetRootName
);
274 PRX_CONTEXT RxContext
,
275 PUNICODE_STRING FileName
,
276 PUNICODE_STRING CanonicalName
,
277 PNET_ROOT_TYPE NetRootType
);
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context
);
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath
);
295 RxGetStringRegistryParameter(
298 OUT PUNICODE_STRING OutString
,
300 IN ULONG BufferLength
,
301 IN BOOLEAN LogFailure
);
305 RxInitializeDebugSupport(
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject
);
315 RxInitializeRegistrationStructures(
320 RxInitializeTopLevelIrpPackage(
326 PDRIVER_OBJECT DriverObject
,
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
);
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext
);
340 PRX_CONTEXT RxContext
);
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext
);
349 IN PRX_CONTEXT RxContext
);
353 RxLowIoWriteShellCompletion(
354 PRX_CONTEXT RxContext
);
358 PRX_CONTEXT RxContext
);
361 RxNotifyChangeDirectory(
362 PRX_CONTEXT RxContext
);
366 PRX_CONTEXT RxContext
,
367 FILE_INFORMATION_CLASS FileInfoClass
,
373 PRX_CONTEXT LocalContext
);
376 RxQueryAlternateNameInfo(
377 PRX_CONTEXT RxContext
,
378 PFILE_NAME_INFORMATION AltNameInfo
);
382 PRX_CONTEXT RxContext
,
383 PFILE_BASIC_INFORMATION BasicInfo
);
386 RxQueryCompressedInfo(
387 PRX_CONTEXT RxContext
,
388 PFILE_COMPRESSION_INFORMATION CompressionInfo
);
392 PRX_CONTEXT RxContext
);
396 PRX_CONTEXT RxContext
,
397 PFILE_EA_INFORMATION EaInfo
);
401 PRX_CONTEXT RxContext
,
402 PFILE_INTERNAL_INFORMATION InternalInfo
);
406 PRX_CONTEXT RxContext
,
407 PFILE_NAME_INFORMATION NameInfo
);
411 PRX_CONTEXT RxContext
,
412 PFILE_PIPE_INFORMATION PipeInfo
);
416 PRX_CONTEXT RxContext
,
417 PFILE_POSITION_INFORMATION PositionInfo
);
421 PRX_CONTEXT RxContext
,
422 PFILE_STANDARD_INFORMATION StandardInfo
);
426 RxReadRegistryParameters(
431 RxReleaseFileForNtCreateSection(
432 PFILE_OBJECT FileObject
);
437 PFILE_OBJECT FileObject
,
438 PDEVICE_OBJECT DeviceObject
);
441 RxRemoveOverflowEntry(
442 PRDBSS_DEVICE_OBJECT DeviceObject
,
443 WORK_QUEUE_TYPE Queue
);
446 RxSearchForCollapsibleOpen(
447 PRX_CONTEXT RxContext
,
448 ACCESS_MASK DesiredAccess
,
453 PRX_CONTEXT RxContext
);
457 PRX_CONTEXT RxContext
);
460 RxSetDispositionInfo(
461 PRX_CONTEXT RxContext
);
465 PRX_CONTEXT RxContext
);
469 PRX_CONTEXT RxContext
);
473 PRX_CONTEXT RxContext
);
477 PRX_CONTEXT RxContext
);
481 PRX_CONTEXT RxContext
);
484 RxSetupNetFileObject(
485 PRX_CONTEXT RxContext
);
489 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
493 RxUninitializeCacheMap(
494 PRX_CONTEXT RxContext
,
495 PFILE_OBJECT FileObject
,
496 PLARGE_INTEGER TruncateSize
);
501 PRDBSS_DEVICE_OBJECT DeviceObject
);
504 RxXXXControlFileCallthru(
505 PRX_CONTEXT Context
);
509 _RxAllocatePoolWithTag(
510 _In_ POOL_TYPE PoolType
,
511 _In_ SIZE_T NumberOfBytes
,
525 WCHAR RxStarForTemplate
= '*';
526 WCHAR Rx8QMdot3QM
[] = L
">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles
= FALSE
;
528 BOOLEAN DisableFlushOnCleanup
= FALSE
;
529 ULONG ReadAheadGranularity
= 1 << PAGE_SHIFT
;
530 LIST_ENTRY RxActiveContexts
;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList
;
532 FAST_MUTEX RxContextPerFileSerializationMutex
;
535 BOOLEAN RxLoudLowIoOpsEnabled
= FALSE
;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
538 { RxCommonDispatchProblem
},
539 { RxCommonDispatchProblem
},
540 { RxCommonDevFCBClose
},
541 { RxCommonDispatchProblem
},
542 { RxCommonDispatchProblem
},
543 { RxCommonDispatchProblem
},
544 { RxCommonDispatchProblem
},
545 { RxCommonDispatchProblem
},
546 { RxCommonDispatchProblem
},
547 { RxCommonDispatchProblem
},
548 { RxCommonDevFCBQueryVolInfo
},
549 { RxCommonDispatchProblem
},
550 { RxCommonDispatchProblem
},
551 { RxCommonDevFCBFsCtl
},
552 { RxCommonDevFCBIoCtl
},
553 { RxCommonDevFCBIoCtl
},
554 { RxCommonDispatchProblem
},
555 { RxCommonDispatchProblem
},
556 { RxCommonDevFCBCleanup
},
557 { RxCommonDispatchProblem
},
558 { RxCommonDispatchProblem
},
559 { RxCommonDispatchProblem
},
560 { RxCommonUnimplemented
},
561 { RxCommonUnimplemented
},
562 { RxCommonUnimplemented
},
563 { RxCommonUnimplemented
},
564 { RxCommonUnimplemented
},
565 { RxCommonUnimplemented
},
567 RDBSS_EXPORTS RxExports
;
568 FAST_IO_DISPATCH RxFastIoDispatch
;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject
;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
573 { RxCommonUnimplemented
},
577 { RxCommonQueryInformation
},
578 { RxCommonSetInformation
},
581 { RxCommonFlushBuffers
},
582 { RxCommonQueryVolumeInformation
},
583 { RxCommonSetVolumeInformation
},
584 { RxCommonDirectoryControl
},
585 { RxCommonFileSystemControl
},
586 { RxCommonDeviceControl
},
587 { RxCommonDeviceControl
},
588 { RxCommonUnimplemented
},
589 { RxCommonLockControl
},
591 { RxCommonUnimplemented
},
592 { RxCommonQuerySecurity
},
593 { RxCommonSetSecurity
},
594 { RxCommonUnimplemented
},
595 { RxCommonUnimplemented
},
596 { RxCommonUnimplemented
},
597 { RxCommonQueryQuotaInformation
},
598 { RxCommonSetQuotaInformation
},
599 { RxCommonUnimplemented
},
601 ULONG RxFsdEntryCount
;
602 LIST_ENTRY RxIrpsList
;
603 KSPIN_LOCK RxIrpsListSpinLock
;
604 KMUTEX RxScavengerMutex
;
605 KMUTEX RxSerializationMutex
;
606 UCHAR RxSpaceForTheWrappersDeviceObject
[sizeof(*RxFileSystemDeviceObject
)];
607 KSPIN_LOCK TopLevelIrpSpinLock
;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList
;
609 BOOLEAN RxForceQFIPassThrough
= FALSE
;
610 BOOLEAN RxNoAsync
= FALSE
;
612 DECLARE_CONST_UNICODE_STRING(unknownId
, L
"???");
619 #define ASSERT(exp) \
622 RxAssert(#exp, __FILE__, __LINE__, NULL); \
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
637 /* FUNCTIONS ****************************************************************/
643 CheckForLoudOperations(
644 PRX_CONTEXT RxContext
)
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
650 /* Are loud operations enabled? */
651 if (RxLoudLowIoOpsEnabled
)
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 Fcb
= (PFCB
)RxContext
->pFcb
;
657 if (RtlCompareMemory(Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, (Fcb
->PrivateAlreadyPrefixedName
.Length
- ALLSCR_LENGTH
)),
658 L
"all.scr", ALLSCR_LENGTH
) == ALLSCR_LENGTH
)
660 SetFlag(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
);
670 __RxInitializeTopLevelIrpContext(
671 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
673 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
676 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext
, Irp
, RxDeviceObject
, Flags
);
678 RtlZeroMemory(TopLevelContext
, sizeof(RX_TOPLEVELIRP_CONTEXT
));
679 TopLevelContext
->Irp
= Irp
;
680 TopLevelContext
->Flags
= (Flags
? RX_TOPLEVELCTX_FLAG_FROM_POOL
: 0);
681 TopLevelContext
->Signature
= RX_TOPLEVELIRP_CONTEXT_SIGNATURE
;
682 TopLevelContext
->RxDeviceObject
= RxDeviceObject
;
683 TopLevelContext
->Previous
= IoGetTopLevelIrp();
684 TopLevelContext
->Thread
= PsGetCurrentThread();
686 /* We cannot add to list something that'd come from stack */
687 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
689 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext
);
697 __RxWriteReleaseResources(
698 PRX_CONTEXT RxContext
,
699 BOOLEAN ResourceOwnerSet
,
708 ASSERT(RxContext
!= NULL
);
710 Fcb
= (PFCB
)RxContext
->pFcb
;
713 /* If FCB resource was acquired, release it */
714 if (RxContext
->FcbResourceAcquired
)
716 /* Taking care of owner */
717 if (ResourceOwnerSet
)
719 RxReleaseFcbForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
723 RxReleaseFcb(RxContext
, Fcb
);
726 RxContext
->FcbResourceAcquired
= FALSE
;
729 /* If FCB paging resource was acquired, release it */
730 if (RxContext
->FcbPagingIoResourceAcquired
)
732 /* Taking care of owner */
733 if (ResourceOwnerSet
)
735 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
739 RxReleasePagingIoResource(RxContext
, Fcb
);
742 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
750 RxAddToTopLevelIrpAllocatedContextsList(
751 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
755 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
757 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
758 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
760 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
761 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
762 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
771 IN PRX_CONTEXT RxContext
,
776 WORK_QUEUE_TYPE Queue
;
777 PIO_STACK_LOCATION Stack
;
779 Stack
= RxContext
->CurrentIrpSp
;
780 RxContext
->PostRequest
= FALSE
;
782 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
784 Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
786 Queue
= DelayedWorkQueue
;
787 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
791 Queue
= CriticalWorkQueue
;
792 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
795 /* Check for overflow */
796 if (Stack
->FileObject
!= NULL
)
798 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
800 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
801 /* In case of an overflow, add the new queued call to the overflow list */
804 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
805 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
806 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
808 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
812 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
815 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
816 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
823 RxAdjustFileTimesAndSize(
829 PFILE_OBJECT FileObject
;
830 LARGE_INTEGER CurrentTime
;
831 FILE_BASIC_INFORMATION FileBasicInfo
;
832 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
833 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
837 FileObject
= Context
->CurrentIrpSp
->FileObject
;
838 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839 if (FileObject
->PrivateCacheMap
== NULL
)
845 KeQuerySystemTime(&CurrentTime
);
847 Fobx
= (PFOBX
)Context
->pFobx
;
848 /* Was the file modified? */
849 FileModified
= BooleanFlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
);
850 /* We'll set last write if it was modified and user didn't update yet */
851 SetLastWrite
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
852 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853 SetLastAccess
= SetLastWrite
||
854 (BooleanFlagOn(FileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
855 !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
856 /* We'll set last change if it was modified and user didn't update yet */
857 SetLastChange
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
859 /* Nothing to update? Job done */
860 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
865 Fcb
= (PFCB
)Context
->pFcb
;
866 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
868 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
870 /* Update lastwrite time if required */
874 Fcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
875 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
878 /* Update lastaccess time if required */
882 Fcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
883 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
886 /* Update lastchange time if required */
890 Fcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
891 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
894 /* If one of the date was modified, issue a call to mini-rdr */
897 Context
->Info
.FileInformationClass
= FileBasicInformation
;
898 Context
->Info
.Buffer
= &FileBasicInfo
;
899 Context
->Info
.Length
= sizeof(FileBasicInfo
);
901 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
905 /* If the file was modified, update its EOF */
908 FileEOFInfo
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
910 Context
->Info
.FileInformationClass
= FileEndOfFileInformation
;
911 Context
->Info
.Buffer
= &FileEOFInfo
;
912 Context
->Info
.Length
= sizeof(FileEOFInfo
);
914 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
923 RxAllocateCanonicalNameBuffer(
924 PRX_CONTEXT RxContext
,
925 PUNICODE_STRING CanonicalName
,
926 USHORT CanonicalLength
)
930 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
932 /* Context must be free of any already allocated name */
933 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
935 /* Validate string length */
936 if (CanonicalLength
> USHRT_MAX
- 1)
938 CanonicalName
->Buffer
= NULL
;
939 return STATUS_OBJECT_PATH_INVALID
;
942 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
943 if (CanonicalName
->Buffer
== NULL
)
945 return STATUS_INSUFFICIENT_RESOURCES
;
948 CanonicalName
->Length
= 0;
949 CanonicalName
->MaximumLength
= CanonicalLength
;
951 /* Set the two places - they must always be identical */
952 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
953 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
955 return STATUS_SUCCESS
;
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
968 LIST_ENTRY ContextsToCancel
;
970 /* Init a list for the contexts to cancel */
971 InitializeListHead(&ContextsToCancel
);
973 /* Lock our list lock */
974 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
976 /* Now, browse all the active contexts, to find the associated ones */
977 Entry
= RxActiveContexts
.Flink
;
978 while (Entry
!= &RxActiveContexts
)
980 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
981 Entry
= Entry
->Flink
;
983 /* Not the IRP we're looking for, ignore */
984 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
985 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
990 /* Not the FOBX we're looking for, ignore */
991 if ((PFOBX
)Context
->pFobx
!= Fobx
)
996 /* No cancel routine (can't be cancel, then), ignore */
997 if (Context
->MRxCancelRoutine
== NULL
)
1002 /* Mark our context as cancelled */
1003 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1005 /* Move it to our list */
1006 RemoveEntryList(&Context
->ContextListEntry
);
1007 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1009 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1012 /* Done with the contexts */
1013 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1015 /* Now, handle all our "extracted" contexts */
1016 while (!IsListEmpty(&ContextsToCancel
))
1018 Entry
= RemoveHeadList(&ContextsToCancel
);
1019 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1021 /* If they had an associated IRP (should be always true) */
1022 if (Context
->CurrentIrp
!= NULL
)
1024 /* Then, call cancel routine */
1025 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1026 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1027 Context
->MRxCancelRoutine(Context
);
1030 /* And delete the context */
1031 RxDereferenceAndDeleteRxContext(Context
);
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040 PV_NET_ROOT VNetRoot
,
1041 BOOLEAN ForceFilesClosed
)
1046 PRX_CONTEXT Context
;
1047 LIST_ENTRY ContextsToCancel
;
1049 /* Init a list for the contexts to cancel */
1050 InitializeListHead(&ContextsToCancel
);
1052 /* Lock our list lock */
1053 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1055 /* Now, browse all the active contexts, to find the associated ones */
1056 Entry
= RxActiveContexts
.Flink
;
1057 while (Entry
!= &RxActiveContexts
)
1059 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1060 Entry
= Entry
->Flink
;
1062 /* Not the IRP we're looking for, ignore */
1063 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1064 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1069 /* Not the VNetRoot we're looking for, ignore */
1070 if (Context
->pFcb
== NULL
||
1071 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1076 /* No cancel routine (can't be cancel, then), ignore */
1077 if (Context
->MRxCancelRoutine
== NULL
)
1082 /* At that point, we found a matching context
1083 * If we're not asked to force close, then fail - it's still open
1085 if (!ForceFilesClosed
)
1087 Status
= STATUS_FILES_OPEN
;
1091 /* Mark our context as cancelled */
1092 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1094 /* Move it to our list */
1095 RemoveEntryList(&Context
->ContextListEntry
);
1096 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1098 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1101 /* Done with the contexts */
1102 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1104 if (Status
!= STATUS_SUCCESS
)
1109 /* Now, handle all our "extracted" contexts */
1110 while (!IsListEmpty(&ContextsToCancel
))
1112 Entry
= RemoveHeadList(&ContextsToCancel
);
1113 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1115 /* If they had an associated IRP (should be always true) */
1116 if (Context
->CurrentIrp
!= NULL
)
1118 /* Then, call cancel routine */
1119 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1120 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1121 Context
->MRxCancelRoutine(Context
);
1124 /* And delete the context */
1125 RxDereferenceAndDeleteRxContext(Context
);
1134 PDEVICE_OBJECT DeviceObject
,
1144 RxCanonicalizeFileNameByServerSpecs(
1145 PRX_CONTEXT RxContext
,
1146 PUNICODE_STRING NetRootName
)
1148 USHORT NextChar
, CurChar
;
1153 /* Validate file name is not empty */
1154 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1157 return STATUS_MORE_PROCESSING_REQUIRED
;
1160 /* Validate name is correct */
1161 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1165 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1167 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1174 if (CurChar
== NextChar
)
1176 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1183 if (CurChar
>= MaxChars
- 1)
1188 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1190 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1195 if (NetRootName
->Buffer
[1] != ':')
1197 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1203 if ((CurChar
- NextChar
) == 1)
1205 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1210 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1212 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1217 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1218 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1223 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1225 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1231 return STATUS_MORE_PROCESSING_REQUIRED
;
1235 RxCanonicalizeNameAndObtainNetRoot(
1236 PRX_CONTEXT RxContext
,
1237 PUNICODE_STRING FileName
,
1238 PUNICODE_STRING NetRootName
)
1241 NET_ROOT_TYPE NetRootType
;
1242 UNICODE_STRING CanonicalName
;
1246 NetRootType
= NET_ROOT_WILD
;
1248 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1249 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1251 /* if not relative opening, just handle the passed name */
1252 if (RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
== NULL
)
1254 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1255 if (!NT_SUCCESS(Status
))
1264 /* Make sure we have a valid FCB and a FOBX */
1265 Fcb
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1267 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1269 return STATUS_INVALID_PARAMETER
;
1272 if (!NodeTypeIsFcb(Fcb
))
1274 return STATUS_INVALID_PARAMETER
;
1280 /* Get/Create the associated VNetRoot for opening */
1281 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1282 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1283 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1285 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1287 RxFreeCanonicalNameBuffer(RxContext
);
1288 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1289 if (NT_SUCCESS(Status
))
1291 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1295 /* Filename cannot contain wildcards */
1296 if (FsRtlDoesNameContainWildCards(NetRootName
))
1298 Status
= STATUS_OBJECT_NAME_INVALID
;
1301 /* Make sure file name is correct */
1302 if (NT_SUCCESS(Status
))
1304 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1307 /* Give the mini-redirector a chance to prepare the name */
1308 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1310 if (RxContext
->Create
.pNetRoot
!= NULL
)
1312 NTSTATUS IgnoredStatus
;
1314 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1315 MRxPreparseName
, (RxContext
, NetRootName
));
1316 (void)IgnoredStatus
;
1325 RxCheckFcbStructuresForAlignment(
1333 _In_ ACCESS_MASK DesiredAccess
,
1334 _In_ ULONG DesiredShareAccess
,
1335 _Inout_ PFILE_OBJECT FileObject
,
1336 _Inout_ PSHARE_ACCESS ShareAccess
,
1337 _In_ BOOLEAN Update
,
1339 _In_ PSZ wherelogtag
)
1343 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1344 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1346 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1353 RxCheckShareAccessPerSrvOpens(
1355 IN ACCESS_MASK DesiredAccess
,
1356 IN ULONG DesiredShareAccess
)
1359 BOOLEAN WriteAccess
;
1360 BOOLEAN DeleteAccess
;
1361 PSHARE_ACCESS ShareAccess
;
1365 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1367 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1368 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1370 /* Check if any access wanted */
1371 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1372 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1373 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1375 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1377 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1378 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1379 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1381 /* Check whether there's a violation */
1383 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1385 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1387 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1388 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1389 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1390 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1392 return STATUS_SHARING_VIOLATION
;
1396 return STATUS_SUCCESS
;
1400 RxCleanupPipeQueues(
1401 PRX_CONTEXT Context
)
1410 RxCloseAssociatedSrvOpen(
1412 IN PRX_CONTEXT RxContext OPTIONAL
)
1417 BOOLEAN CloseSrvOpen
;
1418 PRX_CONTEXT LocalContext
;
1422 /* Assume SRV_OPEN is already closed */
1423 CloseSrvOpen
= FALSE
;
1424 /* If we have a FOBX, we'll have to close it */
1427 /* If the FOBX isn't closed yet */
1428 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1430 SrvOpen
= Fobx
->SrvOpen
;
1431 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1432 /* Check whether we've to close SRV_OPEN first */
1433 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1435 CloseSrvOpen
= TRUE
;
1439 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1441 /* Not much to do */
1442 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1444 if (SrvOpen
->OpenCount
> 0)
1446 --SrvOpen
->OpenCount
;
1451 /* No need to close SRV_OPEN, so close FOBX */
1454 RxMarkFobxOnClose(Fobx
);
1456 return STATUS_SUCCESS
;
1461 /* No FOBX? No RX_CONTEXT, ok, job done! */
1462 if (RxContext
== NULL
)
1464 return STATUS_SUCCESS
;
1467 /* Get the FCB from RX_CONTEXT */
1468 Fcb
= (PFCB
)RxContext
->pFcb
;
1472 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1473 if (RxContext
== NULL
)
1475 ASSERT(Fobx
!= NULL
);
1477 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1478 if (LocalContext
== NULL
)
1480 return STATUS_INSUFFICIENT_RESOURCES
;
1483 LocalContext
->MajorFunction
= 2;
1484 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1485 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1486 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1490 LocalContext
= RxContext
;
1493 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1495 /* Now, close the FOBX */
1498 RxMarkFobxOnClose(Fobx
);
1502 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1505 /* If not a "standard" file, SRV_OPEN can be null */
1506 if (SrvOpen
== NULL
)
1508 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1509 RxDereferenceNetFcb(Fcb
);
1511 if (LocalContext
!= RxContext
)
1513 RxDereferenceAndDeleteRxContext(LocalContext
);
1516 return STATUS_SUCCESS
;
1519 /* If SRV_OPEN isn't in a good condition, nothing to close */
1520 if (SrvOpen
->Condition
!= Condition_Good
)
1522 if (LocalContext
!= RxContext
)
1524 RxDereferenceAndDeleteRxContext(LocalContext
);
1527 return STATUS_SUCCESS
;
1530 /* Decrease open count */
1531 if (SrvOpen
->OpenCount
> 0)
1533 --SrvOpen
->OpenCount
;
1536 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1537 if (SrvOpen
->OpenCount
== 1)
1539 if (!IsListEmpty(&SrvOpen
->FobxList
))
1541 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1543 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1548 /* Nothing left, purge FCB */
1549 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1551 RxPurgeNetFcb(Fcb
, LocalContext
);
1554 /* Already closed? Job done! */
1555 SrvOpen
= Fobx
->SrvOpen
;
1556 if (SrvOpen
== NULL
||
1557 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1558 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1560 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1561 if (LocalContext
!= RxContext
)
1563 RxDereferenceAndDeleteRxContext(LocalContext
);
1566 return STATUS_SUCCESS
;
1569 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1571 /* Inform mini-rdr about closing */
1572 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1573 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1574 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1576 /* And mark as such */
1577 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1578 SrvOpen
->Key
= (PVOID
)-1;
1580 /* If we were delayed, we're not! */
1581 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1583 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1587 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1588 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1591 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1593 /* Mark the FOBX closed as well */
1594 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1596 if (LocalContext
!= RxContext
)
1598 RxDereferenceAndDeleteRxContext(LocalContext
);
1608 RxCollapseOrCreateSrvOpen(
1609 PRX_CONTEXT RxContext
)
1616 PIO_STACK_LOCATION Stack
;
1617 ACCESS_MASK DesiredAccess
;
1618 RX_BLOCK_CONDITION FcbCondition
;
1622 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1624 Fcb
= (PFCB
)RxContext
->pFcb
;
1625 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1626 ++Fcb
->UncleanCount
;
1628 Stack
= RxContext
->CurrentIrpSp
;
1629 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1630 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1632 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1634 /* Try to find a reusable SRV_OPEN */
1635 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1636 if (Status
== STATUS_NOT_FOUND
)
1638 /* If none found, create one */
1639 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1640 if (SrvOpen
== NULL
)
1642 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1646 SrvOpen
->DesiredAccess
= DesiredAccess
;
1647 SrvOpen
->ShareAccess
= ShareAccess
;
1648 Status
= STATUS_SUCCESS
;
1651 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1653 if (Status
!= STATUS_SUCCESS
)
1655 FcbCondition
= Condition_Bad
;
1659 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1661 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1662 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1663 /* Inform the mini-rdr we're handling a create */
1664 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1665 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1667 DPRINT("MRxCreate returned: %x\n", Status
);
1668 if (Status
== STATUS_SUCCESS
)
1670 /* In case of overwrite, reset file size */
1671 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1673 RxAcquirePagingIoResource(RxContext
, Fcb
);
1674 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1675 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1676 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1677 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1678 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1679 RxReleasePagingIoResource(RxContext
, Fcb
);
1683 /* Otherwise, adjust sizes */
1684 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1685 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1687 RxAdjustAllocationSizeforCC(Fcb
);
1689 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1693 /* Set the IoStatus with information returned by mini-rdr */
1694 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1696 SrvOpen
->OpenStatus
= Status
;
1697 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1698 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1700 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1702 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1704 if (Status
== STATUS_SUCCESS
)
1706 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1708 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1710 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1711 FcbCondition
= Condition_Good
;
1715 FcbCondition
= Condition_Bad
;
1716 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1717 RxContext
->pRelevantSrvOpen
= NULL
;
1719 if (RxContext
->pFobx
!= NULL
)
1721 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1722 RxContext
->pFobx
= NULL
;
1727 /* Set FCB state - good or bad - depending on whether create succeed */
1728 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1729 RxTransitionNetFcb(Fcb
, FcbCondition
);
1731 else if (Status
== STATUS_SUCCESS
)
1733 BOOLEAN IsGood
, ExtraOpen
;
1735 /* A reusable SRV_OPEN was found */
1736 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1739 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1741 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1742 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1743 if (!StableCondition(SrvOpen
->Condition
))
1745 RxReferenceSrvOpen(SrvOpen
);
1746 ++SrvOpen
->OpenCount
;
1749 RxReleaseFcb(RxContext
, Fcb
);
1750 RxContext
->Create
.FcbAcquired
= FALSE
;
1752 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1754 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1756 RxContext
->Create
.FcbAcquired
= TRUE
;
1759 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1762 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1765 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1767 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1771 Status
= SrvOpen
->OpenStatus
;
1776 --SrvOpen
->OpenCount
;
1777 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1781 --Fcb
->UncleanCount
;
1783 DPRINT("Status: %x\n", Status
);
1793 PRX_CONTEXT Context
)
1795 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1801 PFILE_OBJECT FileObject
;
1802 LARGE_INTEGER TruncateSize
;
1803 PLARGE_INTEGER TruncateSizePtr
;
1804 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1808 Fcb
= (PFCB
)Context
->pFcb
;
1809 Fobx
= (PFOBX
)Context
->pFobx
;
1810 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1812 /* File system closing, it's OK */
1815 if (Fcb
->UncleanCount
> 0)
1817 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1820 return STATUS_SUCCESS
;
1823 /* Check we have a correct FCB type */
1824 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1825 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1826 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1827 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1829 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1830 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1833 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1834 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1836 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1838 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1839 if (!NT_SUCCESS(Status
))
1846 Fobx
->AssociatedFileObject
= NULL
;
1848 /* In case SRV_OPEN used is part of FCB */
1849 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
))
1851 ASSERT(Fcb
->UncleanCount
!= 0);
1852 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1854 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1856 --Fcb
->UncachedUncleanCount
;
1859 /* Inform mini-rdr */
1860 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1862 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1863 --Fobx
->SrvOpen
->UncleanFobxCount
;
1865 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1867 RxReleaseFcb(Context
, Fcb
);
1869 return STATUS_SUCCESS
;
1872 /* Report the fact that file could be set as delete on close */
1873 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1875 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1878 /* Cancel any pending notification */
1879 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1881 /* Backup open count before we start playing with it */
1882 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1884 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1885 FcbTableAcquired
= FALSE
;
1886 LeftForDelete
= FALSE
;
1887 OneLeft
= (Fcb
->UncleanCount
== 1);
1891 /* Unclean count and delete on close? Verify whether we're the one */
1892 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1894 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1896 FcbTableAcquired
= TRUE
;
1900 RxReleaseFcb(Context
, Fcb
);
1902 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1904 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1905 if (Status
!= STATUS_SUCCESS
)
1907 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1911 FcbTableAcquired
= TRUE
;
1914 /* That means we'll perform the delete on close! */
1915 if (Fcb
->UncleanCount
== 1)
1917 LeftForDelete
= TRUE
;
1921 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1922 FcbTableAcquired
= FALSE
;
1927 TruncateSizePtr
= NULL
;
1928 /* Handle cleanup for pipes and printers */
1929 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1931 RxCleanupPipeQueues(Context
);
1933 /* Handle cleanup for files */
1934 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1936 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1937 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1940 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1942 /* If there are still locks to release, proceed */
1943 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1945 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1946 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1947 Status
= RxLowIoLockControlShell(Context
);
1950 /* Fix times and size */
1951 RxAdjustFileTimesAndSize(Context
);
1953 /* If we're the only one left... */
1956 /* And if we're supposed to delete on close */
1959 /* Update the sizes */
1960 RxAcquirePagingIoResource(Context
, Fcb
);
1961 Fcb
->Header
.FileSize
.QuadPart
= 0;
1962 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1963 RxReleasePagingIoResource(Context
, Fcb
);
1965 /* Otherwise, call the mini-rdr to adjust sizes */
1968 /* File got grown up, fill with zeroes */
1969 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1970 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1972 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1973 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1976 /* File was truncated, let mini-rdr proceed */
1977 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1979 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1980 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1982 /* Keep track of file change for Cc uninit */
1983 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1984 TruncateSizePtr
= &TruncateSize
;
1989 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1997 /* Otherwise, try to see whether we can purge */
2000 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2007 /* We have to still be there! */
2008 ASSERT(Fcb
->UncleanCount
!= 0);
2009 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2011 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2013 --Fcb
->UncachedUncleanCount
;
2016 /* Inform mini-rdr about ongoing cleanup */
2017 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2019 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2020 --Fobx
->SrvOpen
->UncleanFobxCount
;
2023 if (DisableFlushOnCleanup
)
2025 /* Only if we're the last standing */
2026 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2027 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2029 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2030 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2036 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2038 DPRINT("Flushing %p on cleanup\n", Context
);
2039 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2043 /* If only remaining uncached & unclean, then flush and purge */
2044 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2046 if (Fcb
->UncachedUncleanCount
!= 0)
2048 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2049 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2051 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2052 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2057 /* If purge required, and not about to delete, flush */
2058 if (!LeftForDelete
&& NeedPurge
)
2060 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2061 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2064 /* If it was a file, drop cache */
2067 DPRINT("Uninit cache map for file\n");
2068 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2071 /* If that's the one left for deletion, or if it needs purge, flush */
2072 if (LeftForDelete
|| NeedPurge
)
2074 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2075 /* If that's for deletion, also remove from FCB table */
2078 RxRemoveNameNetFcb(Fcb
);
2079 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2080 FcbTableAcquired
= FALSE
;
2084 /* Remove any share access */
2085 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2087 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2090 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2091 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2092 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2094 NTSTATUS InternalStatus
;
2095 PRX_CONTEXT InternalContext
;
2097 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2098 InternalStatus
= STATUS_UNSUCCESSFUL
;
2099 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2100 Fcb
->RxDeviceObject
,
2101 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2102 if (InternalContext
!= NULL
)
2104 FILE_END_OF_FILE_INFORMATION FileEOF
;
2106 InternalStatus
= STATUS_SUCCESS
;
2108 /* Initialize the context for file information set */
2109 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2110 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2111 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2113 /* Get EOF from the FCB */
2114 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2115 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2116 InternalContext
->Info
.Buffer
= &FileEOF
;
2117 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2119 /* Call the mini-rdr */
2120 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2123 RxDereferenceAndDeleteRxContext(InternalContext
);
2126 /* We tried, so, clean the FOBX flag */
2127 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2128 /* If it failed, then, disable collapsing on the FCB */
2129 if (!NT_SUCCESS(InternalStatus
))
2131 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2136 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2138 FcbAcquired
= FALSE
;
2139 RxReleaseFcb(Context
, Fcb
);
2145 RxReleaseFcb(Context
, Fcb
);
2148 if (FcbTableAcquired
)
2150 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2156 #undef BugCheckFileId
2162 PRX_CONTEXT Context
)
2164 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2168 PFILE_OBJECT FileObject
;
2169 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2173 Fcb
= (PFCB
)Context
->pFcb
;
2174 Fobx
= (PFOBX
)Context
->pFobx
;
2175 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2176 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2178 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2179 if (!NT_SUCCESS(Status
))
2189 /* Check our FCB type is expected */
2190 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2191 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2192 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2194 RxBugCheck(NodeType(Fcb
), 0, 0);
2197 RxReferenceNetFcb(Fcb
);
2199 DereferenceFobx
= FALSE
;
2200 /* If we're not closing FS */
2206 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2207 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2208 /* Handle delayed close */
2209 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2211 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2213 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2215 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2217 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2219 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2221 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2225 DereferenceFobx
= TRUE
;
2226 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2233 /* If we reach maximum of delayed close/or if there are no delayed close */
2234 if (!DereferenceFobx
)
2238 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2239 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2241 /* Delete if asked */
2242 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2244 RxScavengeRelatedFobxs(Fcb
);
2245 RxSynchronizeWithScavenger(Context
);
2247 RxReleaseFcb(Context
, Fcb
);
2249 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2250 RxOrphanThisFcb(Fcb
);
2251 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2253 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2254 ASSERT(NT_SUCCESS(Status
));
2259 RxMarkFobxOnClose(Fobx
);
2262 if (DereferenceFobx
)
2264 ASSERT(Fobx
!= NULL
);
2265 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2269 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2272 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2276 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2277 AcquiredFcb
= !Freed
;
2279 FileObject
->FsContext
= (PVOID
)-1;
2283 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2287 RxReleaseFcb(Context
, Fcb
);
2288 AcquiredFcb
= FALSE
;
2293 if (_SEH2_AbnormalTermination())
2297 RxReleaseFcb(Context
, Fcb
);
2302 ASSERT(!AcquiredFcb
);
2307 DPRINT("Status: %x\n", Status
);
2309 #undef BugCheckFileId
2318 PRX_CONTEXT Context
)
2322 PFILE_OBJECT FileObject
;
2323 PIO_STACK_LOCATION Stack
;
2327 DPRINT("RxCommonCreate(%p)\n", Context
);
2329 Irp
= Context
->CurrentIrp
;
2330 Stack
= Context
->CurrentIrpSp
;
2331 FileObject
= Stack
->FileObject
;
2333 /* Check whether that's a device opening */
2334 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2336 FileObject
->FsContext
= &RxDeviceFCB
;
2337 FileObject
->FsContext2
= NULL
;
2339 ++RxDeviceFCB
.NodeReferenceCount
;
2340 ++RxDeviceFCB
.OpenCount
;
2342 Irp
->IoStatus
.Information
= FILE_OPENED
;
2343 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2345 Status
= STATUS_SUCCESS
;
2349 PFCB RelatedFcb
= NULL
;
2351 /* Make sure caller is consistent */
2352 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2353 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2355 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2356 return STATUS_INVALID_PARAMETER
;
2359 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2360 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2361 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2362 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2364 if (FileObject
->RelatedFileObject
!= NULL
)
2366 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2367 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2370 /* Going to rename? */
2371 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2373 DPRINT("TargetDir!\n");
2376 /* Copy create parameters to the context */
2377 RxCopyCreateParameters(Context
);
2379 /* If the caller wants to establish a connection, go ahead */
2380 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2382 Status
= RxCreateTreeConnect(Context
);
2386 /* Validate file name */
2387 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2388 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2389 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2391 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2392 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2393 FileObject
->FileName
.Length
);
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 return STATUS_OBJECT_NAME_INVALID
;
2403 /* Attempt to open the file */
2406 UNICODE_STRING NetRootName
;
2408 /* Strip last \ if required */
2409 if (FileObject
->FileName
.Length
!= 0 &&
2410 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2412 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2414 return STATUS_OBJECT_NAME_INVALID
;
2417 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2418 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2421 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2423 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2426 /* Get the associated net root to opening */
2427 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2428 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2433 /* And attempt to open */
2434 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2435 if (Status
== STATUS_SHARING_VIOLATION
)
2437 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2439 /* If that happens for file creation, fail for real */
2440 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2442 Status
= STATUS_OBJECT_NAME_COLLISION
;
2446 /* Otherwise, if possible, attempt to scavenger current FOBX
2447 * to check whether a dormant FOBX is the reason for sharing violation
2449 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2450 !Context
->Create
.ScavengingAlreadyTried
)
2452 /* Only doable with a VNetRoot */
2453 if (Context
->Create
.pVNetRoot
!= NULL
)
2455 PV_NET_ROOT VNetRoot
;
2456 NT_CREATE_PARAMETERS SavedParameters
;
2458 /* Save create parameters */
2459 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2461 /* Reference the VNetRoot for the scavenging time */
2462 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2463 RxReferenceVNetRoot(VNetRoot
);
2465 /* Prepare the RX_CONTEXT for reuse */
2466 RxpPrepareCreateContextForReuse(Context
);
2467 RxReinitializeContext(Context
);
2469 /* Copy what we saved */
2470 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2472 /* And recopy what can be */
2473 RxCopyCreateParameters(Context
);
2475 /* And start purging, then scavenging FOBX */
2476 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2477 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2478 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2481 /* Ask for a second round */
2482 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2484 /* Keep track we already scavenged */
2485 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2487 /* Reference our SRV_CALL for CBS handling */
2488 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2489 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2491 /* Drop our extra reference */
2492 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2497 else if (Status
== STATUS_REPARSE
)
2499 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2503 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2506 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2509 if (Status
== STATUS_RETRY
)
2511 RxpPrepareCreateContextForReuse(Context
);
2513 ASSERT(Status
!= STATUS_PENDING
);
2516 DPRINT("Status: %lx\n", Status
);
2525 RxCommonDevFCBCleanup(
2526 PRX_CONTEXT Context
)
2533 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2535 Fcb
= Context
->pFcb
;
2536 Status
= STATUS_SUCCESS
;
2537 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2539 /* Our FOBX if set, has to be a VNetRoot */
2540 if (Context
->pFobx
!= NULL
)
2542 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2543 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2545 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2547 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2551 --Fcb
->UncleanCount
;
2562 RxCommonDevFCBClose(
2563 PRX_CONTEXT Context
)
2567 PMRX_V_NET_ROOT NetRoot
;
2571 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2573 Fcb
= Context
->pFcb
;
2574 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2575 Status
= STATUS_SUCCESS
;
2576 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2578 /* Our FOBX if set, has to be a VNetRoot */
2579 if (NetRoot
!= NULL
)
2581 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2582 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2584 --NetRoot
->NumberOfOpens
;
2585 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2589 Status
= STATUS_NOT_IMPLEMENTED
;
2591 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2603 RxCommonDevFCBFsCtl(
2604 PRX_CONTEXT Context
)
2607 return STATUS_NOT_IMPLEMENTED
;
2615 RxCommonDevFCBIoCtl(
2616 PRX_CONTEXT Context
)
2622 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2624 if (Context
->pFobx
!= NULL
)
2626 return STATUS_INVALID_HANDLE
;
2629 /* Is that a prefix claim from MUP? */
2630 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2632 return RxPrefixClaim(Context
);
2635 /* Otherwise, pass through the mini-rdr */
2636 Status
= RxXXXControlFileCallthru(Context
);
2637 if (Status
!= STATUS_PENDING
)
2639 if (Context
->PostRequest
)
2641 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2642 Status
= RxFsdPostRequest(Context
);
2646 DPRINT("Status: %lx\n", Status
);
2652 RxCommonDevFCBQueryVolInfo(
2653 PRX_CONTEXT Context
)
2656 return STATUS_NOT_IMPLEMENTED
;
2664 RxCommonDeviceControl(
2665 PRX_CONTEXT Context
)
2671 /* Prefix claim is only allowed for device, not files */
2672 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2674 return STATUS_INVALID_DEVICE_REQUEST
;
2677 /* Submit to mini-rdr */
2678 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2679 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2680 if (Status
== STATUS_PENDING
)
2682 RxDereferenceAndDeleteRxContext_Real(Context
);
2693 RxCommonDirectoryControl(
2694 PRX_CONTEXT Context
)
2699 PIO_STACK_LOCATION Stack
;
2703 Fcb
= (PFCB
)Context
->pFcb
;
2704 Fobx
= (PFOBX
)Context
->pFobx
;
2705 Stack
= Context
->CurrentIrpSp
;
2706 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2708 /* Call the appropriate helper */
2709 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2711 Status
= RxQueryDirectory(Context
);
2713 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2715 Status
= RxNotifyChangeDirectory(Context
);
2716 if (Status
== STATUS_PENDING
)
2718 RxDereferenceAndDeleteRxContext_Real(Context
);
2723 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2731 RxCommonDispatchProblem(
2732 PRX_CONTEXT Context
)
2735 return STATUS_NOT_IMPLEMENTED
;
2740 RxCommonFileSystemControl(
2741 PRX_CONTEXT Context
)
2745 PIO_STACK_LOCATION Stack
;
2749 Irp
= Context
->CurrentIrp
;
2750 Stack
= Context
->CurrentIrpSp
;
2751 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2753 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2756 return STATUS_NOT_IMPLEMENTED
;
2761 RxCommonFlushBuffers(
2762 PRX_CONTEXT Context
)
2765 return STATUS_NOT_IMPLEMENTED
;
2770 RxCommonLockControl(
2771 PRX_CONTEXT Context
)
2774 return STATUS_NOT_IMPLEMENTED
;
2780 PRX_CONTEXT Context
)
2783 return STATUS_NOT_IMPLEMENTED
;
2791 RxCommonQueryInformation(
2792 PRX_CONTEXT Context
)
2794 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2795 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2796 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2803 PIO_STACK_LOCATION Stack
;
2804 FILE_INFORMATION_CLASS FileInfoClass
;
2808 Fcb
= (PFCB
)Context
->pFcb
;
2809 Fobx
= (PFOBX
)Context
->pFobx
;
2810 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2812 Irp
= Context
->CurrentIrp
;
2813 Stack
= Context
->CurrentIrpSp
;
2814 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2815 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2817 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2818 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2825 /* Get a writable buffer */
2826 Buffer
= RxMapSystemBuffer(Context
);
2829 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2833 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2835 /* Validate file type */
2836 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2838 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2840 Status
= STATUS_INVALID_PARAMETER
;
2843 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2845 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2847 Status
= STATUS_NOT_IMPLEMENTED
;
2851 Status
= STATUS_INVALID_PARAMETER
;
2858 /* Acquire the right lock */
2859 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2860 FileInfoClass
!= FileNameInformation
)
2862 if (FileInfoClass
== FileCompressionInformation
)
2864 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2868 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2871 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2873 Status
= STATUS_PENDING
;
2876 else if (!NT_SUCCESS(Status
))
2884 /* Dispatch to the right helper */
2885 switch (FileInfoClass
)
2887 case FileBasicInformation
:
2888 Status
= RxQueryBasicInfo(Context
, Buffer
);
2891 case FileStandardInformation
:
2892 Status
= RxQueryStandardInfo(Context
, Buffer
);
2895 case FileInternalInformation
:
2896 Status
= RxQueryInternalInfo(Context
, Buffer
);
2899 case FileEaInformation
:
2900 Status
= RxQueryEaInfo(Context
, Buffer
);
2903 case FileNameInformation
:
2904 Status
= RxQueryNameInfo(Context
, Buffer
);
2907 case FileAllInformation
:
2908 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2909 if (!NT_SUCCESS(Status
))
2914 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2915 if (!NT_SUCCESS(Status
))
2920 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2921 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2922 if (!NT_SUCCESS(Status
))
2927 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2928 sizeof(FILE_STANDARD_INFORMATION
) +
2929 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2930 if (!NT_SUCCESS(Status
))
2935 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2936 sizeof(FILE_STANDARD_INFORMATION
) +
2937 sizeof(FILE_INTERNAL_INFORMATION
) +
2938 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2939 if (!NT_SUCCESS(Status
))
2944 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2945 sizeof(FILE_STANDARD_INFORMATION
) +
2946 sizeof(FILE_INTERNAL_INFORMATION
) +
2947 sizeof(FILE_EA_INFORMATION
) +
2948 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2951 case FileAlternateNameInformation
:
2952 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2955 case FilePipeInformation
:
2956 case FilePipeLocalInformation
:
2957 case FilePipeRemoteInformation
:
2958 Status
= RxQueryPipeInfo(Context
, Buffer
);
2961 case FileCompressionInformation
:
2962 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2966 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2967 Status
= Context
->IoStatusBlock
.Status
;
2971 if (Context
->Info
.Length
< 0)
2973 Status
= STATUS_BUFFER_OVERFLOW
;
2974 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2977 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2983 RxReleaseFcb(Context
, Fcb
);
2988 DPRINT("Status: %x\n", Status
);
2991 #undef SET_SIZE_AND_QUERY
2996 RxCommonQueryQuotaInformation(
2997 PRX_CONTEXT Context
)
3000 return STATUS_NOT_IMPLEMENTED
;
3005 RxCommonQuerySecurity(
3006 PRX_CONTEXT Context
)
3009 return STATUS_NOT_IMPLEMENTED
;
3017 RxCommonQueryVolumeInformation(
3018 PRX_CONTEXT Context
)
3024 PIO_STACK_LOCATION Stack
;
3028 Fcb
= (PFCB
)Context
->pFcb
;
3029 Fobx
= (PFOBX
)Context
->pFobx
;
3031 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3033 Irp
= Context
->CurrentIrp
;
3034 Stack
= Context
->CurrentIrpSp
;
3035 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3036 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3038 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3039 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3040 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3042 /* Forward to mini-rdr */
3043 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3045 /* Post request if mini-rdr asked to */
3046 if (Context
->PostRequest
)
3048 Status
= RxFsdPostRequest(Context
);
3052 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3055 DPRINT("Status: %x\n", Status
);
3062 PRX_CONTEXT RxContext
)
3070 PFILE_OBJECT FileObject
;
3071 LARGE_INTEGER ByteOffset
;
3072 PIO_STACK_LOCATION Stack
;
3073 PLOWIO_CONTEXT LowIoContext
;
3074 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3075 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3076 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3080 Fcb
= (PFCB
)RxContext
->pFcb
;
3081 Fobx
= (PFOBX
)RxContext
->pFobx
;
3082 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3084 /* Get some parameters */
3085 Irp
= RxContext
->CurrentIrp
;
3086 Stack
= RxContext
->CurrentIrpSp
;
3087 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3088 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3089 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3090 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3091 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3092 ReadLength
= Stack
->Parameters
.Read
.Length
;
3093 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3094 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3095 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3097 RxItsTheSameContext();
3099 Irp
->IoStatus
.Information
= 0;
3101 /* Should the read be loud - so far, it's just ignored on ReactOS:
3102 * s/DPRINT/DPRINT1/g will make it loud
3104 LowIoContext
= &RxContext
->LowIoContext
;
3105 CheckForLoudOperations(RxContext
);
3106 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3108 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3109 ByteOffset
, ReadLength
,
3110 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3113 RxDeviceObject
= RxContext
->RxDeviceObject
;
3115 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3117 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3119 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3121 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3123 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3127 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3131 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3135 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3139 /* A pagefile cannot be a pipe */
3140 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3141 if (IsPipe
&& PagingIo
)
3143 return STATUS_INVALID_DEVICE_REQUEST
;
3146 /* Null-length read is no-op */
3147 if (ReadLength
== 0)
3149 return STATUS_SUCCESS
;
3152 /* Validate FCB type */
3153 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3155 return STATUS_INVALID_DEVICE_REQUEST
;
3158 /* Init the lowio context for possible forward */
3159 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3161 PostRequest
= FALSE
;
3162 ReadCachingDisabled
= FALSE
;
3164 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3165 FileObject
= Stack
->FileObject
;
3166 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3171 /* If no caching, make sure current Cc data have been flushed */
3172 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3174 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3175 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3180 else if (Status
!= STATUS_SUCCESS
)
3185 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3186 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3187 RxReleasePagingIoResource(RxContext
, Fcb
);
3189 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3191 Status
= Irp
->IoStatus
.Status
;
3195 RxAcquirePagingIoResource(RxContext
, Fcb
);
3196 RxReleasePagingIoResource(RxContext
, Fcb
);
3199 /* Acquire the appropriate lock */
3200 if (PagingIo
&& !ReadCachingEnabled
)
3204 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3212 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3217 if (!ReadCachingEnabled
)
3219 if (!CanWait
&& NoCache
)
3221 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3222 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3224 DPRINT1("RdAsyLNG %x\n", RxContext
);
3228 if (Status
!= STATUS_SUCCESS
)
3230 DPRINT1("RdAsyOthr %x\n", RxContext
);
3234 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3236 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3246 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3247 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3252 else if (Status
!= STATUS_SUCCESS
)
3260 RxItsTheSameContext();
3262 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3268 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3270 /* Make sure FLOCK doesn't conflict */
3273 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3275 Status
= STATUS_FILE_LOCK_CONFLICT
;
3280 /* Validate byteoffset vs length */
3281 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3283 if (ByteOffset
.QuadPart
>= FileSize
)
3285 Status
= STATUS_END_OF_FILE
;
3289 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3291 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3296 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3297 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3299 /* File was not cached yet, do it */
3300 if (FileObject
->PrivateCacheMap
== NULL
)
3302 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3304 Status
= STATUS_FILE_CLOSED
;
3308 RxAdjustAllocationSizeforCC(Fcb
);
3310 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3311 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3313 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3315 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3319 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3320 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3323 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3326 /* This should never happen - fix your RDR */
3327 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3332 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3333 Status
= Irp
->IoStatus
.Status
;
3334 ASSERT(NT_SUCCESS(Status
));
3339 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3340 if (SystemBuffer
== NULL
)
3342 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3346 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3348 RxItsTheSameContext();
3350 /* Perform the read */
3351 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus