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
,
452 RxSetupNetFileObject(
453 PRX_CONTEXT RxContext
);
457 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
461 RxUninitializeCacheMap(
462 PRX_CONTEXT RxContext
,
463 PFILE_OBJECT FileObject
,
464 PLARGE_INTEGER TruncateSize
);
469 PRDBSS_DEVICE_OBJECT DeviceObject
);
472 RxXXXControlFileCallthru(
473 PRX_CONTEXT Context
);
477 _RxAllocatePoolWithTag(
478 _In_ POOL_TYPE PoolType
,
479 _In_ SIZE_T NumberOfBytes
,
493 WCHAR RxStarForTemplate
= '*';
494 WCHAR Rx8QMdot3QM
[] = L
">>>>>>>>.>>>*";
495 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles
= FALSE
;
496 BOOLEAN DisableFlushOnCleanup
= FALSE
;
497 ULONG ReadAheadGranularity
= 1 << PAGE_SHIFT
;
498 LIST_ENTRY RxActiveContexts
;
499 NPAGED_LOOKASIDE_LIST RxContextLookasideList
;
500 FAST_MUTEX RxContextPerFileSerializationMutex
;
503 BOOLEAN RxLoudLowIoOpsEnabled
= FALSE
;
504 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
506 { RxCommonDispatchProblem
},
507 { RxCommonDispatchProblem
},
508 { RxCommonDevFCBClose
},
509 { RxCommonDispatchProblem
},
510 { RxCommonDispatchProblem
},
511 { RxCommonDispatchProblem
},
512 { RxCommonDispatchProblem
},
513 { RxCommonDispatchProblem
},
514 { RxCommonDispatchProblem
},
515 { RxCommonDispatchProblem
},
516 { RxCommonDevFCBQueryVolInfo
},
517 { RxCommonDispatchProblem
},
518 { RxCommonDispatchProblem
},
519 { RxCommonDevFCBFsCtl
},
520 { RxCommonDevFCBIoCtl
},
521 { RxCommonDevFCBIoCtl
},
522 { RxCommonDispatchProblem
},
523 { RxCommonDispatchProblem
},
524 { RxCommonDevFCBCleanup
},
525 { RxCommonDispatchProblem
},
526 { RxCommonDispatchProblem
},
527 { RxCommonDispatchProblem
},
528 { RxCommonUnimplemented
},
529 { RxCommonUnimplemented
},
530 { RxCommonUnimplemented
},
531 { RxCommonUnimplemented
},
532 { RxCommonUnimplemented
},
533 { RxCommonUnimplemented
},
535 RDBSS_EXPORTS RxExports
;
536 FAST_IO_DISPATCH RxFastIoDispatch
;
537 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject
;
538 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
+ 1] =
541 { RxCommonUnimplemented
},
545 { RxCommonQueryInformation
},
546 { RxCommonSetInformation
},
549 { RxCommonFlushBuffers
},
550 { RxCommonQueryVolumeInformation
},
551 { RxCommonSetVolumeInformation
},
552 { RxCommonDirectoryControl
},
553 { RxCommonFileSystemControl
},
554 { RxCommonDeviceControl
},
555 { RxCommonDeviceControl
},
556 { RxCommonUnimplemented
},
557 { RxCommonLockControl
},
559 { RxCommonUnimplemented
},
560 { RxCommonQuerySecurity
},
561 { RxCommonSetSecurity
},
562 { RxCommonUnimplemented
},
563 { RxCommonUnimplemented
},
564 { RxCommonUnimplemented
},
565 { RxCommonQueryQuotaInformation
},
566 { RxCommonSetQuotaInformation
},
567 { RxCommonUnimplemented
},
569 ULONG RxFsdEntryCount
;
570 LIST_ENTRY RxIrpsList
;
571 KSPIN_LOCK RxIrpsListSpinLock
;
572 KMUTEX RxScavengerMutex
;
573 KMUTEX RxSerializationMutex
;
574 UCHAR RxSpaceForTheWrappersDeviceObject
[sizeof(*RxFileSystemDeviceObject
)];
575 KSPIN_LOCK TopLevelIrpSpinLock
;
576 LIST_ENTRY TopLevelIrpAllocatedContextsList
;
577 BOOLEAN RxForceQFIPassThrough
= FALSE
;
578 BOOLEAN RxNoAsync
= FALSE
;
580 DECLARE_CONST_UNICODE_STRING(unknownId
, L
"???");
587 #define ASSERT(exp) \
590 RxAssert(#exp, __FILE__, __LINE__, NULL); \
595 #undef RxAllocatePool
596 #undef RxAllocatePoolWithTag
599 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
600 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
601 #define RxFreePool _RxFreePool
602 #define RxFreePoolWithTag _RxFreePoolWithTag
605 /* FUNCTIONS ****************************************************************/
611 CheckForLoudOperations(
612 PRX_CONTEXT RxContext
)
616 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
618 /* Are loud operations enabled? */
619 if (RxLoudLowIoOpsEnabled
)
623 /* If so, the operation will be loud only if filename ends with all.scr */
624 Fcb
= (PFCB
)RxContext
->pFcb
;
625 if (RtlCompareMemory(Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, (Fcb
->PrivateAlreadyPrefixedName
.Length
- ALLSCR_LENGTH
)),
626 L
"all.scr", ALLSCR_LENGTH
) == ALLSCR_LENGTH
)
628 SetFlag(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
);
638 __RxInitializeTopLevelIrpContext(
639 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
641 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
644 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext
, Irp
, RxDeviceObject
, Flags
);
646 RtlZeroMemory(TopLevelContext
, sizeof(RX_TOPLEVELIRP_CONTEXT
));
647 TopLevelContext
->Irp
= Irp
;
648 TopLevelContext
->Flags
= (Flags
? RX_TOPLEVELCTX_FLAG_FROM_POOL
: 0);
649 TopLevelContext
->Signature
= RX_TOPLEVELIRP_CONTEXT_SIGNATURE
;
650 TopLevelContext
->RxDeviceObject
= RxDeviceObject
;
651 TopLevelContext
->Previous
= IoGetTopLevelIrp();
652 TopLevelContext
->Thread
= PsGetCurrentThread();
654 /* We cannot add to list something that'd come from stack */
655 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
657 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext
);
665 __RxWriteReleaseResources(
666 PRX_CONTEXT RxContext
,
667 BOOLEAN ResourceOwnerSet
,
676 ASSERT(RxContext
!= NULL
);
678 Fcb
= (PFCB
)RxContext
->pFcb
;
681 /* If FCB resource was acquired, release it */
682 if (RxContext
->FcbResourceAcquired
)
684 /* Taking care of owner */
685 if (ResourceOwnerSet
)
687 RxReleaseFcbForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
691 RxReleaseFcb(RxContext
, Fcb
);
694 RxContext
->FcbResourceAcquired
= FALSE
;
697 /* If FCB paging resource was acquired, release it */
698 if (RxContext
->FcbPagingIoResourceAcquired
)
700 /* Taking care of owner */
701 if (ResourceOwnerSet
)
703 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, RxContext
->LowIoContext
.ResourceThreadId
);
707 RxReleasePagingIoResource(RxContext
, Fcb
);
710 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
716 RxAcquireExclusiveFcbResourceInMRx(
717 _Inout_ PMRX_FCB Fcb
)
720 return STATUS_NOT_IMPLEMENTED
;
725 RxAcquireFcbForLazyWrite(
735 RxAcquireFcbForReadAhead(
745 RxAcquireFileForNtCreateSection(
746 PFILE_OBJECT FileObject
)
754 PFILE_OBJECT FileObject
,
755 PDEVICE_OBJECT DeviceObject
)
758 return STATUS_NOT_IMPLEMENTED
;
765 RxAddToTopLevelIrpAllocatedContextsList(
766 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
770 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext
);
772 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
773 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
775 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
776 InsertTailList(&TopLevelIrpAllocatedContextsList
, &TopLevelContext
->ListEntry
);
777 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
786 IN PRX_CONTEXT RxContext
,
791 WORK_QUEUE_TYPE Queue
;
792 PIO_STACK_LOCATION Stack
;
794 Stack
= RxContext
->CurrentIrpSp
;
795 RxContext
->PostRequest
= FALSE
;
797 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
798 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
&&
799 Stack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
801 Queue
= DelayedWorkQueue
;
802 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
);
806 Queue
= CriticalWorkQueue
;
807 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
);
810 /* Check for overflow */
811 if (Stack
->FileObject
!= NULL
)
813 KeAcquireSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
815 Queued
= InterlockedIncrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
816 /* In case of an overflow, add the new queued call to the overflow list */
819 InterlockedDecrement(&RxFileSystemDeviceObject
->PostedRequestCount
[Queue
]);
820 InsertTailList(&RxFileSystemDeviceObject
->OverflowQueue
[Queue
], &RxContext
->OverflowListEntry
);
821 ++RxFileSystemDeviceObject
->OverflowQueueCount
[Queue
];
823 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
827 KeReleaseSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
, OldIrql
);
830 ExInitializeWorkItem(&RxContext
->WorkQueueItem
, RxFspDispatch
, RxContext
);
831 ExQueueWorkItem((PWORK_QUEUE_ITEM
)&RxContext
->WorkQueueItem
, Queue
);
838 RxAdjustFileTimesAndSize(
844 PFILE_OBJECT FileObject
;
845 LARGE_INTEGER CurrentTime
;
846 FILE_BASIC_INFORMATION FileBasicInfo
;
847 FILE_END_OF_FILE_INFORMATION FileEOFInfo
;
848 BOOLEAN FileModified
, SetLastChange
, SetLastAccess
, SetLastWrite
, NeedUpdate
;
852 FileObject
= Context
->CurrentIrpSp
->FileObject
;
853 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
854 if (FileObject
->PrivateCacheMap
== NULL
)
860 KeQuerySystemTime(&CurrentTime
);
862 Fobx
= (PFOBX
)Context
->pFobx
;
863 /* Was the file modified? */
864 FileModified
= BooleanFlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
);
865 /* We'll set last write if it was modified and user didn't update yet */
866 SetLastWrite
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_WRITE
);
867 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
868 SetLastAccess
= SetLastWrite
||
869 (BooleanFlagOn(FileObject
->Flags
, FO_FILE_FAST_IO_READ
) &&
870 !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_ACCESS
));
871 /* We'll set last change if it was modified and user didn't update yet */
872 SetLastChange
= FileModified
&& !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_USER_SET_LAST_CHANGE
);
874 /* Nothing to update? Job done */
875 if (!FileModified
&& !SetLastWrite
&& !SetLastAccess
&& !SetLastChange
)
880 Fcb
= (PFCB
)Context
->pFcb
;
881 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
883 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
885 /* Update lastwrite time if required */
889 Fcb
->LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
890 FileBasicInfo
.LastWriteTime
.QuadPart
= CurrentTime
.QuadPart
;
893 /* Update lastaccess time if required */
897 Fcb
->LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
898 FileBasicInfo
.LastAccessTime
.QuadPart
= CurrentTime
.QuadPart
;
901 /* Update lastchange time if required */
905 Fcb
->LastChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
906 FileBasicInfo
.ChangeTime
.QuadPart
= CurrentTime
.QuadPart
;
909 /* If one of the date was modified, issue a call to mini-rdr */
912 Context
->Info
.FileInformationClass
= FileBasicInformation
;
913 Context
->Info
.Buffer
= &FileBasicInfo
;
914 Context
->Info
.Length
= sizeof(FileBasicInfo
);
916 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
920 /* If the file was modified, update its EOF */
923 FileEOFInfo
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
925 Context
->Info
.FileInformationClass
= FileEndOfFileInformation
;
926 Context
->Info
.Buffer
= &FileEOFInfo
;
927 Context
->Info
.Length
= sizeof(FileEOFInfo
);
929 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxSetFileInfoAtCleanup
, (Context
));
938 RxAllocateCanonicalNameBuffer(
939 PRX_CONTEXT RxContext
,
940 PUNICODE_STRING CanonicalName
,
941 USHORT CanonicalLength
)
945 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext
, RxContext
->Create
.CanonicalNameBuffer
);
947 /* Context must be free of any already allocated name */
948 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
950 /* Validate string length */
951 if (CanonicalLength
> USHRT_MAX
- 1)
953 CanonicalName
->Buffer
= NULL
;
954 return STATUS_OBJECT_PATH_INVALID
;
957 CanonicalName
->Buffer
= RxAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
, CanonicalLength
, RX_MISC_POOLTAG
);
958 if (CanonicalName
->Buffer
== NULL
)
960 return STATUS_INSUFFICIENT_RESOURCES
;
963 CanonicalName
->Length
= 0;
964 CanonicalName
->MaximumLength
= CanonicalLength
;
966 /* Set the two places - they must always be identical */
967 RxContext
->Create
.CanonicalNameBuffer
= CanonicalName
->Buffer
;
968 RxContext
->AlsoCanonicalNameBuffer
= CanonicalName
->Buffer
;
970 return STATUS_SUCCESS
;
977 RxCancelNotifyChangeDirectoryRequestsForFobx(
983 LIST_ENTRY ContextsToCancel
;
985 /* Init a list for the contexts to cancel */
986 InitializeListHead(&ContextsToCancel
);
988 /* Lock our list lock */
989 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
991 /* Now, browse all the active contexts, to find the associated ones */
992 Entry
= RxActiveContexts
.Flink
;
993 while (Entry
!= &RxActiveContexts
)
995 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
996 Entry
= Entry
->Flink
;
998 /* Not the IRP we're looking for, ignore */
999 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1000 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1005 /* Not the FOBX we're looking for, ignore */
1006 if ((PFOBX
)Context
->pFobx
!= Fobx
)
1011 /* No cancel routine (can't be cancel, then), ignore */
1012 if (Context
->MRxCancelRoutine
== NULL
)
1017 /* Mark our context as cancelled */
1018 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1020 /* Move it to our list */
1021 RemoveEntryList(&Context
->ContextListEntry
);
1022 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1024 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1027 /* Done with the contexts */
1028 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1030 /* Now, handle all our "extracted" contexts */
1031 while (!IsListEmpty(&ContextsToCancel
))
1033 Entry
= RemoveHeadList(&ContextsToCancel
);
1034 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1036 /* If they had an associated IRP (should be always true) */
1037 if (Context
->CurrentIrp
!= NULL
)
1039 /* Then, call cancel routine */
1040 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1041 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1042 Context
->MRxCancelRoutine(Context
);
1045 /* And delete the context */
1046 RxDereferenceAndDeleteRxContext(Context
);
1054 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1055 PV_NET_ROOT VNetRoot
,
1056 BOOLEAN ForceFilesClosed
)
1061 PRX_CONTEXT Context
;
1062 LIST_ENTRY ContextsToCancel
;
1064 /* Init a list for the contexts to cancel */
1065 InitializeListHead(&ContextsToCancel
);
1067 /* Lock our list lock */
1068 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1070 /* Now, browse all the active contexts, to find the associated ones */
1071 Entry
= RxActiveContexts
.Flink
;
1072 while (Entry
!= &RxActiveContexts
)
1074 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1075 Entry
= Entry
->Flink
;
1077 /* Not the IRP we're looking for, ignore */
1078 if (Context
->MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
||
1079 Context
->MinorFunction
!= IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
1084 /* Not the VNetRoot we're looking for, ignore */
1085 if (Context
->pFcb
== NULL
||
1086 (PV_NET_ROOT
)Context
->NotifyChangeDirectory
.pVNetRoot
!= VNetRoot
)
1091 /* No cancel routine (can't be cancel, then), ignore */
1092 if (Context
->MRxCancelRoutine
== NULL
)
1097 /* At that point, we found a matching context
1098 * If we're not asked to force close, then fail - it's still open
1100 if (!ForceFilesClosed
)
1102 Status
= STATUS_FILES_OPEN
;
1106 /* Mark our context as cancelled */
1107 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
);
1109 /* Move it to our list */
1110 RemoveEntryList(&Context
->ContextListEntry
);
1111 InsertTailList(&ContextsToCancel
, &Context
->ContextListEntry
);
1113 InterlockedIncrement((volatile long *)&Context
->ReferenceCount
);
1116 /* Done with the contexts */
1117 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1119 if (Status
!= STATUS_SUCCESS
)
1124 /* Now, handle all our "extracted" contexts */
1125 while (!IsListEmpty(&ContextsToCancel
))
1127 Entry
= RemoveHeadList(&ContextsToCancel
);
1128 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, ContextListEntry
);
1130 /* If they had an associated IRP (should be always true) */
1131 if (Context
->CurrentIrp
!= NULL
)
1133 /* Then, call cancel routine */
1134 ASSERT(Context
->MRxCancelRoutine
!= NULL
);
1135 DPRINT1("Canceling %p with %p\n", Context
, Context
->MRxCancelRoutine
);
1136 Context
->MRxCancelRoutine(Context
);
1139 /* And delete the context */
1140 RxDereferenceAndDeleteRxContext(Context
);
1149 PDEVICE_OBJECT DeviceObject
,
1159 RxCanonicalizeFileNameByServerSpecs(
1160 PRX_CONTEXT RxContext
,
1161 PUNICODE_STRING NetRootName
)
1163 USHORT NextChar
, CurChar
;
1168 /* Validate file name is not empty */
1169 MaxChars
= NetRootName
->Length
/ sizeof(WCHAR
);
1172 return STATUS_MORE_PROCESSING_REQUIRED
;
1175 /* Validate name is correct */
1176 for (NextChar
= 0, CurChar
= 0; CurChar
+ 1 < MaxChars
; NextChar
= CurChar
+ 1)
1180 for (i
= NextChar
+ 1; i
< MaxChars
; ++i
)
1182 if (NetRootName
->Buffer
[i
] == '\\' || NetRootName
->Buffer
[i
] == ':')
1189 if (CurChar
== NextChar
)
1191 if (((NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':') || NextChar
== (MaxChars
- 1)) && NetRootName
->Buffer
[NextChar
] != '.')
1198 if (CurChar
>= MaxChars
- 1)
1203 if (NetRootName
->Buffer
[CurChar
+ 1] != ':')
1205 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1210 if (NetRootName
->Buffer
[1] != ':')
1212 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1218 if ((CurChar
- NextChar
) == 1)
1220 if (NetRootName
->Buffer
[NextChar
+ 2] != '.')
1225 if (NetRootName
->Buffer
[NextChar
] == '\\' || NetRootName
->Buffer
[NextChar
] == ':' || NetRootName
->Buffer
[NextChar
] == '.')
1227 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1232 if ((CurChar
- NextChar
) != 2 || (NetRootName
->Buffer
[NextChar
] != '\\' && NetRootName
->Buffer
[NextChar
] != ':')
1233 || NetRootName
->Buffer
[NextChar
+ 1] != '.')
1238 if (NetRootName
->Buffer
[NextChar
+ 2] == '.')
1240 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
1246 return STATUS_MORE_PROCESSING_REQUIRED
;
1250 RxCanonicalizeNameAndObtainNetRoot(
1251 PRX_CONTEXT RxContext
,
1252 PUNICODE_STRING FileName
,
1253 PUNICODE_STRING NetRootName
)
1256 NET_ROOT_TYPE NetRootType
;
1257 UNICODE_STRING CanonicalName
;
1261 NetRootType
= NET_ROOT_WILD
;
1263 RtlInitEmptyUnicodeString(NetRootName
, NULL
, 0);
1264 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
1266 /* if not relative opening, just handle the passed name */
1267 if (RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
== NULL
)
1269 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1270 if (!NT_SUCCESS(Status
))
1279 /* Make sure we have a valid FCB and a FOBX */
1280 Fcb
= RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext
;
1282 RxContext
->CurrentIrpSp
->FileObject
->RelatedFileObject
->FsContext2
== NULL
)
1284 return STATUS_INVALID_PARAMETER
;
1287 if (!NodeTypeIsFcb(Fcb
))
1289 return STATUS_INVALID_PARAMETER
;
1295 /* Get/Create the associated VNetRoot for opening */
1296 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1297 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
&&
1298 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_MAILSLOT_REPARSE
))
1300 ASSERT(CanonicalName
.Buffer
== RxContext
->Create
.CanonicalNameBuffer
);
1302 RxFreeCanonicalNameBuffer(RxContext
);
1303 Status
= RxFirstCanonicalize(RxContext
, FileName
, &CanonicalName
, &NetRootType
);
1304 if (NT_SUCCESS(Status
))
1306 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, NetRootName
);
1310 /* Filename cannot contain wildcards */
1311 if (FsRtlDoesNameContainWildCards(NetRootName
))
1313 Status
= STATUS_OBJECT_NAME_INVALID
;
1316 /* Make sure file name is correct */
1317 if (NT_SUCCESS(Status
))
1319 Status
= RxCanonicalizeFileNameByServerSpecs(RxContext
, NetRootName
);
1322 /* Give the mini-redirector a chance to prepare the name */
1323 if (NT_SUCCESS(Status
) || Status
== STATUS_MORE_PROCESSING_REQUIRED
)
1325 if (RxContext
->Create
.pNetRoot
!= NULL
)
1327 NTSTATUS IgnoredStatus
;
1329 MINIRDR_CALL(IgnoredStatus
, RxContext
, RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
1330 MRxPreparseName
, (RxContext
, NetRootName
));
1331 (void)IgnoredStatus
;
1340 RxCheckFcbStructuresForAlignment(
1348 _In_ ACCESS_MASK DesiredAccess
,
1349 _In_ ULONG DesiredShareAccess
,
1350 _Inout_ PFILE_OBJECT FileObject
,
1351 _Inout_ PSHARE_ACCESS ShareAccess
,
1352 _In_ BOOLEAN Update
,
1354 _In_ PSZ wherelogtag
)
1358 RxDumpWantedAccess(where
, "", wherelogtag
, DesiredAccess
, DesiredShareAccess
);
1359 RxDumpCurrentAccess(where
, "", wherelogtag
, ShareAccess
);
1361 return IoCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
, Update
);
1368 RxCheckShareAccessPerSrvOpens(
1370 IN ACCESS_MASK DesiredAccess
,
1371 IN ULONG DesiredShareAccess
)
1374 BOOLEAN WriteAccess
;
1375 BOOLEAN DeleteAccess
;
1376 PSHARE_ACCESS ShareAccess
;
1380 ShareAccess
= &Fcb
->ShareAccessPerSrvOpens
;
1382 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess
, DesiredShareAccess
);
1383 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess
);
1385 /* Check if any access wanted */
1386 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
1387 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
1388 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
1390 if (ReadAccess
|| WriteAccess
|| DeleteAccess
)
1392 BOOLEAN SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
1393 BOOLEAN SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
1394 BOOLEAN SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
1396 /* Check whether there's a violation */
1398 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
1400 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
1402 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
1403 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
1404 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
1405 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
1407 return STATUS_SHARING_VIOLATION
;
1411 return STATUS_SUCCESS
;
1415 RxCleanupPipeQueues(
1416 PRX_CONTEXT Context
)
1425 RxCloseAssociatedSrvOpen(
1427 IN PRX_CONTEXT RxContext OPTIONAL
)
1432 BOOLEAN CloseSrvOpen
;
1433 PRX_CONTEXT LocalContext
;
1437 /* Assume SRV_OPEN is already closed */
1438 CloseSrvOpen
= FALSE
;
1439 /* If we have a FOBX, we'll have to close it */
1442 /* If the FOBX isn't closed yet */
1443 if (!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
1445 SrvOpen
= Fobx
->SrvOpen
;
1446 Fcb
= (PFCB
)SrvOpen
->pFcb
;
1447 /* Check whether we've to close SRV_OPEN first */
1448 if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1450 CloseSrvOpen
= TRUE
;
1454 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1456 /* Not much to do */
1457 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1459 if (SrvOpen
->OpenCount
> 0)
1461 --SrvOpen
->OpenCount
;
1466 /* No need to close SRV_OPEN, so close FOBX */
1469 RxMarkFobxOnClose(Fobx
);
1471 return STATUS_SUCCESS
;
1476 /* No FOBX? No RX_CONTEXT, ok, job done! */
1477 if (RxContext
== NULL
)
1479 return STATUS_SUCCESS
;
1482 /* Get the FCB from RX_CONTEXT */
1483 Fcb
= (PFCB
)RxContext
->pFcb
;
1487 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1488 if (RxContext
== NULL
)
1490 ASSERT(Fobx
!= NULL
);
1492 LocalContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
1493 if (LocalContext
== NULL
)
1495 return STATUS_INSUFFICIENT_RESOURCES
;
1498 LocalContext
->MajorFunction
= 2;
1499 LocalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1500 LocalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
1501 LocalContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)Fobx
->SrvOpen
;
1505 LocalContext
= RxContext
;
1508 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1510 /* Now, close the FOBX */
1513 RxMarkFobxOnClose(Fobx
);
1517 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
1520 /* If not a "standard" file, SRV_OPEN can be null */
1521 if (SrvOpen
== NULL
)
1523 ASSERT((NodeType(Fcb
) == RDBSS_NTC_OPENTARGETDIR_FCB
) || (NodeType(Fcb
) == RDBSS_NTC_IPC_SHARE
) || (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
));
1524 RxDereferenceNetFcb(Fcb
);
1526 if (LocalContext
!= RxContext
)
1528 RxDereferenceAndDeleteRxContext(LocalContext
);
1531 return STATUS_SUCCESS
;
1534 /* If SRV_OPEN isn't in a good condition, nothing to close */
1535 if (SrvOpen
->Condition
!= Condition_Good
)
1537 if (LocalContext
!= RxContext
)
1539 RxDereferenceAndDeleteRxContext(LocalContext
);
1542 return STATUS_SUCCESS
;
1545 /* Decrease open count */
1546 if (SrvOpen
->OpenCount
> 0)
1548 --SrvOpen
->OpenCount
;
1551 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1552 if (SrvOpen
->OpenCount
== 1)
1554 if (!IsListEmpty(&SrvOpen
->FobxList
))
1556 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
)->ScavengerFinalizationList
))
1558 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
1563 /* Nothing left, purge FCB */
1564 if (SrvOpen
->OpenCount
== 0 && RxContext
== NULL
)
1566 RxPurgeNetFcb(Fcb
, LocalContext
);
1569 /* Already closed? Job done! */
1570 SrvOpen
= Fobx
->SrvOpen
;
1571 if (SrvOpen
== NULL
||
1572 (SrvOpen
->OpenCount
!= 0 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
)) ||
1573 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
1575 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1576 if (LocalContext
!= RxContext
)
1578 RxDereferenceAndDeleteRxContext(LocalContext
);
1581 return STATUS_SUCCESS
;
1584 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1586 /* Inform mini-rdr about closing */
1587 MINIRDR_CALL(Status
, LocalContext
, Fcb
->MRxDispatch
, MRxCloseSrvOpen
, (LocalContext
));
1588 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1589 Status
, RxContext
, Fobx
, Fcb
, SrvOpen
);
1591 /* And mark as such */
1592 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
);
1593 SrvOpen
->Key
= (PVOID
)-1;
1595 /* If we were delayed, we're not! */
1596 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
1598 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
1602 RxRemoveShareAccessPerSrvOpens(SrvOpen
);
1603 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
1606 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1608 /* Mark the FOBX closed as well */
1609 SetFlag(Fobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
);
1611 if (LocalContext
!= RxContext
)
1613 RxDereferenceAndDeleteRxContext(LocalContext
);
1623 RxCollapseOrCreateSrvOpen(
1624 PRX_CONTEXT RxContext
)
1631 PIO_STACK_LOCATION Stack
;
1632 ACCESS_MASK DesiredAccess
;
1633 RX_BLOCK_CONDITION FcbCondition
;
1637 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext
);
1639 Fcb
= (PFCB
)RxContext
->pFcb
;
1640 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1641 ++Fcb
->UncleanCount
;
1643 Stack
= RxContext
->CurrentIrpSp
;
1644 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
1645 ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
1647 Disposition
= RxContext
->Create
.NtCreateParameters
.Disposition
;
1649 /* Try to find a reusable SRV_OPEN */
1650 Status
= RxSearchForCollapsibleOpen(RxContext
, DesiredAccess
, ShareAccess
);
1651 if (Status
== STATUS_NOT_FOUND
)
1653 /* If none found, create one */
1654 SrvOpen
= RxCreateSrvOpen((PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
, Fcb
);
1655 if (SrvOpen
== NULL
)
1657 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1661 SrvOpen
->DesiredAccess
= DesiredAccess
;
1662 SrvOpen
->ShareAccess
= ShareAccess
;
1663 Status
= STATUS_SUCCESS
;
1666 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
1668 if (Status
!= STATUS_SUCCESS
)
1670 FcbCondition
= Condition_Bad
;
1674 RxInitiateSrvOpenKeyAssociation(SrvOpen
);
1676 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1677 RxContext
->CurrentIrp
->IoStatus
.Information
= 0xABCDEF;
1678 /* Inform the mini-rdr we're handling a create */
1679 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCreate
, (RxContext
));
1680 ASSERT(RxContext
->CurrentIrp
->IoStatus
.Information
== 0xABCDEF);
1682 DPRINT("MRxCreate returned: %x\n", Status
);
1683 if (Status
== STATUS_SUCCESS
)
1685 /* In case of overwrite, reset file size */
1686 if (Disposition
== FILE_OVERWRITE
|| Disposition
== FILE_OVERWRITE_IF
)
1688 RxAcquirePagingIoResource(RxContext
, Fcb
);
1689 Fcb
->Header
.AllocationSize
.QuadPart
= 0LL;
1690 Fcb
->Header
.FileSize
.QuadPart
= 0LL;
1691 Fcb
->Header
.ValidDataLength
.QuadPart
= 0LL;
1692 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1693 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1694 RxReleasePagingIoResource(RxContext
, Fcb
);
1698 /* Otherwise, adjust sizes */
1699 RxContext
->CurrentIrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
1700 if (CcIsFileCached(RxContext
->CurrentIrpSp
->FileObject
))
1702 RxAdjustAllocationSizeforCC(Fcb
);
1704 CcSetFileSizes(RxContext
->CurrentIrpSp
->FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1708 /* Set the IoStatus with information returned by mini-rdr */
1709 RxContext
->CurrentIrp
->IoStatus
.Information
= RxContext
->Create
.ReturnedCreateInformation
;
1711 SrvOpen
->OpenStatus
= Status
;
1712 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1713 RxTransitionSrvOpen(SrvOpen
, (Status
== STATUS_SUCCESS
? Condition_Good
: Condition_Bad
));
1715 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1717 RxCompleteSrvOpenKeyAssociation(SrvOpen
);
1719 if (Status
== STATUS_SUCCESS
)
1721 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
1723 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
1725 SrvOpen
->CreateOptions
= RxContext
->Create
.NtCreateParameters
.CreateOptions
;
1726 FcbCondition
= Condition_Good
;
1730 FcbCondition
= Condition_Bad
;
1731 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1732 RxContext
->pRelevantSrvOpen
= NULL
;
1734 if (RxContext
->pFobx
!= NULL
)
1736 RxDereferenceNetFobx(RxContext
->pFobx
, LHS_ExclusiveLockHeld
);
1737 RxContext
->pFobx
= NULL
;
1742 /* Set FCB state - good or bad - depending on whether create succeed */
1743 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb
, Fcb
->Condition
);
1744 RxTransitionNetFcb(Fcb
, FcbCondition
);
1746 else if (Status
== STATUS_SUCCESS
)
1748 BOOLEAN IsGood
, ExtraOpen
;
1750 /* A reusable SRV_OPEN was found */
1751 RxContext
->CurrentIrp
->IoStatus
.Information
= FILE_OPENED
;
1754 SrvOpen
= (PSRV_OPEN
)RxContext
->pRelevantSrvOpen
;
1756 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1757 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1758 if (!StableCondition(SrvOpen
->Condition
))
1760 RxReferenceSrvOpen(SrvOpen
);
1761 ++SrvOpen
->OpenCount
;
1764 RxReleaseFcb(RxContext
, Fcb
);
1765 RxContext
->Create
.FcbAcquired
= FALSE
;
1767 RxWaitForStableSrvOpen(SrvOpen
, RxContext
);
1769 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext
, Fcb
)))
1771 RxContext
->Create
.FcbAcquired
= TRUE
;
1774 IsGood
= (SrvOpen
->Condition
== Condition_Good
);
1777 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1780 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxCollapseOpen
, (RxContext
));
1782 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1786 Status
= SrvOpen
->OpenStatus
;
1791 --SrvOpen
->OpenCount
;
1792 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
1796 --Fcb
->UncleanCount
;
1798 DPRINT("Status: %x\n", Status
);
1808 PRX_CONTEXT Context
)
1810 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1816 PFILE_OBJECT FileObject
;
1817 LARGE_INTEGER TruncateSize
;
1818 PLARGE_INTEGER TruncateSizePtr
;
1819 BOOLEAN NeedPurge
, FcbTableAcquired
, OneLeft
, IsFile
, FcbAcquired
, LeftForDelete
;
1823 Fcb
= (PFCB
)Context
->pFcb
;
1824 Fobx
= (PFOBX
)Context
->pFobx
;
1825 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context
, Fobx
, Fcb
);
1827 /* File system closing, it's OK */
1830 if (Fcb
->UncleanCount
> 0)
1832 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1835 return STATUS_SUCCESS
;
1838 /* Check we have a correct FCB type */
1839 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&&
1840 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
1841 NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
1842 NodeType(Fcb
) != RDBSS_NTC_SPOOLFILE
)
1844 DPRINT1("Invalid Fcb type for %p\n", Fcb
);
1845 RxBugCheck(Fcb
->Header
.NodeTypeCode
, 0, 0);
1848 FileObject
= Context
->CurrentIrpSp
->FileObject
;
1849 ASSERT(!BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
));
1851 RxMarkFobxOnCleanup(Fobx
, &NeedPurge
);
1853 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1854 if (!NT_SUCCESS(Status
))
1861 Fobx
->AssociatedFileObject
= NULL
;
1863 /* In case SRV_OPEN used is part of FCB */
1864 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
))
1866 ASSERT(Fcb
->UncleanCount
!= 0);
1867 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
1869 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
1871 --Fcb
->UncachedUncleanCount
;
1874 /* Inform mini-rdr */
1875 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
1877 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
1878 --Fobx
->SrvOpen
->UncleanFobxCount
;
1880 RxUninitializeCacheMap(Context
, FileObject
, NULL
);
1882 RxReleaseFcb(Context
, Fcb
);
1884 return STATUS_SUCCESS
;
1887 /* Report the fact that file could be set as delete on close */
1888 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
1890 SetFlag(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1893 /* Cancel any pending notification */
1894 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx
);
1896 /* Backup open count before we start playing with it */
1897 OpenCount
= Fcb
->ShareAccess
.OpenCount
;
1899 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
1900 FcbTableAcquired
= FALSE
;
1901 LeftForDelete
= FALSE
;
1902 OneLeft
= (Fcb
->UncleanCount
== 1);
1906 /* Unclean count and delete on close? Verify whether we're the one */
1907 if (OneLeft
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
1909 if (RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
1911 FcbTableAcquired
= TRUE
;
1915 RxReleaseFcb(Context
, Fcb
);
1917 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
1919 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
1920 if (Status
!= STATUS_SUCCESS
)
1922 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1926 FcbTableAcquired
= TRUE
;
1929 /* That means we'll perform the delete on close! */
1930 if (Fcb
->UncleanCount
== 1)
1932 LeftForDelete
= TRUE
;
1936 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
1937 FcbTableAcquired
= FALSE
;
1942 TruncateSizePtr
= NULL
;
1943 /* Handle cleanup for pipes and printers */
1944 if (NetRoot
->Type
== NET_ROOT_PIPE
|| NetRoot
->Type
== NET_ROOT_PRINT
)
1946 RxCleanupPipeQueues(Context
);
1948 /* Handle cleanup for files */
1949 else if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
1951 Context
->LowIoContext
.Flags
|= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS
;
1952 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
1955 FsRtlFastUnlockAll(&Fcb
->Specific
.Fcb
.FileLock
, FileObject
, RxGetRequestorProcess(Context
), Context
);
1957 /* If there are still locks to release, proceed */
1958 if (Context
->LowIoContext
.ParamsFor
.Locks
.LockList
!= NULL
)
1960 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_UNLOCK_MULTIPLE
);
1961 Context
->LowIoContext
.ParamsFor
.Locks
.Flags
= 0;
1962 Status
= RxLowIoLockControlShell(Context
);
1965 /* Fix times and size */
1966 RxAdjustFileTimesAndSize(Context
);
1968 /* If we're the only one left... */
1971 /* And if we're supposed to delete on close */
1974 /* Update the sizes */
1975 RxAcquirePagingIoResource(Context
, Fcb
);
1976 Fcb
->Header
.FileSize
.QuadPart
= 0;
1977 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1978 RxReleasePagingIoResource(Context
, Fcb
);
1980 /* Otherwise, call the mini-rdr to adjust sizes */
1983 /* File got grown up, fill with zeroes */
1984 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
1985 (Fcb
->Header
.ValidDataLength
.QuadPart
< Fcb
->Header
.FileSize
.QuadPart
))
1987 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxZeroExtend
, (Context
));
1988 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1991 /* File was truncated, let mini-rdr proceed */
1992 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
))
1994 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxTruncate
, (Context
));
1995 ClearFlag(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
);
1997 /* Keep track of file change for Cc uninit */
1998 TruncateSize
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1999 TruncateSizePtr
= &TruncateSize
;
2004 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2012 /* Otherwise, try to see whether we can purge */
2015 NeedPurge
= (OneLeft
&& (LeftForDelete
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
)));
2022 /* We have to still be there! */
2023 ASSERT(Fcb
->UncleanCount
!= 0);
2024 InterlockedDecrement((volatile long *)&Fcb
->UncleanCount
);
2026 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2028 --Fcb
->UncachedUncleanCount
;
2031 /* Inform mini-rdr about ongoing cleanup */
2032 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxCleanupFobx
, (Context
));
2034 ASSERT(Fobx
->SrvOpen
->UncleanFobxCount
!= 0);
2035 --Fobx
->SrvOpen
->UncleanFobxCount
;
2038 if (DisableFlushOnCleanup
)
2040 /* Only if we're the last standing */
2041 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
&&
2042 Fcb
->UncleanCount
== Fcb
->UncachedUncleanCount
)
2044 DPRINT("Flushing %p due to last cached handle cleanup\n", Context
);
2045 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2051 if (Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2053 DPRINT("Flushing %p on cleanup\n", Context
);
2054 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2058 /* If only remaining uncached & unclean, then flush and purge */
2059 if (!BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
2061 if (Fcb
->UncachedUncleanCount
!= 0)
2063 if (Fcb
->UncachedUncleanCount
== Fcb
->UncleanCount
&&
2064 Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
2066 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2067 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
2072 /* If purge required, and not about to delete, flush */
2073 if (!LeftForDelete
&& NeedPurge
)
2075 DPRINT("Flushing FCB in system cache for %p\n", Context
);
2076 RxFlushFcbInSystemCache(Fcb
, TRUE
);
2079 /* If it was a file, drop cache */
2082 DPRINT("Uninit cache map for file\n");
2083 RxUninitializeCacheMap(Context
, FileObject
, TruncateSizePtr
);
2086 /* If that's the one left for deletion, or if it needs purge, flush */
2087 if (LeftForDelete
|| NeedPurge
)
2089 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, !LeftForDelete
);
2090 /* If that's for deletion, also remove from FCB table */
2093 RxRemoveNameNetFcb(Fcb
);
2094 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2095 FcbTableAcquired
= FALSE
;
2099 /* Remove any share access */
2100 if (OpenCount
!= 0 && NetRoot
->Type
== NET_ROOT_DISK
)
2102 RxRemoveShareAccess(FileObject
, &Fcb
->ShareAccess
, "Cleanup the share access", "ClnUpShr");
2105 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2106 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
&& BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
) &&
2107 RxWriteCacheingAllowed(Fcb
, Fobx
->pSrvOpen
))
2109 NTSTATUS InternalStatus
;
2110 PRX_CONTEXT InternalContext
;
2112 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2113 InternalStatus
= STATUS_UNSUCCESSFUL
;
2114 InternalContext
= RxCreateRxContext(Context
->CurrentIrp
,
2115 Fcb
->RxDeviceObject
,
2116 RX_CONTEXT_FLAG_WAIT
| RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
);
2117 if (InternalContext
!= NULL
)
2119 FILE_END_OF_FILE_INFORMATION FileEOF
;
2121 InternalStatus
= STATUS_SUCCESS
;
2123 /* Initialize the context for file information set */
2124 InternalContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2125 InternalContext
->pFobx
= (PMRX_FOBX
)Fobx
;
2126 InternalContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
2128 /* Get EOF from the FCB */
2129 FileEOF
.EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
2130 InternalContext
->Info
.FileInformationClass
= FileEndOfFileInformation
;
2131 InternalContext
->Info
.Buffer
= &FileEOF
;
2132 InternalContext
->Info
.Length
= sizeof(FileEOF
);
2134 /* Call the mini-rdr */
2135 MINIRDR_CALL_THROUGH(InternalStatus
, Fcb
->MRxDispatch
, MRxSetFileInfo
, (InternalContext
));
2138 RxDereferenceAndDeleteRxContext(InternalContext
);
2141 /* We tried, so, clean the FOBX flag */
2142 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
2143 /* If it failed, then, disable collapsing on the FCB */
2144 if (!NT_SUCCESS(InternalStatus
))
2146 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2151 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
2153 FcbAcquired
= FALSE
;
2154 RxReleaseFcb(Context
, Fcb
);
2160 RxReleaseFcb(Context
, Fcb
);
2163 if (FcbTableAcquired
)
2165 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2171 #undef BugCheckFileId
2177 PRX_CONTEXT Context
)
2179 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2183 PFILE_OBJECT FileObject
;
2184 BOOLEAN DereferenceFobx
, AcquiredFcb
;
2188 Fcb
= (PFCB
)Context
->pFcb
;
2189 Fobx
= (PFOBX
)Context
->pFobx
;
2190 FileObject
= Context
->CurrentIrpSp
->FileObject
;
2191 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context
, Fobx
, Fcb
, FileObject
);
2193 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2194 if (!NT_SUCCESS(Status
))
2204 /* Check our FCB type is expected */
2205 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2206 (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
|| (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
&&
2207 (NodeType(Fcb
) < RDBSS_NTC_SPOOLFILE
|| NodeType(Fcb
) > RDBSS_NTC_OPENTARGETDIR_FCB
))))
2209 RxBugCheck(NodeType(Fcb
), 0, 0);
2212 RxReferenceNetFcb(Fcb
);
2214 DereferenceFobx
= FALSE
;
2215 /* If we're not closing FS */
2221 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
2222 SrvCall
= (PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
;
2223 /* Handle delayed close */
2224 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2226 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
| FCB_STATE_ORPHANED
))
2228 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
))
2230 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx
, SrvOpen
);
2232 if (SrvOpen
->OpenCount
== 1 && !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_COLLAPSING_DISABLED
))
2234 if (InterlockedIncrement(&SrvCall
->NumberOfCloseDelayedFiles
) >= SrvCall
->MaximumNumberOfCloseDelayedFiles
)
2236 InterlockedDecrement(&SrvCall
->NumberOfCloseDelayedFiles
);
2240 DereferenceFobx
= TRUE
;
2241 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
2248 /* If we reach maximum of delayed close/or if there are no delayed close */
2249 if (!DereferenceFobx
)
2253 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
2254 if (NetRoot
->Type
!= NET_ROOT_PRINT
)
2256 /* Delete if asked */
2257 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
))
2259 RxScavengeRelatedFobxs(Fcb
);
2260 RxSynchronizeWithScavenger(Context
);
2262 RxReleaseFcb(Context
, Fcb
);
2264 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2265 RxOrphanThisFcb(Fcb
);
2266 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2268 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2269 ASSERT(NT_SUCCESS(Status
));
2274 RxMarkFobxOnClose(Fobx
);
2277 if (DereferenceFobx
)
2279 ASSERT(Fobx
!= NULL
);
2280 RxDereferenceNetFobx(Fobx
, LHS_SharedLockHeld
);
2284 RxCloseAssociatedSrvOpen(Fobx
, Context
);
2287 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
2291 Freed
= RxDereferenceAndFinalizeNetFcb(Fcb
, Context
, FALSE
, FALSE
);
2292 AcquiredFcb
= !Freed
;
2294 FileObject
->FsContext
= (PVOID
)-1;
2298 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
2302 RxReleaseFcb(Context
, Fcb
);
2303 AcquiredFcb
= FALSE
;
2308 if (_SEH2_AbnormalTermination())
2312 RxReleaseFcb(Context
, Fcb
);
2317 ASSERT(!AcquiredFcb
);
2322 DPRINT("Status: %x\n", Status
);
2324 #undef BugCheckFileId
2333 PRX_CONTEXT Context
)
2337 PFILE_OBJECT FileObject
;
2338 PIO_STACK_LOCATION Stack
;
2342 DPRINT("RxCommonCreate(%p)\n", Context
);
2344 Irp
= Context
->CurrentIrp
;
2345 Stack
= Context
->CurrentIrpSp
;
2346 FileObject
= Stack
->FileObject
;
2348 /* Check whether that's a device opening */
2349 if (FileObject
->FileName
.Length
== 0 && FileObject
->RelatedFileObject
== NULL
)
2351 FileObject
->FsContext
= &RxDeviceFCB
;
2352 FileObject
->FsContext2
= NULL
;
2354 ++RxDeviceFCB
.NodeReferenceCount
;
2355 ++RxDeviceFCB
.OpenCount
;
2357 Irp
->IoStatus
.Information
= FILE_OPENED
;
2358 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject
, Context
->RxDeviceObject
, &Context
->RxDeviceObject
->DeviceName
);
2360 Status
= STATUS_SUCCESS
;
2364 PFCB RelatedFcb
= NULL
;
2366 /* Make sure caller is consistent */
2367 if (FlagOn(Stack
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
) ==
2368 (FILE_DIRECTORY_FILE
| FILE_NON_DIRECTORY_FILE
| FILE_OPEN_REMOTE_INSTANCE
))
2370 DPRINT1("Create.Options: %x\n", Stack
->Parameters
.Create
.Options
);
2371 return STATUS_INVALID_PARAMETER
;
2374 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2375 Context
, FileObject
, Stack
->Parameters
.Create
.Options
, Stack
->Flags
, Stack
->Parameters
.Create
.FileAttributes
,
2376 Stack
->Parameters
.Create
.ShareAccess
, Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2377 DPRINT("FileName: %wZ\n", &FileObject
->FileName
);
2379 if (FileObject
->RelatedFileObject
!= NULL
)
2381 RelatedFcb
= FileObject
->RelatedFileObject
->FsContext
;
2382 DPRINT("Rel FO: %p, path: %wZ\n", FileObject
->RelatedFileObject
, RelatedFcb
->FcbTableEntry
.Path
);
2385 /* Going to rename? */
2386 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
2388 DPRINT("TargetDir!\n");
2391 /* Copy create parameters to the context */
2392 RxCopyCreateParameters(Context
);
2394 /* If the caller wants to establish a connection, go ahead */
2395 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2397 Status
= RxCreateTreeConnect(Context
);
2401 /* Validate file name */
2402 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2403 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2404 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2406 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2407 RtlMoveMemory(&FileObject
->FileName
.Buffer
[0], &FileObject
->FileName
.Buffer
[1],
2408 FileObject
->FileName
.Length
);
2410 if (FileObject
->FileName
.Length
> sizeof(WCHAR
) &&
2411 FileObject
->FileName
.Buffer
[1] == OBJ_NAME_PATH_SEPARATOR
&&
2412 FileObject
->FileName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2414 return STATUS_OBJECT_NAME_INVALID
;
2418 /* Attempt to open the file */
2421 UNICODE_STRING NetRootName
;
2423 /* Strip last \ if required */
2424 if (FileObject
->FileName
.Length
!= 0 &&
2425 FileObject
->FileName
.Buffer
[FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
2427 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
))
2429 return STATUS_OBJECT_NAME_INVALID
;
2432 FileObject
->FileName
.Length
-= sizeof(WCHAR
);
2433 Context
->Create
.Flags
|= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
;
2436 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
))
2438 FileObject
->Flags
|= FO_WRITE_THROUGH
;
2441 /* Get the associated net root to opening */
2442 Status
= RxCanonicalizeNameAndObtainNetRoot(Context
, &FileObject
->FileName
, &NetRootName
);
2443 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2448 /* And attempt to open */
2449 Status
= RxCreateFromNetRoot(Context
, &NetRootName
);
2450 if (Status
== STATUS_SHARING_VIOLATION
)
2452 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2454 /* If that happens for file creation, fail for real */
2455 if (Context
->Create
.NtCreateParameters
.Disposition
== FILE_CREATE
)
2457 Status
= STATUS_OBJECT_NAME_COLLISION
;
2461 /* Otherwise, if possible, attempt to scavenger current FOBX
2462 * to check whether a dormant FOBX is the reason for sharing violation
2464 if (Context
->Create
.TryForScavengingOnSharingViolation
&&
2465 !Context
->Create
.ScavengingAlreadyTried
)
2467 /* Only doable with a VNetRoot */
2468 if (Context
->Create
.pVNetRoot
!= NULL
)
2470 PV_NET_ROOT VNetRoot
;
2471 NT_CREATE_PARAMETERS SavedParameters
;
2473 /* Save create parameters */
2474 RtlCopyMemory(&SavedParameters
, &Context
->Create
.NtCreateParameters
, sizeof(NT_CREATE_PARAMETERS
));
2476 /* Reference the VNetRoot for the scavenging time */
2477 VNetRoot
= (PV_NET_ROOT
)Context
->Create
.pVNetRoot
;
2478 RxReferenceVNetRoot(VNetRoot
);
2480 /* Prepare the RX_CONTEXT for reuse */
2481 RxpPrepareCreateContextForReuse(Context
);
2482 RxReinitializeContext(Context
);
2484 /* Copy what we saved */
2485 RtlCopyMemory(&Context
->Create
.NtCreateParameters
, &SavedParameters
, sizeof(NT_CREATE_PARAMETERS
));
2487 /* And recopy what can be */
2488 RxCopyCreateParameters(Context
);
2490 /* And start purging, then scavenging FOBX */
2491 RxPurgeRelatedFobxs((PNET_ROOT
)VNetRoot
->pNetRoot
, Context
,
2492 DONT_ATTEMPT_FINALIZE_ON_PURGE
, NULL
);
2493 RxScavengeFobxsForNetRoot((PNET_ROOT
)VNetRoot
->pNetRoot
,
2496 /* Ask for a second round */
2497 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2499 /* Keep track we already scavenged */
2500 Context
->Create
.ScavengingAlreadyTried
= TRUE
;
2502 /* Reference our SRV_CALL for CBS handling */
2503 RxReferenceSrvCall(VNetRoot
->pNetRoot
->pSrvCall
);
2504 RxpProcessChangeBufferingStateRequests((PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
, FALSE
);
2506 /* Drop our extra reference */
2507 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2512 else if (Status
== STATUS_REPARSE
)
2514 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2518 ASSERT(!BooleanFlagOn(Context
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_REPARSE
));
2521 while (Status
== STATUS_MORE_PROCESSING_REQUIRED
);
2524 if (Status
== STATUS_RETRY
)
2526 RxpPrepareCreateContextForReuse(Context
);
2528 ASSERT(Status
!= STATUS_PENDING
);
2531 DPRINT("Status: %lx\n", Status
);
2540 RxCommonDevFCBCleanup(
2541 PRX_CONTEXT Context
)
2548 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context
);
2550 Fcb
= Context
->pFcb
;
2551 Status
= STATUS_SUCCESS
;
2552 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2554 /* Our FOBX if set, has to be a VNetRoot */
2555 if (Context
->pFobx
!= NULL
)
2557 RxAcquirePrefixTableLockShared(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2558 if (Context
->pFobx
->NodeTypeCode
!= RDBSS_NTC_V_NETROOT
)
2560 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2562 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2566 --Fcb
->UncleanCount
;
2577 RxCommonDevFCBClose(
2578 PRX_CONTEXT Context
)
2582 PMRX_V_NET_ROOT NetRoot
;
2586 DPRINT("RxCommonDevFCBClose(%p)\n", Context
);
2588 Fcb
= Context
->pFcb
;
2589 NetRoot
= (PMRX_V_NET_ROOT
)Context
->pFobx
;
2590 Status
= STATUS_SUCCESS
;
2591 ASSERT(NodeType(Fcb
) == RDBSS_NTC_DEVICE_FCB
);
2593 /* Our FOBX if set, has to be a VNetRoot */
2594 if (NetRoot
!= NULL
)
2596 RxAcquirePrefixTableLockExclusive(Context
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2597 if (NetRoot
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
2599 --NetRoot
->NumberOfOpens
;
2600 RxDereferenceVNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2604 Status
= STATUS_NOT_IMPLEMENTED
;
2606 RxReleasePrefixTableLock(Context
->RxDeviceObject
->pRxNetNameTable
);
2618 RxCommonDevFCBFsCtl(
2619 PRX_CONTEXT Context
)
2622 return STATUS_NOT_IMPLEMENTED
;
2630 RxCommonDevFCBIoCtl(
2631 PRX_CONTEXT Context
)
2637 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context
);
2639 if (Context
->pFobx
!= NULL
)
2641 return STATUS_INVALID_HANDLE
;
2644 /* Is that a prefix claim from MUP? */
2645 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2647 return RxPrefixClaim(Context
);
2650 /* Otherwise, pass through the mini-rdr */
2651 Status
= RxXXXControlFileCallthru(Context
);
2652 if (Status
!= STATUS_PENDING
)
2654 if (Context
->PostRequest
)
2656 Context
->ResumeRoutine
= RxCommonDevFCBIoCtl
;
2657 Status
= RxFsdPostRequest(Context
);
2661 DPRINT("Status: %lx\n", Status
);
2667 RxCommonDevFCBQueryVolInfo(
2668 PRX_CONTEXT Context
)
2671 return STATUS_NOT_IMPLEMENTED
;
2679 RxCommonDeviceControl(
2680 PRX_CONTEXT Context
)
2686 /* Prefix claim is only allowed for device, not files */
2687 if (Context
->CurrentIrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_REDIR_QUERY_PATH
)
2689 return STATUS_INVALID_DEVICE_REQUEST
;
2692 /* Submit to mini-rdr */
2693 RxInitializeLowIoContext(&Context
->LowIoContext
, LOWIO_OP_IOCTL
);
2694 Status
= RxLowIoSubmit(Context
, RxLowIoIoCtlShellCompletion
);
2695 if (Status
== STATUS_PENDING
)
2697 RxDereferenceAndDeleteRxContext_Real(Context
);
2708 RxCommonDirectoryControl(
2709 PRX_CONTEXT Context
)
2714 PIO_STACK_LOCATION Stack
;
2718 Fcb
= (PFCB
)Context
->pFcb
;
2719 Fobx
= (PFOBX
)Context
->pFobx
;
2720 Stack
= Context
->CurrentIrpSp
;
2721 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context
, Fobx
, Fcb
, Stack
->MinorFunction
);
2723 /* Call the appropriate helper */
2724 if (Stack
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
)
2726 Status
= RxQueryDirectory(Context
);
2728 else if (Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
2730 Status
= RxNotifyChangeDirectory(Context
);
2731 if (Status
== STATUS_PENDING
)
2733 RxDereferenceAndDeleteRxContext_Real(Context
);
2738 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2746 RxCommonDispatchProblem(
2747 PRX_CONTEXT Context
)
2750 return STATUS_NOT_IMPLEMENTED
;
2755 RxCommonFileSystemControl(
2756 PRX_CONTEXT Context
)
2760 PIO_STACK_LOCATION Stack
;
2764 Irp
= Context
->CurrentIrp
;
2765 Stack
= Context
->CurrentIrpSp
;
2766 ControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
2768 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context
, Irp
, Stack
->MinorFunction
, ControlCode
);
2771 return STATUS_NOT_IMPLEMENTED
;
2776 RxCommonFlushBuffers(
2777 PRX_CONTEXT Context
)
2780 return STATUS_NOT_IMPLEMENTED
;
2785 RxCommonLockControl(
2786 PRX_CONTEXT Context
)
2789 return STATUS_NOT_IMPLEMENTED
;
2795 PRX_CONTEXT Context
)
2798 return STATUS_NOT_IMPLEMENTED
;
2806 RxCommonQueryInformation(
2807 PRX_CONTEXT Context
)
2809 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2810 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2811 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2818 PIO_STACK_LOCATION Stack
;
2819 FILE_INFORMATION_CLASS FileInfoClass
;
2823 Fcb
= (PFCB
)Context
->pFcb
;
2824 Fobx
= (PFOBX
)Context
->pFobx
;
2825 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
2827 Irp
= Context
->CurrentIrp
;
2828 Stack
= Context
->CurrentIrpSp
;
2829 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp
->AssociatedIrp
.SystemBuffer
,
2830 Stack
->Parameters
.QueryFile
.Length
, Stack
->Parameters
.QueryFile
.FileInformationClass
);
2832 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2833 FileInfoClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
2840 /* Get a writable buffer */
2841 Buffer
= RxMapSystemBuffer(Context
);
2844 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2848 RtlZeroMemory(Buffer
, Context
->Info
.Length
);
2850 /* Validate file type */
2851 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN
)
2853 if (NodeType(Fcb
) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2855 Status
= STATUS_INVALID_PARAMETER
;
2858 else if (NodeType(Fcb
) > RDBSS_NTC_STORAGE_TYPE_FILE
)
2860 if (NodeType(Fcb
) == RDBSS_NTC_MAILSLOT
)
2862 Status
= STATUS_NOT_IMPLEMENTED
;
2866 Status
= STATUS_INVALID_PARAMETER
;
2873 /* Acquire the right lock */
2874 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) &&
2875 FileInfoClass
!= FileNameInformation
)
2877 if (FileInfoClass
== FileCompressionInformation
)
2879 Status
= RxAcquireExclusiveFcb(Context
, Fcb
);
2883 Status
= RxAcquireSharedFcb(Context
, Fcb
);
2886 if (Status
== STATUS_LOCK_NOT_GRANTED
)
2888 Status
= STATUS_PENDING
;
2891 else if (!NT_SUCCESS(Status
))
2899 /* Dispatch to the right helper */
2900 switch (FileInfoClass
)
2902 case FileBasicInformation
:
2903 Status
= RxQueryBasicInfo(Context
, Buffer
);
2906 case FileStandardInformation
:
2907 Status
= RxQueryStandardInfo(Context
, Buffer
);
2910 case FileInternalInformation
:
2911 Status
= RxQueryInternalInfo(Context
, Buffer
);
2914 case FileEaInformation
:
2915 Status
= RxQueryEaInfo(Context
, Buffer
);
2918 case FileNameInformation
:
2919 Status
= RxQueryNameInfo(Context
, Buffer
);
2922 case FileAllInformation
:
2923 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo
);
2924 if (!NT_SUCCESS(Status
))
2929 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
), RxQueryStandardInfo
);
2930 if (!NT_SUCCESS(Status
))
2935 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2936 sizeof(FILE_STANDARD_INFORMATION
), RxQueryInternalInfo
);
2937 if (!NT_SUCCESS(Status
))
2942 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2943 sizeof(FILE_STANDARD_INFORMATION
) +
2944 sizeof(FILE_INTERNAL_INFORMATION
), RxQueryEaInfo
);
2945 if (!NT_SUCCESS(Status
))
2950 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2951 sizeof(FILE_STANDARD_INFORMATION
) +
2952 sizeof(FILE_INTERNAL_INFORMATION
) +
2953 sizeof(FILE_EA_INFORMATION
), RxQueryPositionInfo
);
2954 if (!NT_SUCCESS(Status
))
2959 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION
) +
2960 sizeof(FILE_STANDARD_INFORMATION
) +
2961 sizeof(FILE_INTERNAL_INFORMATION
) +
2962 sizeof(FILE_EA_INFORMATION
) +
2963 sizeof(FILE_POSITION_INFORMATION
), RxQueryNameInfo
);
2966 case FileAlternateNameInformation
:
2967 Status
= RxQueryAlternateNameInfo(Context
, Buffer
);
2970 case FilePipeInformation
:
2971 case FilePipeLocalInformation
:
2972 case FilePipeRemoteInformation
:
2973 Status
= RxQueryPipeInfo(Context
, Buffer
);
2976 case FileCompressionInformation
:
2977 Status
= RxQueryCompressedInfo(Context
, Buffer
);
2981 Context
->IoStatusBlock
.Status
= RxpQueryInfoMiniRdr(Context
, FileInfoClass
, Buffer
);
2982 Status
= Context
->IoStatusBlock
.Status
;
2986 if (Context
->Info
.Length
< 0)
2988 Status
= STATUS_BUFFER_OVERFLOW
;
2989 Context
->Info
.Length
= Stack
->Parameters
.QueryFile
.Length
;
2992 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryFile
.Length
- Context
->Info
.Length
;
2998 RxReleaseFcb(Context
, Fcb
);
3003 DPRINT("Status: %x\n", Status
);
3006 #undef SET_SIZE_AND_QUERY
3011 RxCommonQueryQuotaInformation(
3012 PRX_CONTEXT Context
)
3015 return STATUS_NOT_IMPLEMENTED
;
3020 RxCommonQuerySecurity(
3021 PRX_CONTEXT Context
)
3024 return STATUS_NOT_IMPLEMENTED
;
3032 RxCommonQueryVolumeInformation(
3033 PRX_CONTEXT Context
)
3039 PIO_STACK_LOCATION Stack
;
3043 Fcb
= (PFCB
)Context
->pFcb
;
3044 Fobx
= (PFOBX
)Context
->pFobx
;
3046 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context
, Fcb
, Fobx
);
3048 Irp
= Context
->CurrentIrp
;
3049 Stack
= Context
->CurrentIrpSp
;
3050 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack
->Parameters
.QueryVolume
.Length
,
3051 Stack
->Parameters
.QueryVolume
.FsInformationClass
, Irp
->AssociatedIrp
.SystemBuffer
);
3053 Context
->Info
.FsInformationClass
= Stack
->Parameters
.QueryVolume
.FsInformationClass
;
3054 Context
->Info
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3055 Context
->Info
.Length
= Stack
->Parameters
.QueryVolume
.Length
;
3057 /* Forward to mini-rdr */
3058 MINIRDR_CALL(Status
, Context
, Fcb
->MRxDispatch
, MRxQueryVolumeInfo
, (Context
));
3060 /* Post request if mini-rdr asked to */
3061 if (Context
->PostRequest
)
3063 Status
= RxFsdPostRequest(Context
);
3067 Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryVolume
.Length
- Context
->Info
.Length
;
3070 DPRINT("Status: %x\n", Status
);
3077 PRX_CONTEXT RxContext
)
3085 PFILE_OBJECT FileObject
;
3086 LARGE_INTEGER ByteOffset
;
3087 PIO_STACK_LOCATION Stack
;
3088 PLOWIO_CONTEXT LowIoContext
;
3089 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3090 ULONG ReadLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3091 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, PostRequest
, IsPipe
, ReadCachingEnabled
, ReadCachingDisabled
, InFsp
, OwnerSet
;
3095 Fcb
= (PFCB
)RxContext
->pFcb
;
3096 Fobx
= (PFOBX
)RxContext
->pFobx
;
3097 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3099 /* Get some parameters */
3100 Irp
= RxContext
->CurrentIrp
;
3101 Stack
= RxContext
->CurrentIrpSp
;
3102 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3103 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3104 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3105 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3106 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3107 ReadLength
= Stack
->Parameters
.Read
.Length
;
3108 ByteOffset
.QuadPart
= Stack
->Parameters
.Read
.ByteOffset
.QuadPart
;
3109 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength
, ByteOffset
.QuadPart
,
3110 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3112 RxItsTheSameContext();
3114 Irp
->IoStatus
.Information
= 0;
3116 /* Should the read be loud - so far, it's just ignored on ReactOS:
3117 * s/DPRINT/DPRINT1/g will make it loud
3119 LowIoContext
= &RxContext
->LowIoContext
;
3120 CheckForLoudOperations(RxContext
);
3121 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3123 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3124 ByteOffset
, ReadLength
,
3125 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3128 RxDeviceObject
= RxContext
->RxDeviceObject
;
3130 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3132 InterlockedIncrement((volatile long *)&RxDeviceObject
->ReadOperations
);
3134 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedReadOffset
)
3136 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomReadOperations
);
3138 Fobx
->Specific
.DiskFile
.PredictedReadOffset
= ByteOffset
.QuadPart
+ ReadLength
;
3142 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingReadBytesRequested
, ReadLength
);
3146 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingReadBytesRequested
, ReadLength
);
3150 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheReadBytesRequested
, ReadLength
);
3154 /* A pagefile cannot be a pipe */
3155 IsPipe
= Fcb
->NetRoot
->Type
== NET_ROOT_PIPE
;
3156 if (IsPipe
&& PagingIo
)
3158 return STATUS_INVALID_DEVICE_REQUEST
;
3161 /* Null-length read is no-op */
3162 if (ReadLength
== 0)
3164 return STATUS_SUCCESS
;
3167 /* Validate FCB type */
3168 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeType(Fcb
) != RDBSS_NTC_VOLUME_FCB
)
3170 return STATUS_INVALID_DEVICE_REQUEST
;
3173 /* Init the lowio context for possible forward */
3174 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_READ
);
3176 PostRequest
= FALSE
;
3177 ReadCachingDisabled
= FALSE
;
3179 ReadCachingEnabled
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3180 FileObject
= Stack
->FileObject
;
3181 NetRoot
= (PNET_ROOT
)Fcb
->pNetRoot
;
3186 /* If no caching, make sure current Cc data have been flushed */
3187 if (!PagingIo
&& NoCache
&& !ReadCachingEnabled
&& FileObject
->SectionObjectPointer
!= NULL
)
3189 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3190 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3195 else if (Status
!= STATUS_SUCCESS
)
3200 ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, TRUE
);
3201 CcFlushCache(FileObject
->SectionObjectPointer
, &ByteOffset
, ReadLength
, &Irp
->IoStatus
);
3202 RxReleasePagingIoResource(RxContext
, Fcb
);
3204 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3209 RxAcquirePagingIoResource(RxContext
, Fcb
);
3210 RxReleasePagingIoResource(RxContext
, Fcb
);
3213 /* Acquire the appropriate lock */
3214 if (PagingIo
&& !ReadCachingEnabled
)
3218 if (!ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, CanWait
))
3226 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3231 if (!ReadCachingEnabled
)
3233 if (!CanWait
&& NoCache
)
3235 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3236 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3238 DPRINT1("RdAsyLNG %x\n", RxContext
);
3242 if (Status
!= STATUS_SUCCESS
)
3244 DPRINT1("RdAsyOthr %x\n", RxContext
);
3248 if (RxIsFcbAcquiredShared(Fcb
) <= 0xF000)
3250 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3260 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3261 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3266 else if (Status
!= STATUS_SUCCESS
)
3274 RxItsTheSameContext();
3276 ReadCachingDisabled
= (ReadCachingEnabled
== FALSE
);
3282 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3284 /* Make sure FLOCK doesn't conflict */
3287 if (!FsRtlCheckLockForReadAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3289 Status
= STATUS_FILE_LOCK_CONFLICT
;
3294 /* Validate byteoffset vs length */
3295 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
3297 if (ByteOffset
.QuadPart
>= FileSize
)
3299 Status
= STATUS_END_OF_FILE
;
3303 if (ReadLength
> FileSize
- ByteOffset
.QuadPart
)
3305 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3310 if (!PagingIo
&& !NoCache
&& ReadCachingEnabled
&&
3311 !BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
))
3313 /* File was not cached yet, do it */
3314 if (FileObject
->PrivateCacheMap
== NULL
)
3316 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
3318 Status
= STATUS_FILE_CLOSED
;
3322 RxAdjustAllocationSizeforCC(Fcb
);
3324 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
3325 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
3327 if (BooleanFlagOn(Fcb
->MRxDispatch
->MRxFlags
, RDBSS_NO_DEFERRED_CACHE_READAHEAD
))
3329 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3333 CcSetAdditionalCacheAttributes(FileObject
, TRUE
, FALSE
);
3334 SetFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3337 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
3340 /* This should never happen - fix your RDR */
3341 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
3346 CcMdlRead(FileObject
, &ByteOffset
, ReadLength
, &Irp
->MdlAddress
, &Irp
->IoStatus
);
3347 Status
= Irp
->IoStatus
.Status
;
3348 ASSERT(NT_SUCCESS(Status
));
3353 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3354 if (SystemBuffer
== NULL
)
3356 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3360 SetFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3362 RxItsTheSameContext();
3364 /* Perform the read */
3365 if (!CcCopyRead(FileObject
, &ByteOffset
, ReadLength
, CanWait
, SystemBuffer
, &Irp
->IoStatus
))
3367 if (!ReadCachingEnabled
)
3369 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3372 RxItsTheSameContext();
3378 if (!ReadCachingEnabled
)
3380 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
3383 Status
= Irp
->IoStatus
.Status
;
3384 ASSERT(NT_SUCCESS(Status
));
3389 /* Validate the reading */
3390 if (FileObject
->PrivateCacheMap
!= NULL
&& BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) &&
3391 ByteOffset
.QuadPart
>= 4096)
3393 CcSetAdditionalCacheAttributes(FileObject
, FALSE
, FALSE
);
3394 ClearFlag(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
);
3397 /* If it's consistent, forward to mini-rdr */
3398 if (Fcb
->CachedNetRootType
!= NET_ROOT_DISK
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READAHEAD_DEFERRED
) ||
3399 ByteOffset
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)
3401 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= ReadLength
;
3402 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
3404 RxItsTheSameContext();
3406 if (InFsp
&& ReadCachingDisabled
)
3408 ExSetResourceOwnerPointer((PagingIo
? Fcb
->Header
.PagingIoResource
: Fcb
->Header
.Resource
),
3409 (PVOID
)((ULONG_PTR
)RxContext
| 3));
3413 Status
= RxLowIoReadShell(RxContext
);
3415 RxItsTheSameContext();
3419 if (ByteOffset
.QuadPart
> FileSize
)
3422 Irp
->IoStatus
.Information
= ReadLength
;
3426 if (ByteOffset
.QuadPart
+ ReadLength
> FileSize
)
3428 ReadLength
= FileSize
- ByteOffset
.QuadPart
;
3431 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
3432 RtlZeroMemory(SystemBuffer
, ReadLength
);
3433 Irp
->IoStatus
.Information
= ReadLength
;
3439 RxItsTheSameContext();
3441 /* Post if required */
3444 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
3445 Status
= RxFsdPostRequest(RxContext
);
3449 /* Update FO in case of sync IO */
3450 if (!IsPipe
&& !PagingIo
)
3452 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
3454 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
3459 /* Set FastIo if read was a success */
3460 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
3462 if (!IsPipe
&& !PagingIo
)
3464 SetFlag(FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
3468 /* In case we're done (not expected any further processing */
3469 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostRequest
)
3471 /* Release everything that can be */
3472 if (ReadCachingDisabled
)
3478 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3482 RxReleasePagingIoResource(RxContext
, Fcb
);
3489 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
3493 RxReleaseFcb(RxContext
, Fcb
);
3498 /* Dereference/Delete context */
3501 RxDereferenceAndDeleteRxContext(RxContext
);
3505 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
3507 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
3511 /* We cannot return more than asked */
3512 if (Status
== STATUS_SUCCESS
)
3514 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
3521 RxDereferenceAndDeleteRxContext(RxContext
);
3532 PRX_CONTEXT Context
)
3535 return STATUS_NOT_IMPLEMENTED
;
3540 RxCommonSetInformation(
3541 PRX_CONTEXT Context
)
3544 return STATUS_NOT_IMPLEMENTED
;
3549 RxCommonSetQuotaInformation(
3550 PRX_CONTEXT Context
)
3553 return STATUS_NOT_IMPLEMENTED
;
3558 RxCommonSetSecurity(
3559 PRX_CONTEXT Context
)
3562 return STATUS_NOT_IMPLEMENTED
;
3567 RxCommonSetVolumeInformation(
3568 PRX_CONTEXT Context
)
3571 return STATUS_NOT_IMPLEMENTED
;
3576 RxCommonUnimplemented(
3577 PRX_CONTEXT Context
)
3580 return STATUS_NOT_IMPLEMENTED
;
3586 PRX_CONTEXT RxContext
)
3594 PFILE_OBJECT FileObject
;
3595 PIO_STACK_LOCATION Stack
;
3596 LARGE_INTEGER ByteOffset
;
3597 NODE_TYPE_CODE NodeTypeCode
;
3598 PLOWIO_CONTEXT LowIoContext
;
3599 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3600 ULONG WriteLength
, CapturedRxContextSerialNumber
= RxContext
->SerialNumber
;
3601 LONGLONG FileSize
, ValidDataLength
, InitialFileSize
, InitialValidDataLength
;
3602 BOOLEAN CanWait
, PagingIo
, NoCache
, Sync
, NormalFile
, WriteToEof
, IsPipe
, NoPreposting
, InFsp
, RecursiveWriteThrough
, CalledByLazyWriter
, SwitchBackToAsync
, ExtendingFile
, ExtendingValidData
, UnwindOutstandingAsync
, ResourceOwnerSet
, PostIrp
, ContextReferenced
;
3606 Fcb
= (PFCB
)RxContext
->pFcb
;
3607 NodeTypeCode
= NodeType(Fcb
);
3608 /* Validate FCB type */
3609 if (NodeTypeCode
!= RDBSS_NTC_STORAGE_TYPE_FILE
&& NodeTypeCode
!= RDBSS_NTC_VOLUME_FCB
&&
3610 NodeTypeCode
!= RDBSS_NTC_SPOOLFILE
&& NodeTypeCode
!= RDBSS_NTC_MAILSLOT
)
3612 return STATUS_INVALID_DEVICE_REQUEST
;
3615 /* We'll write to file, keep track of it */
3616 Fcb
->IsFileWritten
= TRUE
;
3618 Stack
= RxContext
->CurrentIrpSp
;
3619 /* Set write through if asked */
3620 if (BooleanFlagOn(Stack
->Flags
, SL_WRITE_THROUGH
))
3622 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
3625 Fobx
= (PFOBX
)RxContext
->pFobx
;
3626 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext
, Fobx
, Fcb
);
3628 /* Get some parameters */
3629 Irp
= RxContext
->CurrentIrp
;
3630 NoPreposting
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
3631 InFsp
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
);
3632 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
3633 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
3634 NoCache
= BooleanFlagOn(Irp
->Flags
, IRP_NOCACHE
);
3635 Sync
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
3636 WriteLength
= Stack
->Parameters
.Write
.Length
;
3637 ByteOffset
.QuadPart
= Stack
->Parameters
.Write
.ByteOffset
.QuadPart
;
3638 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength
, ByteOffset
.QuadPart
,
3639 (CanWait
? "CW" : "!CW"), (PagingIo
? "PI" : "!PI"), (NoCache
? "NC" : "!NC"), (Sync
? "S" : "!S"));
3641 RxItsTheSameContext();
3643 RxContext
->FcbResourceAcquired
= FALSE
;
3644 RxContext
->FcbPagingIoResourceAcquired
= FALSE
;
3646 LowIoContext
= &RxContext
->LowIoContext
;
3647 CheckForLoudOperations(RxContext
);
3648 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_LOUDOPS
))
3650 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3651 ByteOffset
, WriteLength
,
3652 Fcb
, Fcb
->Header
.ValidDataLength
, Fcb
->Header
.FileSize
, Fcb
->Header
.AllocationSize
);
3655 RxDeviceObject
= RxContext
->RxDeviceObject
;
3657 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
) && Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
3659 InterlockedIncrement((volatile long *)&RxDeviceObject
->WriteOperations
);
3661 if (ByteOffset
.QuadPart
!= Fobx
->Specific
.DiskFile
.PredictedWriteOffset
)
3663 InterlockedIncrement((volatile long *)&RxDeviceObject
->RandomWriteOperations
);
3665 Fobx
->Specific
.DiskFile
.PredictedWriteOffset
= ByteOffset
.QuadPart
+ WriteLength
;
3669 ExInterlockedAddLargeStatistic(&RxDeviceObject
->PagingWriteBytesRequested
, WriteLength
);
3673 ExInterlockedAddLargeStatistic(&RxDeviceObject
->NonPagingWriteBytesRequested
, WriteLength
);
3677 ExInterlockedAddLargeStatistic(&RxDeviceObject
->CacheWriteBytesRequested
, WriteLength
);
3681 NetRoot
= (PNET_ROOT
)Fcb
->NetRoot
;
3682 IsPipe
= (NetRoot
->Type
== NET_ROOT_PIPE
);
3683 /* Keep track for normal writes */
3684 if (NetRoot
->Type
== NET_ROOT_DISK
|| NetRoot
->Type
== NET_ROOT_WILD
)
3693 /* Zero-length write is immediate success */
3694 if (NormalFile
&& WriteLength
== 0)
3696 return STATUS_SUCCESS
;
3699 /* Check whether we have input data */
3700 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
3702 return STATUS_INVALID_PARAMETER
;
3705 /* Are we writting to EOF? */
3706 WriteToEof
= ((ByteOffset
.LowPart
== FILE_WRITE_TO_END_OF_FILE
) && (ByteOffset
.HighPart
== -1));
3707 /* FIXME: validate length/offset */
3709 /* Get our SRV_OPEN in case of normal write */
3712 SrvOpen
= (PSRV_OPEN
)Fobx
->pSrvOpen
;
3719 FileObject
= Stack
->FileObject
;
3721 /* If we have caching enabled, check whether we have to defer write */
3724 if (RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3726 if (!CcCanIWrite(FileObject
, WriteLength
,
3727 (CanWait
&& !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
)),
3728 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
)))
3732 Retrying
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3734 RxPrePostIrp(RxContext
, Irp
);
3736 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_DEFERRED_WRITE
);
3738 CcDeferWrite(FileObject
, (PCC_POST_DEFERRED_WRITE
)RxAddToWorkque
, RxContext
, Irp
, WriteLength
, Retrying
);
3740 return STATUS_PENDING
;
3745 /* Initialize the low IO context for write */
3746 RxInitializeLowIoContext(LowIoContext
, LOWIO_OP_WRITE
);
3748 /* Initialize our (many) booleans */
3749 RecursiveWriteThrough
= FALSE
;
3750 CalledByLazyWriter
= FALSE
;
3751 SwitchBackToAsync
= FALSE
;
3752 ExtendingFile
= FALSE
;
3753 ExtendingValidData
= FALSE
;
3754 UnwindOutstandingAsync
= FALSE
;
3755 ResourceOwnerSet
= FALSE
;
3757 ContextReferenced
= FALSE
;
3759 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3763 /* No volume FCB here! */
3764 ASSERT((NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
) ||
3765 (NodeTypeCode
== RDBSS_NTC_SPOOLFILE
) ||
3766 (NodeTypeCode
== RDBSS_NTC_MAILSLOT
));
3768 /* Writing to EOF on a paging file is non sense */
3769 ASSERT(!(WriteToEof
&& PagingIo
));
3771 RxItsTheSameContext();
3773 /* Start locking stuff */
3774 if (!PagingIo
&& !NoPreposting
)
3776 /* If it's already acquired, all fine */
3777 if (RxContext
->FcbResourceAcquired
)
3783 /* Otherwise, try to acquire shared (excepted for pipes) */
3786 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3789 (!NoCache
&& RxWriteCacheingAllowed(Fcb
, SrvOpen
)))
3791 Status
= RxAcquireSharedFcb(RxContext
, Fcb
);
3795 Status
= RxAcquireSharedFcbWaitForEx(RxContext
, Fcb
);
3798 /* We'll post IRP to retry */
3799 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3802 DPRINT1("Failed to acquire lock!\n");
3803 _SEH2_TRY_RETURN(Status
);
3806 /* We'll just fail */
3807 if (Status
!= STATUS_SUCCESS
)
3809 _SEH2_TRY_RETURN(Status
);
3812 /* Resource acquired */
3813 RxContext
->FcbResourceAcquired
= TRUE
;
3816 /* At that point, resource is acquired */
3819 ASSERT(RxContext
->FcbResourceAcquired
);
3825 /* Now, check whether we have to promote shared lock */
3826 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
3828 IsDormant
= BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
3835 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
3836 if (RxIsFcbAcquiredShared(Fcb
) &&
3837 ByteOffset
.QuadPart
+ WriteLength
> Fcb
->Header
.ValidDataLength
.QuadPart
)
3841 RxReleaseFcb(RxContext
, Fcb
);
3842 RxContext
->FcbResourceAcquired
= FALSE
;
3844 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3845 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3848 DPRINT1("Failed to acquire lock!\n");
3849 _SEH2_TRY_RETURN(Status
);
3852 if (Status
!= STATUS_SUCCESS
)
3854 _SEH2_TRY_RETURN(Status
);
3857 RxContext
->FcbResourceAcquired
= TRUE
;
3861 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
3862 if (ByteOffset
.QuadPart
+ WriteLength
<= Fcb
->Header
.ValidDataLength
.QuadPart
||
3865 if (RxIsFcbAcquiredExclusive(Fcb
))
3867 RxConvertToSharedFcb(RxContext
, Fcb
);
3872 /* We're extending file, disable collapsing */
3873 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
3875 DPRINT("Disabling collapsing\n");
3877 if (NodeTypeCode
== RDBSS_NTC_STORAGE_TYPE_FILE
&& Fobx
!= NULL
)
3879 SetFlag(Fobx
->Flags
, FOBX_FLAG_DISABLE_COLLAPSING
);
3883 ASSERT(RxContext
->FcbResourceAcquired
);
3886 /* Keep track of the acquired resource */
3887 LowIoContext
->Resource
= Fcb
->Header
.Resource
;
3894 /* Lock the paging resource */
3895 RxAcquirePagingIoResourceShared(RxContext
, Fcb
, TRUE
);
3897 /* Keep track of the acquired resource */
3898 LowIoContext
->Resource
= Fcb
->Header
.PagingIoResource
;
3904 _SEH2_TRY_RETURN(Status
= STATUS_NOT_IMPLEMENTED
);
3907 /* If it's a non cached write, or if caching is disallowed */
3908 if (NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
3910 /* If cache was previously enabled, we'll have to flush before writing */
3911 if (!PagingIo
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
)
3913 LARGE_INTEGER FlushOffset
;
3916 ASSERT(RxIsFcbAcquiredExclusive(Fcb
) || RxIsFcbAcquiredShared(Fcb
));
3918 /* If shared, we'll have to relock exclusive */
3919 if (!RxIsFcbAcquiredExclusive(Fcb
))
3921 /* Release and retry exclusive */
3922 RxReleaseFcb(RxContext
, Fcb
);
3923 RxContext
->FcbResourceAcquired
= FALSE
;
3925 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
3926 if (Status
== STATUS_LOCK_NOT_GRANTED
)
3929 DPRINT1("Failed to acquire lock for flush!\n");
3930 _SEH2_TRY_RETURN(Status
);
3933 if (Status
!= STATUS_SUCCESS
)
3935 _SEH2_TRY_RETURN(Status
);
3938 RxContext
->FcbResourceAcquired
= TRUE
;
3941 /* Get the length to flush */
3944 RxGetFileSizeWithLock(Fcb
, &FlushOffset
.QuadPart
);
3948 FlushOffset
.QuadPart
= ByteOffset
.QuadPart
;
3951 /* Perform the flushing */
3952 RxAcquirePagingIoResource(RxContext
, Fcb
);
3953 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, &FlushOffset
,
3954 WriteLength
, &Irp
->IoStatus
);
3955 RxReleasePagingIoResource(RxContext
, Fcb
);
3957 /* Cannot continue if flushing failed */
3958 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
3960 _SEH2_TRY_RETURN(Status
= Irp
->IoStatus
.Status
);
3964 RxAcquirePagingIoResource(RxContext
, Fcb
);
3965 RxReleasePagingIoResource(RxContext
, Fcb
);
3968 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
,
3969 &FlushOffset
, WriteLength
, FALSE
);
3973 /* If not paging IO, check if write is allowed */
3976 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
3978 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
3982 /* Get file sizes */
3983 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
3984 RxGetFileSizeWithLock(Fcb
, &FileSize
);
3985 ASSERT(ValidDataLength
<= FileSize
);
3987 /* If paging IO, we cannot write past file size
3988 * so fix write length if needed
3992 if (ByteOffset
.QuadPart
>= FileSize
)
3994 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
3997 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
3999 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4003 /* If we're being called by the lazywrite */
4004 if (Fcb
->Specific
.Fcb
.LazyWriteThread
== PsGetCurrentThread())
4006 CalledByLazyWriter
= TRUE
;
4008 /* Fail if we're beyong VDL */
4009 if (BooleanFlagOn(Fcb
->Header
.Flags
, FSRTL_FLAG_USER_MAPPED_FILE
))
4011 if ((ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
) &&
4012 (ByteOffset
.QuadPart
< FileSize
))
4014 if (ByteOffset
.QuadPart
+ WriteLength
> ((ValidDataLength
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
4016 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4022 /* If that's a recursive synchronous page write */
4023 if (BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) &&
4024 BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
4028 /* Check the top level IRP on the FastIO path */
4029 TopIrp
= RxGetTopIrpIfRdbssIrp();
4030 if (TopIrp
!= NULL
&& (ULONG_PTR
)TopIrp
> FSRTL_FAST_IO_TOP_LEVEL_IRP
)
4032 PIO_STACK_LOCATION IrpStack
;
4034 ASSERT(NodeType(TopIrp
) == IO_TYPE_IRP
);
4036 /* If the top level IRP was a cached write for this file, keep track */
4037 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
4038 if (IrpStack
->MajorFunction
== IRP_MJ_WRITE
&&
4039 IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
)
4041 RecursiveWriteThrough
= TRUE
;
4042 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WRITE_THROUGH
);
4047 /* Now, deal with file size and VDL */
4048 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
&&
4049 (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
))
4051 /* Not sync? Let's make it sync, just the time we extended */
4055 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4056 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4059 /* Keep track we'll have to switch back to async */
4062 SwitchBackToAsync
= TRUE
;
4066 /* Release all the locks */
4067 RxWriteReleaseResources(RxContext
, 0);
4069 /* Acquire exclusive */
4070 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
4071 if (Status
== STATUS_LOCK_NOT_GRANTED
)
4074 DPRINT1("Failed to acquire lock for extension!\n");
4075 _SEH2_TRY_RETURN(Status
);
4078 if (Status
!= STATUS_SUCCESS
)
4080 _SEH2_TRY_RETURN(Status
);
4083 RxContext
->FcbResourceAcquired
= TRUE
;
4085 RxItsTheSameContext();
4087 /* Get the sizes again, to be sure they didn't change in the meantime */
4088 ValidDataLength
= Fcb
->Header
.ValidDataLength
.QuadPart
;
4089 RxGetFileSizeWithLock(Fcb
, &FileSize
);
4090 ASSERT(ValidDataLength
<= FileSize
);
4092 /* Check we can switch back to async? */
4093 if ((SwitchBackToAsync
&& Fcb
->NonPaged
->SectionObjectPointers
.DataSectionObject
!= NULL
) ||
4094 (ByteOffset
.QuadPart
+ WriteLength
> FileSize
) || RxNoAsync
)
4096 SwitchBackToAsync
= FALSE
;
4099 /* If paging IO, check we don't try to extend the file */
4102 if (ByteOffset
.QuadPart
>= FileSize
)
4104 _SEH2_TRY_RETURN(Status
= STATUS_SUCCESS
);
4107 if (WriteLength
> FileSize
- ByteOffset
.QuadPart
)
4109 WriteLength
= FileSize
- ByteOffset
.QuadPart
;
4114 /* Save our initial sizes for potential rollback */
4115 InitialFileSize
= FileSize
;
4116 InitialValidDataLength
= ValidDataLength
;
4117 /* If writing to EOF, update byte offset with file size */
4120 ByteOffset
.QuadPart
= FileSize
;
4123 /* Check again whether we're allowed to write */
4126 if (!FsRtlCheckLockForWriteAccess(&Fcb
->Specific
.Fcb
.FileLock
, Irp
))
4128 _SEH2_TRY_RETURN(Status
= STATUS_FILE_LOCK_CONFLICT
);
4131 /* Do we have to extend? */
4132 if (NormalFile
&& (ByteOffset
.QuadPart
+ WriteLength
> FileSize
))
4134 DPRINT("Need to extend file\n");
4135 ExtendingFile
= TRUE
;
4136 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
);
4140 /* Let's start to extend */
4143 /* If we're past allocating, inform mini-rdr */
4144 FileSize
= ByteOffset
.QuadPart
+ WriteLength
;
4145 if (FileSize
> Fcb
->Header
.AllocationSize
.QuadPart
)
4147 LARGE_INTEGER NewAllocationSize
;
4149 DPRINT("Extending %p\n", RxContext
);
4153 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4154 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForNonCache
,
4155 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4159 C_ASSERT(sizeof(LONGLONG
) == sizeof(LARGE_INTEGER
));
4160 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxExtendForCache
,
4161 (RxContext
, (PLARGE_INTEGER
)&FileSize
, &NewAllocationSize
));
4164 if (!NT_SUCCESS(Status
))
4166 _SEH2_TRY_RETURN(Status
);
4169 if (FileSize
> NewAllocationSize
.QuadPart
)
4171 NewAllocationSize
.QuadPart
= FileSize
;
4174 /* And update FCB */
4175 Fcb
->Header
.AllocationSize
.QuadPart
= NewAllocationSize
.QuadPart
;
4178 /* Set the new sizes */
4179 RxSetFileSizeWithLock(Fcb
, &FileSize
);
4180 RxAdjustAllocationSizeforCC(Fcb
);
4183 if (CcIsFileCached(FileObject
))
4185 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4189 /* Do we have to extend VDL? */
4190 if (!CalledByLazyWriter
&& !RecursiveWriteThrough
)
4192 if (WriteToEof
|| ByteOffset
.QuadPart
+ WriteLength
> ValidDataLength
)
4194 ExtendingValidData
= TRUE
;
4195 SetFlag(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
);
4199 /* If none cached write */
4200 if (PagingIo
|| NoCache
|| !RxWriteCacheingAllowed(Fcb
, SrvOpen
))
4202 /* Switch back to async, if asked to */
4203 if (SwitchBackToAsync
)
4208 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
4209 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4212 /* If not synchronous, keep track of writes to be finished */
4215 if (Fcb
->NonPaged
->OutstandingAsyncEvent
== NULL
)
4217 Fcb
->NonPaged
->OutstandingAsyncEvent
= &Fcb
->NonPaged
->TheActualEvent
;
4218 KeInitializeEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
,
4219 NotificationEvent
, FALSE
);
4222 if (ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
,
4224 &RxStrucSupSpinLock
) == 0)
4226 KeResetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
);
4229 UnwindOutstandingAsync
= TRUE
;
4230 LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
= Fcb
->NonPaged
;
4233 /* Set our LOWIO_CONTEXT information */
4234 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
= ByteOffset
.QuadPart
;
4235 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
= WriteLength
;
4237 RxItsTheSameContext();
4239 /* We have to be locked */
4240 ASSERT(RxContext
->FcbResourceAcquired
|| RxContext
->FcbPagingIoResourceAcquired
);
4242 /* Update thread ID if we're in FSP */
4245 LowIoContext
->ResourceThreadId
= (ULONG_PTR
)RxContext
| 3;
4247 if (RxContext
->FcbResourceAcquired
)
4249 ExSetResourceOwnerPointer(Fcb
->Header
.Resource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4252 if (RxContext
->FcbPagingIoResourceAcquired
)
4254 ExSetResourceOwnerPointer(Fcb
->Header
.PagingIoResource
, (PVOID
)((ULONG_PTR
)RxContext
| 3));
4257 ResourceOwnerSet
= TRUE
;
4260 /* And perform the write */
4261 Status
= RxLowIoWriteShell(RxContext
);
4263 RxItsTheSameContext();
4265 /* Not outstanding write anymore */
4266 if (UnwindOutstandingAsync
&& Status
== STATUS_PENDING
)
4268 UnwindOutstandingAsync
= FALSE
;
4274 /* If cache wasn't enabled yet, do it */
4275 if (FileObject
->PrivateCacheMap
== NULL
)
4277 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
4279 _SEH2_TRY_RETURN(Status
= STATUS_FILE_CLOSED
);
4282 RxAdjustAllocationSizeforCC(Fcb
);
4284 CcInitializeCacheMap(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
4285 FALSE
, &RxData
.CacheManagerCallbacks
, Fcb
);
4287 CcSetReadAheadGranularity(FileObject
, NetRoot
->DiskParameters
.ReadAheadGranularity
);
4290 /* If that's a MDL backed write */
4291 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
4293 /* Shouldn't happen */
4297 /* Perform it, though */
4298 CcPrepareMdlWrite(FileObject
, &ByteOffset
, WriteLength
,
4299 &Irp
->MdlAddress
, &Irp
->IoStatus
);
4301 Status
= Irp
->IoStatus
.Status
;
4306 ULONG BreakpointsSave
;
4308 /* Map the user buffer */
4309 SystemBuffer
= RxNewMapUserBuffer(RxContext
);
4310 if (SystemBuffer
== NULL
)
4312 _SEH2_TRY_RETURN(Status
= STATUS_INSUFFICIENT_RESOURCES
);
4315 RxSaveAndSetExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4317 RxItsTheSameContext();
4319 /* And deal with Cc */
4320 if (!CcCopyWrite(FileObject
, &ByteOffset
, WriteLength
, CanWait
,
4323 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4325 RxItsTheSameContext();
4327 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4328 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4334 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4335 Irp
->IoStatus
.Information
= WriteLength
;
4337 RxRestoreExceptionNoBreakpointFlag(RxContext
, BreakpointsSave
);
4339 RxItsTheSameContext();
4341 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4342 FileObject
, Fcb
->Header
.FileSize
.QuadPart
, WriteLength
, Status
);
4349 /* If we've to post the IRP */
4352 /* Reset the file size if required */
4353 if (ExtendingFile
&& !IsPipe
)
4355 ASSERT(RxWriteCacheingAllowed(Fcb
, SrvOpen
));
4356 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4358 RxAcquirePagingIoResource(RxContext
, Fcb
);
4359 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4360 RxReleasePagingIoResource(RxContext
, Fcb
);
4362 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4364 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4368 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4369 ContextReferenced
= TRUE
;
4372 ASSERT(!ResourceOwnerSet
);
4373 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4375 #ifdef RDBSS_TRACKER
4376 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
4379 /* And post the request */
4380 Status
= RxFsdPostRequest(RxContext
);
4386 /* Update FILE_OBJECT if synchronous write succeed */
4389 if (NT_SUCCESS(Status
) && BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
4391 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4395 /* If write succeed, ,also update FILE_OBJECT flags */
4396 if (NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
4398 /* File was modified */
4401 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
4404 /* If was even extended */
4407 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
4410 /* If VDL was extended, update FCB and inform Cc */
4411 if (ExtendingValidData
)
4413 LONGLONG LastOffset
;
4415 LastOffset
= ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
4416 if (FileSize
< LastOffset
)
4418 LastOffset
= FileSize
;
4421 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
4423 if (NoCache
&& CcIsFileCached(FileObject
))
4425 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
4434 /* Finally, if we failed while extension was required */
4435 if (_SEH2_AbnormalTermination() && (ExtendingFile
|| ExtendingValidData
))
4440 ASSERT(Fcb
->Header
.PagingIoResource
!= NULL
);
4442 RxAcquirePagingIoResource(RxContext
, Fcb
);
4443 RxSetFileSizeWithLock(Fcb
, &InitialFileSize
);
4444 Fcb
->Header
.ValidDataLength
.QuadPart
= InitialValidDataLength
;
4445 RxReleasePagingIoResource(RxContext
, Fcb
);
4447 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
4449 *CcGetFileSizePointer(FileObject
) = Fcb
->Header
.FileSize
;
4454 /* One async write less */
4455 if (UnwindOutstandingAsync
)
4459 ExInterlockedAddUlong(&Fcb
->NonPaged
->OutstandingAsyncWrites
, -1, &RxStrucSupSpinLock
);
4460 KeSetEvent(Fcb
->NonPaged
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
4463 /* And now, cleanup everything */
4464 if (_SEH2_AbnormalTermination() || Status
!= STATUS_PENDING
|| PostIrp
)
4466 /* If we didn't post, release every lock (for posting, it's already done) */
4469 RxWriteReleaseResources(RxContext
, ResourceOwnerSet
);
4472 /* If the context was referenced - posting, dereference it */
4473 if (ContextReferenced
)
4475 RxDereferenceAndDeleteRxContext(RxContext
);
4478 /* If that's a pipe operation, resume any blocked one */
4481 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4483 RxResumeBlockedOperations_Serially(RxContext
, &Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4487 /* Sanity check for write */
4488 if (Status
== STATUS_SUCCESS
)
4490 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
4493 /* Just dereference our context */
4497 RxDereferenceAndDeleteRxContext(RxContext
);
4511 IN PRX_CONTEXT RxContext
)
4514 PFILE_OBJECT FileObject
;
4515 PIO_STACK_LOCATION Stack
;
4517 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4521 Irp
= RxContext
->CurrentIrp
;
4522 Stack
= RxContext
->CurrentIrpSp
;
4523 FileObject
= Stack
->FileObject
;
4525 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4526 switch (RxContext
->MajorFunction
)
4528 /* Call the Cc function */
4530 CcMdlReadComplete(FileObject
, Irp
->MdlAddress
);
4534 /* If here, we can wait */
4535 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
));
4537 /* Call the Cc function */
4538 CcMdlWriteComplete(FileObject
, &Stack
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
4540 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4544 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext
->MajorFunction
);
4545 RxBugCheck(RxContext
->MajorFunction
, 0, 0);
4550 Irp
->MdlAddress
= NULL
;
4552 /* And complete the IRP */
4553 RxCompleteRequest(RxContext
, STATUS_SUCCESS
);
4555 #undef BugCheckFileId
4557 return STATUS_SUCCESS
;
4564 RxCopyCreateParameters(
4565 IN PRX_CONTEXT RxContext
)
4569 PFILE_OBJECT FileObject
;
4570 PIO_STACK_LOCATION Stack
;
4571 PDFS_NAME_CONTEXT DfsNameContext
;
4572 PIO_SECURITY_CONTEXT SecurityContext
;
4574 Irp
= RxContext
->CurrentIrp
;
4575 Stack
= RxContext
->CurrentIrpSp
;
4576 FileObject
= Stack
->FileObject
;
4577 SecurityContext
= Stack
->Parameters
.Create
.SecurityContext
;
4579 RxContext
->Create
.NtCreateParameters
.SecurityContext
= SecurityContext
;
4580 if (SecurityContext
->AccessState
!= NULL
&& SecurityContext
->AccessState
->SecurityDescriptor
!= NULL
)
4582 RxContext
->Create
.SdLength
= RtlLengthSecurityDescriptor(SecurityContext
->AccessState
->SecurityDescriptor
);
4583 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext
->Create
.NtCreateParameters
.SecurityContext
,
4584 RxContext
->Create
.SdLength
);
4586 if (SecurityContext
->SecurityQos
!= NULL
)
4588 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityContext
->SecurityQos
->ImpersonationLevel
;
4592 RxContext
->Create
.NtCreateParameters
.ImpersonationLevel
= SecurityImpersonation
;
4594 RxContext
->Create
.NtCreateParameters
.DesiredAccess
= SecurityContext
->DesiredAccess
;
4596 RxContext
->Create
.NtCreateParameters
.AllocationSize
.QuadPart
= Irp
->Overlay
.AllocationSize
.QuadPart
;
4597 RxContext
->Create
.NtCreateParameters
.FileAttributes
= Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
;
4598 RxContext
->Create
.NtCreateParameters
.ShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4599 RxContext
->Create
.NtCreateParameters
.Disposition
= (Stack
->Parameters
.Create
.Options
>> 24) & 0x000000FF;
4600 RxContext
->Create
.NtCreateParameters
.CreateOptions
= Stack
->Parameters
.Create
.Options
& 0xFFFFFF;
4602 DfsContext
= FileObject
->FsContext2
;
4603 DfsNameContext
= FileObject
->FsContext
;
4604 RxContext
->Create
.NtCreateParameters
.DfsContext
= DfsContext
;
4605 RxContext
->Create
.NtCreateParameters
.DfsNameContext
= DfsNameContext
;
4606 ASSERT(DfsContext
== NULL
|| DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) ||
4607 DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) ||
4608 DfsContext
== UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT
) ||
4609 DfsContext
== UIntToPtr(DFS_USER_NAME_CONTEXT
));
4610 ASSERT(DfsNameContext
== NULL
|| DfsNameContext
->NameContextType
== DFS_OPEN_CONTEXT
||
4611 DfsNameContext
->NameContextType
== DFS_DOWNLEVEL_OPEN_CONTEXT
||
4612 DfsNameContext
->NameContextType
== DFS_CSCAGENT_NAME_CONTEXT
||
4613 DfsNameContext
->NameContextType
== DFS_USER_NAME_CONTEXT
);
4614 FileObject
->FsContext2
= NULL
;
4615 FileObject
->FsContext
= NULL
;
4617 RxContext
->pFcb
= NULL
;
4618 RxContext
->Create
.ReturnedCreateInformation
= 0;
4620 /* if we stripped last \, it has to be a directory! */
4621 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH
))
4623 SetFlag(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DIRECTORY_FILE
);
4626 RxContext
->Create
.EaLength
= Stack
->Parameters
.Create
.EaLength
;
4627 if (RxContext
->Create
.EaLength
== 0)
4629 RxContext
->Create
.EaBuffer
= NULL
;
4633 RxContext
->Create
.EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4634 DPRINT("EA Buffer: %p, Length: %lx\n", Irp
->AssociatedIrp
.SystemBuffer
, RxContext
->Create
.EaLength
);
4639 RxCreateFromNetRoot(
4640 PRX_CONTEXT Context
,
4641 PUNICODE_STRING NetRootName
)
4646 PFILE_OBJECT FileObject
;
4647 PIO_STACK_LOCATION Stack
;
4648 ACCESS_MASK DesiredAccess
;
4649 USHORT DesiredShareAccess
;
4653 /* Validate that the context is consistent */
4654 if (Context
->Create
.pNetRoot
== NULL
)
4656 return STATUS_BAD_NETWORK_PATH
;
4659 NetRoot
= (PNET_ROOT
)Context
->Create
.pNetRoot
;
4660 if (Context
->RxDeviceObject
!= NetRoot
->pSrvCall
->RxDeviceObject
)
4662 return STATUS_BAD_NETWORK_PATH
;
4665 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
) &&
4666 !BooleanFlagOn(NetRoot
->pSrvCall
->Flags
, SRVCALL_FLAG_DFS_AWARE_SERVER
))
4668 return STATUS_DFS_UNAVAILABLE
;
4671 if (Context
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
4672 BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_DFS_AWARE_NETROOT
))
4674 return STATUS_OBJECT_TYPE_MISMATCH
;
4677 Stack
= Context
->CurrentIrpSp
;
4678 DesiredShareAccess
= Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
;
4679 if (NetRoot
->Type
== NET_ROOT_PRINT
)
4681 DesiredShareAccess
= FILE_SHARE_VALID_FLAGS
;
4684 DesiredAccess
= Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_ALL_ACCESS
;
4686 /* We don't support renaming yet */
4687 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
))
4690 return STATUS_NOT_IMPLEMENTED
;
4693 /* Try to find (or create) the FCB for the file */
4694 Status
= RxFindOrCreateFcb(Context
, NetRootName
);
4695 Fcb
= (PFCB
)Context
->pFcb
;
4698 ASSERT(!NT_SUCCESS(Status
));
4700 if (!NT_SUCCESS(Status
) || Fcb
== NULL
)
4705 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
4707 Fcb
->Header
.NodeTypeCode
= RDBSS_NTC_MAILSLOT
;
4711 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
4714 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4715 if (NT_SUCCESS(Status
))
4717 RxTransitionNetFcb(Fcb
, Condition_Good
);
4718 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb
, Fcb
->Condition
);
4720 RxSetupNetFileObject(Context
);
4721 return STATUS_SUCCESS
;
4725 FileObject
= Stack
->FileObject
;
4726 /* Check SA for conflict */
4727 if (Fcb
->OpenCount
> 0)
4729 Status
= RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
4730 &Fcb
->ShareAccess
, FALSE
, "early check per useropens", "EarlyPerUO");
4731 if (!NT_SUCCESS(Status
))
4733 RxDereferenceNetFcb(Fcb
);
4738 if (BooleanFlagOn(Context
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
) &&
4739 !BooleanFlagOn(Context
->Create
.NtCreateParameters
.DesiredAccess
, ~SYNCHRONIZE
))
4746 /* Find a SRV_OPEN that suits the opening */
4747 Status
= RxCollapseOrCreateSrvOpen(Context
);
4748 if (Status
== STATUS_SUCCESS
)
4753 SrvOpen
= (PSRV_OPEN
)Context
->pRelevantSrvOpen
;
4754 Fobx
= (PFOBX
)Context
->pFobx
;
4755 /* There are already opens, check for conflict */
4756 if (Fcb
->OpenCount
!= 0)
4758 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess
, DesiredShareAccess
,
4759 FileObject
, &Fcb
->ShareAccess
,
4760 FALSE
, "second check per useropens",
4763 ++SrvOpen
->UncleanFobxCount
;
4764 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
4771 if (NetRoot
->Type
!= NET_ROOT_PIPE
)
4773 RxSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
,
4774 &Fcb
->ShareAccess
, "initial shareaccess setup", "InitShrAcc");
4778 RxSetupNetFileObject(Context
);
4780 /* No conflict? Set up SA */
4781 if (Fcb
->OpenCount
!= 0 && NetRoot
->Type
!= NET_ROOT_PIPE
)
4783 RxUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
, "update share access", "UpdShrAcc");
4786 ++Fcb
->UncleanCount
;
4787 if (BooleanFlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
))
4789 ++Fcb
->UncachedUncleanCount
;
4792 if (SrvOpen
->UncleanFobxCount
== 0 && Fcb
->UncleanCount
== 1 &&
4793 !BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE
))
4795 RxChangeBufferingState(SrvOpen
, NULL
, FALSE
);
4798 /* No pending close, we're active */
4799 ClearFlag(Fcb
->FcbState
, FCB_STATE_DELAY_CLOSE
);
4802 ++SrvOpen
->UncleanFobxCount
;
4803 ++SrvOpen
->OpenCount
;
4804 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
4806 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
))
4808 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_READ_CACHING
);
4809 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING
);
4811 ClearFlag(Fcb
->FcbState
, FCB_STATE_WRITECACHING_ENABLED
);
4812 ClearFlag(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
);
4814 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
4817 /* Now, update SA for the SRV_OPEN */
4818 RxUpdateShareAccessPerSrvOpens(SrvOpen
);
4820 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_DELETE_ON_CLOSE
))
4822 SetFlag(Fobx
->Flags
, FOBX_FLAG_DELETE_ON_CLOSE
);
4825 /* Update the FOBX info */
4828 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
4830 SetFlag(FileObject
->Flags
, FO_NAMED_PIPE
);
4833 if (Context
->Create
.pNetRoot
->Type
== NET_ROOT_PRINT
||
4834 Context
->Create
.pNetRoot
->Type
== NET_ROOT_PIPE
)
4836 Fobx
->PipeHandleInformation
= &Fobx
->Specific
.NamedPipe
.PipeHandleInformation
;
4838 Fobx
->Specific
.NamedPipe
.CollectDataTime
.QuadPart
= 0;
4839 Fobx
->Specific
.NamedPipe
.CollectDataSize
= Context
->Create
.pNetRoot
->NamedPipeParameters
.DataCollectionSize
;
4841 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.TypeOfPipe
= Context
->Create
.PipeType
;
4842 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.ReadMode
= Context
->Create
.PipeReadMode
;
4843 Fobx
->Specific
.NamedPipe
.PipeHandleInformation
.CompletionMode
= Context
->Create
.PipeCompletionMode
;
4845 InitializeListHead(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
);
4846 InitializeListHead(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
);
4850 Status
= STATUS_SUCCESS
;
4855 if (Fcb
->OpenCount
== 0)
4857 if (Context
->Create
.FcbAcquired
)
4859 Context
->Create
.FcbAcquired
= (RxDereferenceAndFinalizeNetFcb(Fcb
,
4863 if (!Context
->Create
.FcbAcquired
)
4865 RxTrackerUpdateHistory(Context
, NULL
, TRACKER_FCB_FREE
, __LINE__
, __FILE__
, 0);
4871 RxDereferenceNetFcb(Fcb
);
4883 RxCreateTreeConnect(
4884 IN PRX_CONTEXT RxContext
)
4887 PV_NET_ROOT VNetRoot
;
4888 PFILE_OBJECT FileObject
;
4889 PIO_STACK_LOCATION Stack
;
4890 NET_ROOT_TYPE NetRootType
;
4891 UNICODE_STRING CanonicalName
, RemainingName
;
4895 Stack
= RxContext
->CurrentIrpSp
;
4896 FileObject
= Stack
->FileObject
;
4898 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
4899 /* As long as we don't know connection type, mark it wild */
4900 NetRootType
= NET_ROOT_WILD
;
4901 /* Get the type by parsing the name */
4902 Status
= RxFirstCanonicalize(RxContext
, &FileObject
->FileName
, &CanonicalName
, &NetRootType
);
4903 if (!NT_SUCCESS(Status
))
4908 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
4909 RxContext
->Create
.TreeConnectOpenDeferred
= FALSE
;
4910 RtlInitEmptyUnicodeString(&RxContext
->Create
.TransportName
, NULL
, 0);
4911 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserName
, NULL
, 0);
4912 RtlInitEmptyUnicodeString(&RxContext
->Create
.Password
, NULL
, 0);
4913 RtlInitEmptyUnicodeString(&RxContext
->Create
.UserDomainName
, NULL
, 0);
4915 /* We don't handle EA - they come from DFS, don't care */
4916 if (Stack
->Parameters
.Create
.EaLength
> 0)
4921 /* Mount if required */
4922 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
4923 if (Status
== STATUS_NETWORK_CREDENTIAL_CONFLICT
)
4925 RxScavengeVNetRoots(RxContext
->RxDeviceObject
);
4926 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &RemainingName
);
4929 if (!NT_SUCCESS(Status
))
4934 /* Validate the rest of the name with mini-rdr */
4935 if (RemainingName
.Length
> 0)
4937 MINIRDR_CALL(Status
, RxContext
,
4938 RxContext
->Create
.pNetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
4939 MRxIsValidDirectory
, (RxContext
, &RemainingName
));
4942 if (!NT_SUCCESS(Status
))
4947 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
4948 RxReferenceVNetRoot(VNetRoot
);
4949 if (InterlockedCompareExchange(&VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
, 1, 0) != 0)
4951 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
4954 FileObject
->FsContext
= &RxDeviceFCB
;
4955 FileObject
->FsContext2
= VNetRoot
;
4957 VNetRoot
->ConstructionStatus
= STATUS_SUCCESS
;
4958 ++VNetRoot
->NumberOfOpens
;
4960 /* Create is over - clear context */
4961 RxContext
->Create
.pSrvCall
= NULL
;
4962 RxContext
->Create
.pNetRoot
= NULL
;
4963 RxContext
->Create
.pVNetRoot
= NULL
;
4970 RxDebugControlCommand(
4971 _In_ PSTR ControlString
)
4979 IN PDRIVER_OBJECT DriverObject
,
4980 IN PUNICODE_STRING RegistryPath
)
4983 USHORT i
, State
= 0;
4985 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject
, RegistryPath
);
4989 RxCheckFcbStructuresForAlignment();
4991 RtlZeroMemory(&RxData
, sizeof(RxData
));
4992 RxData
.NodeTypeCode
= RDBSS_NTC_DATA_HEADER
;
4993 RxData
.NodeByteSize
= sizeof(RxData
);
4994 RxData
.DriverObject
= DriverObject
;
4996 RtlZeroMemory(&RxDeviceFCB
, sizeof(RxDeviceFCB
));
4997 RxDeviceFCB
.spacer
.NodeTypeCode
= RDBSS_NTC_DEVICE_FCB
;
4998 RxDeviceFCB
.spacer
.NodeByteSize
= sizeof(RxDeviceFCB
);
5000 KeInitializeSpinLock(&RxStrucSupSpinLock
);
5001 RxExports
.pRxStrucSupSpinLock
= &RxStrucSupSpinLock
;
5003 RxInitializeDebugSupport();
5005 RxFileSystemDeviceObject
= (PRDBSS_DEVICE_OBJECT
)&RxSpaceForTheWrappersDeviceObject
;
5006 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject
, sizeof(RxSpaceForTheWrappersDeviceObject
));
5011 RxGetRegistryParameters(RegistryPath
);
5012 RxReadRegistryParameters();
5014 Status
= RxInitializeRegistrationStructures();
5015 if (!NT_SUCCESS(Status
))
5021 RxInitializeDispatcher();
5023 ExInitializeNPagedLookasideList(&RxContextLookasideList
, RxAllocatePoolWithTag
, RxFreePool
, 0, sizeof(RX_CONTEXT
), RX_IRPC_POOLTAG
, 4);
5025 InitializeListHead(&RxIrpsList
);
5026 KeInitializeSpinLock(&RxIrpsListSpinLock
);
5028 InitializeListHead(&RxActiveContexts
);
5029 InitializeListHead(&RxSrvCalldownList
);
5031 ExInitializeFastMutex(&RxContextPerFileSerializationMutex
);
5032 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex
);
5033 KeInitializeMutex(&RxScavengerMutex
, 1);
5034 KeInitializeMutex(&RxSerializationMutex
, 1);
5036 for (i
= 0; i
< RxMaximumWorkQueue
; ++i
)
5038 RxFileSystemDeviceObject
->PostedRequestCount
[i
] = 0;
5039 RxFileSystemDeviceObject
->OverflowQueueCount
[i
] = 0;
5040 InitializeListHead(&RxFileSystemDeviceObject
->OverflowQueue
[i
]);
5043 KeInitializeSpinLock(&RxFileSystemDeviceObject
->OverflowQueueSpinLock
);
5045 RxInitializeDispatchVectors(DriverObject
);
5047 ExInitializeResourceLite(&RxData
.Resource
);
5048 RxData
.OurProcess
= IoGetCurrentProcess();
5050 RxInitializeRxTimer();
5054 if (!NT_SUCCESS(Status
))
5056 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BC4, Status
);
5057 RxInitUnwind(DriverObject
, State
);
5061 /* There are still bits to init - be consider it's fine for now */
5064 return STATUS_NOT_IMPLEMENTED
;
5066 return STATUS_SUCCESS
;
5074 RxDumpCurrentAccess(
5077 _In_ PSZ wherelogtag
,
5078 _In_ PSHARE_ACCESS ShareAccess
)
5090 _In_ PSZ wherelogtag
,
5091 _In_ ACCESS_MASK DesiredAccess
,
5092 _In_ ULONG DesiredShareAccess
)
5099 RxFastIoCheckIfPossible(
5100 PFILE_OBJECT FileObject
,
5101 PLARGE_INTEGER FileOffset
,
5102 ULONG Length
, BOOLEAN Wait
,
5103 ULONG LockKey
, BOOLEAN CheckForReadOperation
,
5104 PIO_STATUS_BLOCK IoStatus
,
5105 PDEVICE_OBJECT DeviceObject
)
5112 /* Get the FCB to validate it */
5113 Fcb
= FileObject
->FsContext
;
5114 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
)
5116 DPRINT1("Not a file, FastIO not possible!\n");
5120 if (FileObject
->DeletePending
)
5122 DPRINT1("File delete pending\n");
5126 /* If there's a pending write operation, deny fast operation */
5127 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5129 DPRINT1("Write operations to be completed\n");
5133 /* Deny read on orphaned node */
5134 SrvOpen
= (PSRV_OPEN
)((PFOBX
)FileObject
->FsContext2
)->pSrvOpen
;
5135 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5137 DPRINT1("SRV_OPEN orphaned\n");
5141 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
5143 DPRINT1("FCB orphaned\n");
5147 /* If there's a buffering state change pending, deny fast operation (it might change
5150 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
5152 DPRINT1("Buffering change pending\n");
5156 /* File got renamed/deleted, deny operation */
5157 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
) ||
5158 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5160 DPRINT1("File renamed/deleted\n");
5164 /* Process pending change buffering state operations */
5165 FsRtlEnterFileSystem();
5166 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen
);
5167 FsRtlExitFileSystem();
5169 /* If operation to come is a read operation */
5170 if (CheckForReadOperation
)
5172 LARGE_INTEGER LargeLength
;
5174 /* Check that read cache is enabled */
5175 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_READCACHING_ENABLED
))
5177 DPRINT1("Read caching disabled\n");
5181 /* Check whether there's a lock conflict */
5182 LargeLength
.QuadPart
= Length
;
5183 if (!FsRtlFastCheckLockForRead(&Fcb
->Specific
.Fcb
.FileLock
,
5188 PsGetCurrentProcess()))
5190 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5203 RxFastIoDeviceControl(
5204 PFILE_OBJECT FileObject
,
5206 PVOID InputBuffer OPTIONAL
,
5207 ULONG InputBufferLength
,
5208 PVOID OutputBuffer OPTIONAL
,
5209 ULONG OutputBufferLength
,
5210 ULONG IoControlCode
,
5211 PIO_STATUS_BLOCK IoStatus
,
5212 PDEVICE_OBJECT DeviceObject
)
5214 /* Only supported IOCTL */
5215 if (IoControlCode
== IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
)
5232 PFILE_OBJECT FileObject
,
5233 PLARGE_INTEGER FileOffset
,
5238 PIO_STATUS_BLOCK IoStatus
,
5239 PDEVICE_OBJECT DeviceObject
)
5242 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5246 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject
, FileObject
->FsContext
,
5247 FileObject
->FsContext2
);
5248 DPRINT("Reading %ld at %I64x\n", Length
, FileOffset
->QuadPart
);
5250 /* Prepare a TLI context */
5251 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
5252 RxInitializeTopLevelIrpContext(&TopLevelContext
, (PIRP
)FSRTL_FAST_IO_TOP_LEVEL_IRP
,
5253 (PRDBSS_DEVICE_OBJECT
)DeviceObject
);
5255 Ret
= FsRtlCopyRead2(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
,
5256 IoStatus
, DeviceObject
, &TopLevelContext
);
5259 DPRINT("Read OK\n");
5263 DPRINT1("Read failed!\n");
5272 PFILE_OBJECT FileObject
,
5273 PLARGE_INTEGER FileOffset
,
5278 PIO_STATUS_BLOCK IoStatus
,
5279 PDEVICE_OBJECT DeviceObject
)
5287 PRX_CONTEXT RxContext
,
5288 PUNICODE_STRING NetRootName
)
5294 PV_NET_ROOT VNetRoot
;
5295 BOOLEAN TableAcquired
, AcquiredExclusive
;
5299 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
5300 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
5301 ASSERT(NetRoot
== VNetRoot
->NetRoot
);
5303 Status
= STATUS_SUCCESS
;
5304 AcquiredExclusive
= FALSE
;
5306 RxAcquireFcbTableLockShared(&NetRoot
->FcbTable
, TRUE
);
5307 TableAcquired
= TRUE
;
5308 Version
= NetRoot
->FcbTable
.Version
;
5310 /* Look for a cached FCB */
5311 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5314 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName
);
5318 DPRINT("FCB found for %wZ\n", &Fcb
->FcbTableEntry
.Path
);
5319 /* If FCB was to be orphaned, consider it as not suitable */
5320 if (Fcb
->fShouldBeOrphaned
)
5322 RxDereferenceNetFcb(Fcb
);
5323 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5325 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5326 TableAcquired
= TRUE
;
5327 AcquiredExclusive
= TRUE
;
5329 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5330 if (Fcb
!= NULL
&& Fcb
->fShouldBeOrphaned
)
5332 RxOrphanThisFcb(Fcb
);
5333 RxDereferenceNetFcb(Fcb
);
5339 /* If FCB was not found or is not covering full path, prepare for more work */
5340 if (Fcb
== NULL
|| Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5342 if (!AcquiredExclusive
)
5344 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5345 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5346 TableAcquired
= TRUE
;
5349 /* If FCB table was updated in between, re-attempt a lookup */
5350 if (NetRoot
->FcbTable
.Version
!= Version
)
5352 Fcb
= RxFcbTableLookupFcb(&NetRoot
->FcbTable
, NetRootName
);
5353 if (Fcb
!= NULL
&& Fcb
->FcbTableEntry
.Path
.Length
!= NetRootName
->Length
)
5360 /* Allocate the FCB */
5365 Fcb
= RxCreateNetFcb(RxContext
, VNetRoot
, NetRootName
);
5368 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5372 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5373 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5379 if (_SEH2_AbnormalTermination())
5381 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5382 TableAcquired
= FALSE
;
5386 RxTransitionNetFcb(Fcb
, Condition_Bad
);
5388 ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, TRUE
);
5389 if (RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
) != 0)
5391 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5400 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5403 if (!NT_SUCCESS(Status
))
5408 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
5409 DPRINT("FCB %p is in condition %lx\n", Fcb
, Fcb
->Condition
);
5411 if (!RxContext
->Create
.FcbAcquired
)
5413 RxWaitForStableNetFcb(Fcb
, RxContext
);
5414 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
5415 RxContext
->Create
.FcbAcquired
= NT_SUCCESS(Status
);
5422 RxFirstCanonicalize(
5423 PRX_CONTEXT RxContext
,
5424 PUNICODE_STRING FileName
,
5425 PUNICODE_STRING CanonicalName
,
5426 PNET_ROOT_TYPE NetRootType
)
5430 BOOLEAN UncName
, PrependString
, IsSpecial
;
5431 USHORT CanonicalLength
;
5432 UNICODE_STRING SessionIdString
;
5433 WCHAR SessionIdBuffer
[16];
5437 Type
= NET_ROOT_WILD
;
5438 PrependString
= FALSE
;
5441 Status
= STATUS_SUCCESS
;
5443 /* Name has to contain at least \\ */
5444 if (FileName
->Length
< 2 * sizeof(WCHAR
))
5446 return STATUS_OBJECT_NAME_INVALID
;
5449 /* First easy check, is that a path with a name? */
5450 CanonicalLength
= FileName
->Length
;
5451 if (FileName
->Length
> 5 * sizeof(WCHAR
))
5453 if (FileName
->Buffer
[0] == '\\' && FileName
->Buffer
[1] == ';')
5455 if (FileName
->Buffer
[3] == ':')
5457 Type
= NET_ROOT_DISK
;
5461 Type
= NET_ROOT_PRINT
;
5466 /* Nope, attempt deeper parsing */
5467 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
&& FileName
->Buffer
[1] != ';')
5470 PWSTR FirstSlash
, EndOfString
;
5472 SetFlag(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
);
5475 /* The lack of drive letter will be replaced by session ID */
5476 SessionId
= RxGetSessionId(RxContext
->CurrentIrpSp
);
5477 RtlInitEmptyUnicodeString(&SessionIdString
, SessionIdBuffer
, sizeof(SessionIdBuffer
));
5478 RtlIntegerToUnicodeString(SessionId
, 10, &SessionIdString
);
5480 EndOfString
= Add2Ptr(FileName
->Buffer
, FileName
->Length
);
5481 for (FirstSlash
= &FileName
->Buffer
[1]; FirstSlash
!= EndOfString
; ++FirstSlash
)
5483 if (*FirstSlash
== OBJ_NAME_PATH_SEPARATOR
)
5489 if (EndOfString
- FirstSlash
<= sizeof(WCHAR
))
5491 Status
= STATUS_OBJECT_NAME_INVALID
;
5496 DPRINT1("WARNING: Assuming not special + disk!\n");
5497 Type
= NET_ROOT_DISK
;
5498 Status
= STATUS_SUCCESS
;
5499 //Status = STATUS_NOT_IMPLEMENTED;
5500 /* Should be check against IPC, mailslot, and so on */
5504 /* Update net root type with our deduced one */
5505 *NetRootType
= Type
;
5506 DPRINT("Returning type: %x\n", Type
);
5508 if (!NT_SUCCESS(Status
))
5513 /* Do we have to prepend session ID? */
5518 PrependString
= TRUE
;
5519 CanonicalLength
+= SessionIdString
.Length
+ 3 * sizeof(WCHAR
);
5523 /* If not UNC path, we should preprend stuff */
5524 if (!PrependString
&& !IsSpecial
&& FileName
->Buffer
[0] != '\\')
5526 return STATUS_OBJECT_PATH_INVALID
;
5529 /* Allocate the buffer */
5530 Status
= RxAllocateCanonicalNameBuffer(RxContext
, CanonicalName
, CanonicalLength
);
5531 if (!NT_SUCCESS(Status
))
5536 /* We don't support that case, we always return disk */
5539 ASSERT(CanonicalName
->Length
== CanonicalLength
);
5541 Status
= STATUS_NOT_IMPLEMENTED
;
5545 /* If we have to prepend, go ahead */
5548 CanonicalName
->Buffer
[0] = '\\';
5549 CanonicalName
->Buffer
[1] = ';';
5550 CanonicalName
->Buffer
[2] = ':';
5551 CanonicalName
->Length
= 3 * sizeof(WCHAR
);
5552 RtlAppendUnicodeStringToString(CanonicalName
, &SessionIdString
);
5553 RtlAppendUnicodeStringToString(CanonicalName
, FileName
);
5555 DPRINT1("CanonicalName: %wZ\n", CanonicalName
);
5557 /* Otherwise, that's a simple copy */
5560 RtlCopyUnicodeString(CanonicalName
, FileName
);
5571 RxFreeCanonicalNameBuffer(
5572 PRX_CONTEXT Context
)
5574 /* These two buffers are always the same */
5575 ASSERT(Context
->Create
.CanonicalNameBuffer
== Context
->AlsoCanonicalNameBuffer
);
5577 if (Context
->Create
.CanonicalNameBuffer
!= NULL
)
5579 RxFreePoolWithTag(Context
->Create
.CanonicalNameBuffer
, RX_MISC_POOLTAG
);
5580 Context
->Create
.CanonicalNameBuffer
= NULL
;
5581 Context
->AlsoCanonicalNameBuffer
= NULL
;
5584 ASSERT(Context
->AlsoCanonicalNameBuffer
== NULL
);
5588 RxFsdCommonDispatch(
5589 PRX_FSD_DISPATCH_VECTOR DispatchVector
,
5590 UCHAR MajorFunction
,
5591 PIO_STACK_LOCATION Stack
,
5592 PFILE_OBJECT FileObject
,
5594 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
5598 PRX_CONTEXT Context
;
5599 UCHAR MinorFunction
;
5600 PFILE_OBJECT StackFileObject
;
5601 PRX_FSD_DISPATCH DispatchFunc
;
5602 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
5603 BOOLEAN TopLevel
, Closing
, PassToDriver
, SetCancelRoutine
, PostRequest
, CanWait
;
5605 Status
= STATUS_SUCCESS
;
5607 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector
, MajorFunction
, Stack
, FileObject
, Irp
, RxDeviceObject
);
5609 FsRtlEnterFileSystem();
5611 TopLevel
= RxTryToBecomeTheTopLevelIrp(&TopLevelContext
, Irp
, RxDeviceObject
, FALSE
);
5617 PostRequest
= FALSE
;
5618 SetCancelRoutine
= TRUE
;
5619 MinorFunction
= Stack
->MinorFunction
;
5621 switch (MajorFunction
)
5623 case IRP_MJ_FILE_SYSTEM_CONTROL
:
5624 if (FileObject
!= NULL
)
5626 CanWait
= IoIsOperationSynchronous(Irp
);
5636 case IRP_MJ_QUERY_INFORMATION
:
5637 case IRP_MJ_SET_INFORMATION
:
5638 case IRP_MJ_QUERY_EA
:
5640 case IRP_MJ_FLUSH_BUFFERS
:
5641 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
5642 case IRP_MJ_SET_VOLUME_INFORMATION
:
5643 case IRP_MJ_DIRECTORY_CONTROL
:
5644 case IRP_MJ_DEVICE_CONTROL
:
5645 case IRP_MJ_LOCK_CONTROL
:
5646 case IRP_MJ_QUERY_SECURITY
:
5647 case IRP_MJ_SET_SECURITY
:
5648 CanWait
= IoIsOperationSynchronous(Irp
);
5652 case IRP_MJ_CLEANUP
:
5654 SetCancelRoutine
= FALSE
;
5661 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
5662 /* Should we stop it right now, or mini-rdr deserves to know? */
5663 PassToDriver
= TRUE
;
5664 if (RxGetRdbssState(RxDeviceObject
) != RDBSS_STARTABLE
)
5666 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& !Closing
)
5668 PassToDriver
= FALSE
;
5669 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
5670 DPRINT1("Not started!\n");
5675 if (DispatchVector
!= RxDeviceFCBVector
&& (FileObject
->FileName
.Length
!= 0 || FileObject
->RelatedFileObject
!= NULL
))
5677 PassToDriver
= FALSE
;
5678 Status
= STATUS_REDIRECTOR_NOT_STARTED
;
5679 DPRINT1("Not started!\n");
5682 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
5684 StackFileObject
= Stack
->FileObject
;
5685 /* Make sure we don't deal with orphaned stuff */
5686 if (StackFileObject
!= NULL
&& StackFileObject
->FsContext
!= NULL
)
5688 if (StackFileObject
->FsContext2
!= UIntToPtr(DFS_OPEN_CONTEXT
) &&
5689 StackFileObject
->FsContext2
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
) &&
5690 StackFileObject
->FsContext
!= &RxDeviceFCB
)
5695 Fcb
= StackFileObject
->FsContext
;
5696 Fobx
= StackFileObject
->FsContext2
;
5698 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
) ||
5699 BooleanFlagOn(Fobx
->pSrvOpen
->Flags
, SRVOPEN_FLAG_ORPHANED
))
5703 PassToDriver
= TRUE
;
5707 PassToDriver
= FALSE
;
5708 Status
= STATUS_UNEXPECTED_NETWORK_ERROR
;
5709 DPRINT1("Operation on orphaned FCB: %p\n", Fcb
);
5715 /* Did we receive a close request whereas we're stopping? */
5716 if (RxGetRdbssState(RxDeviceObject
) == RDBSS_STOP_IN_PROGRESS
&& Closing
)
5720 Fcb
= StackFileObject
->FsContext
;
5722 DPRINT1("Close received after stop\n");
5723 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
5724 Irp
, Stack
->MajorFunction
, Stack
->MinorFunction
, StackFileObject
, Fcb
);
5726 if (Fcb
!= NULL
&& Fcb
!= &RxDeviceFCB
&&
5729 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
5730 Fcb
->OpenCount
, Fcb
->UncleanCount
, &Fcb
->FcbTableEntry
.Path
);
5734 /* Should we stop the whole thing now? */
5737 if (MajorFunction
!= IRP_MJ_DIRECTORY_CONTROL
|| MinorFunction
!= IRP_MN_REMOVE_DEVICE
)
5739 IoMarkIrpPending(Irp
);
5740 Irp
->IoStatus
.Status
= Status
;
5741 Irp
->IoStatus
.Information
= 0;
5742 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
5743 Status
= STATUS_PENDING
;
5747 Irp
->IoStatus
.Status
= Status
;
5748 Irp
->IoStatus
.Information
= 0;
5749 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
5755 /* No? Allocate a context to deal with the mini-rdr */
5756 Context
= RxCreateRxContext(Irp
, RxDeviceObject
, (CanWait
? RX_CONTEXT_FLAG_WAIT
: 0));
5757 if (Context
== NULL
)
5759 Status
= STATUS_INSUFFICIENT_RESOURCES
;
5760 RxCompleteRequest_Real(RxNull
, Irp
, STATUS_INSUFFICIENT_RESOURCES
);
5764 /* Set cancel routine if required */
5765 if (SetCancelRoutine
)
5767 IoAcquireCancelSpinLock(&OldIrql
);
5768 IoSetCancelRoutine(Irp
, RxCancelRoutine
);
5772 IoAcquireCancelSpinLock(&OldIrql
);
5773 IoSetCancelRoutine(Irp
, NULL
);
5775 IoReleaseCancelSpinLock(OldIrql
);
5777 ASSERT(MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
5779 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5780 Irp
->IoStatus
.Information
= 0;
5781 /* Get the dispatch routine */
5782 DispatchFunc
= DispatchVector
[MajorFunction
].CommonRoutine
;
5784 if (MajorFunction
== IRP_MJ_READ
|| MajorFunction
== IRP_MJ_WRITE
)
5786 /* Handle the complete MDL case */
5787 if (BooleanFlagOn(MinorFunction
, IRP_MN_COMPLETE
))
5789 DispatchFunc
= RxCompleteMdl
;
5793 /* Do we have to post request? */
5794 if (BooleanFlagOn(MinorFunction
, IRP_MN_DPC
))
5800 /* Our read function needs stack, make sure we won't overflow,
5801 * otherwise, post the request
5803 if (MajorFunction
== IRP_MJ_READ
)
5805 if (IoGetRemainingStackSize() < 0xE00)
5807 Context
->PendingReturned
= TRUE
;
5808 Status
= RxPostStackOverflowRead(Context
);
5809 if (Status
!= STATUS_PENDING
)
5811 Context
->PendingReturned
= FALSE
;
5812 RxCompleteAsynchronousRequest(Context
, Status
);
5822 Context
->ResumeRoutine
= DispatchFunc
;
5823 /* There's a dispatch routine? Time to dispatch! */
5824 if (DispatchFunc
!= NULL
)
5826 Context
->PendingReturned
= TRUE
;
5829 Status
= RxFsdPostRequest(Context
);
5833 /* Retry as long as we have */
5836 Status
= DispatchFunc(Context
);
5838 while (Status
== STATUS_RETRY
);
5840 if (Status
== STATUS_PENDING
)
5845 /* Sanity check: did someone mess with our context? */
5846 if (Context
->CurrentIrp
!= Irp
|| Context
->CurrentIrpSp
!= Stack
||
5847 Context
->MajorFunction
!= MajorFunction
|| Stack
->MinorFunction
!= MinorFunction
)
5849 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context
);
5850 DPRINT1("->CurrentIrp %p %p\n", Context
->CurrentIrp
, Irp
);
5851 DPRINT1("->CurrentIrpSp %p %p\n", Context
->CurrentIrpSp
, Stack
);
5852 DPRINT1("->MajorFunction %d %d\n", Context
->MajorFunction
, MajorFunction
);
5853 DPRINT1("->MinorFunction %d %d\n", Context
->MinorFunction
, MinorFunction
);
5855 Context
->PendingReturned
= FALSE
;
5856 Status
= RxCompleteAsynchronousRequest(Context
, Status
);
5861 Status
= STATUS_NOT_IMPLEMENTED
;
5868 RxUnwindTopLevelIrp(&TopLevelContext
);
5871 FsRtlExitFileSystem();
5875 DPRINT("RxFsdDispatch, Status: %lx\n", Status
);
5885 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
5889 PIO_STACK_LOCATION Stack
;
5890 PRX_FSD_DISPATCH_VECTOR DispatchVector
;
5894 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject
, Irp
);
5896 Stack
= IoGetCurrentIrpStackLocation(Irp
);
5898 /* Dispatch easy case */
5899 if (Stack
->MajorFunction
== IRP_MJ_SYSTEM_CONTROL
)
5901 return RxSystemControl(RxDeviceObject
, Irp
);
5904 /* Bail out broken cases */
5905 if (Stack
->MajorFunction
== IRP_MJ_CREATE_MAILSLOT
||
5906 Stack
->MajorFunction
== IRP_MJ_CREATE_NAMED_PIPE
)
5908 IoMarkIrpPending(Irp
);
5909 Irp
->IoStatus
.Information
= 0;
5910 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
5911 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
5912 return STATUS_PENDING
;
5915 /* Immediately handle create */
5916 if (Stack
->MajorFunction
== IRP_MJ_CREATE
)
5918 return RxFsdCommonDispatch(&RxFsdDispatchVector
[0], Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
5921 /* If not a creation, we must have at least a FO with a FCB */
5922 if (Stack
->FileObject
== NULL
|| Stack
->FileObject
->FsContext
== NULL
)
5924 IoMarkIrpPending(Irp
);
5925 Irp
->IoStatus
.Information
= 0;
5926 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
5927 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
5928 return STATUS_PENDING
;
5931 /* Set the dispatch vector if required */
5932 Fcb
= Stack
->FileObject
->FsContext
;
5933 if (!NodeTypeIsFcb(Fcb
) || Fcb
->PrivateDispatchVector
== NULL
)
5935 DispatchVector
= &RxFsdDispatchVector
[0];
5939 DispatchVector
= Fcb
->PrivateDispatchVector
;
5942 /* Device cannot accept such requests */
5943 if (RxDeviceObject
== RxFileSystemDeviceObject
)
5945 IoMarkIrpPending(Irp
);
5946 Irp
->IoStatus
.Information
= 0;
5947 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
5948 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
5949 return STATUS_PENDING
;
5952 /* Dispatch for real! */
5953 return RxFsdCommonDispatch(DispatchVector
, Stack
->MajorFunction
, Stack
, Stack
->FileObject
, Irp
, RxDeviceObject
);
5961 IN PRX_CONTEXT RxContext
)
5963 /* Initialize posting if required */
5964 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
5966 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
5969 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
5970 RxContext
->MinorFunction
, RxContext
,
5971 RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
5972 RxContext
->SerialNumber
);
5974 RxAddToWorkque(RxContext
, RxContext
->CurrentIrp
);
5975 return STATUS_PENDING
;
5987 WORK_QUEUE_TYPE Queue
;
5988 PRDBSS_DEVICE_OBJECT VolumeDO
;
5989 PRX_CONTEXT RxContext
, EntryContext
;
5993 RxContext
= Context
;
5994 EntryContext
= Context
;
5995 /* Save IRQL at entry for later checking */
5996 EntryIrql
= KeGetCurrentIrql();
5998 /* No FO, deal with device */
5999 if (RxContext
->CurrentIrpSp
->FileObject
!= NULL
)
6001 VolumeDO
= RxFileSystemDeviceObject
;
6008 /* Which queue to used for delayed? */
6009 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
))
6011 Queue
= DelayedWorkQueue
;
6015 ASSERT(BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
6016 Queue
= CriticalWorkQueue
;
6023 BOOLEAN RecursiveCall
;
6024 RX_TOPLEVELIRP_CONTEXT TopLevelContext
;
6026 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
6027 ASSERT(!RxContext
->PostRequest
);
6029 RxContext
->LastExecutionThread
= PsGetCurrentThread();
6030 SetFlag(RxContext
->Flags
, (RX_CONTEXT_FLAG_IN_FSP
| RX_CONTEXT_FLAG_WAIT
));
6032 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx", RxContext
->MinorFunction
,
6033 RxContext
, RxContext
->CurrentIrp
, RxContext
->LastExecutionThread
,
6034 RxContext
->SerialNumber
);
6036 Irp
= RxContext
->CurrentIrp
;
6038 FsRtlEnterFileSystem();
6040 RecursiveCall
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
);
6041 RxTryToBecomeTheTopLevelIrp(&TopLevelContext
,
6042 (RecursiveCall
? (PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
: RxContext
->CurrentIrp
),
6043 RxContext
->RxDeviceObject
, TRUE
);
6045 ASSERT(RxContext
->ResumeRoutine
!= NULL
);
6047 if (BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_DPC
) && Irp
->Tail
.Overlay
.Thread
== NULL
)
6049 ASSERT((RxContext
->MajorFunction
== IRP_MJ_WRITE
) || (RxContext
->MajorFunction
== IRP_MJ_READ
));
6050 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
6053 /* Call the resume routine */
6058 NoComplete
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP
);
6060 Status
= RxContext
->ResumeRoutine(RxContext
);
6061 if (!NoComplete
&& Status
!= STATUS_PENDING
)
6063 if (Status
!= STATUS_RETRY
)
6065 Status
= RxCompleteRequest(RxContext
, Status
);
6069 while (Status
== STATUS_RETRY
);
6071 RxUnwindTopLevelIrp(&TopLevelContext
);
6072 FsRtlExitFileSystem();
6074 if (VolumeDO
!= NULL
)
6076 RxContext
= RxRemoveOverflowEntry(VolumeDO
, Queue
);
6082 } while (RxContext
!= NULL
);
6084 /* Did we mess with IRQL? */
6085 if (KeGetCurrentIrql() >= APC_LEVEL
)
6087 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext
, EntryIrql
);
6095 RxGetNetworkProviderPriority(
6096 PUNICODE_STRING DeviceName
)
6107 RxGetRegistryParameters(
6108 IN PUNICODE_STRING RegistryPath
)
6112 UCHAR Buffer
[0x400];
6113 HANDLE DriverHandle
, KeyHandle
;
6114 UNICODE_STRING KeyName
, OutString
;
6115 OBJECT_ATTRIBUTES ObjectAttributes
;
6119 InitializeObjectAttributes(&ObjectAttributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
6120 Status
= ZwOpenKey(&DriverHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6121 if (!NT_SUCCESS(Status
))
6126 RtlInitUnicodeString(&KeyName
, L
"Parameters");
6127 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DriverHandle
, FALSE
);
6128 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
6129 if (NT_SUCCESS(Status
))
6131 /* The only parameter we deal with is InitialDebugString */
6132 RxGetStringRegistryParameter(KeyHandle
, L
"InitialDebugString", &OutString
, Buffer
, sizeof(Buffer
), 0);
6133 if (OutString
.Length
!= 0 && OutString
.Length
< 0x140)
6138 Read
= OutString
.Buffer
;
6139 Write
= (PSTR
)OutString
.Buffer
;
6140 for (i
= 0; i
< OutString
.Length
; ++i
)
6148 /* Which is a string we'll just write out */
6149 DPRINT("InitialDebugString read from registry: '%s'\n", OutString
.Buffer
);
6150 RxDebugControlCommand((PSTR
)OutString
.Buffer
);
6156 ZwClose(DriverHandle
);
6164 IN PIO_STACK_LOCATION IrpSp
)
6167 PACCESS_TOKEN Token
;
6168 PIO_SECURITY_CONTEXT SecurityContext
;
6172 /* If that's not a prefix claim, not an open request, session id will be 0 */
6173 if (IrpSp
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
|| IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_REDIR_QUERY_PATH
)
6175 if (IrpSp
->MajorFunction
!= IRP_MJ_CREATE
|| IrpSp
->Parameters
.Create
.SecurityContext
== NULL
)
6180 SecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
6184 SecurityContext
= ((PQUERY_PATH_REQUEST
)IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
)->SecurityContext
;
6187 /* Query the session id */
6188 Token
= SeQuerySubjectContextToken(&SecurityContext
->AccessState
->SubjectSecurityContext
);
6189 SeQuerySessionIdToken(Token
, &SessionId
);
6199 RxGetStringRegistryParameter(
6200 IN HANDLE KeyHandle
,
6202 OUT PUNICODE_STRING OutString
,
6204 IN ULONG BufferLength
,
6205 IN BOOLEAN LogFailure
)
6209 UNICODE_STRING KeyString
;
6213 RtlInitUnicodeString(&KeyString
, KeyName
);
6214 Status
= ZwQueryValueKey(KeyHandle
, &KeyString
, KeyValuePartialInformation
, Buffer
, BufferLength
, &ResultLength
);
6215 OutString
->Length
= 0;
6216 OutString
->Buffer
= 0;
6217 if (!NT_SUCCESS(Status
))
6221 RxLogFailure(RxFileSystemDeviceObject
, NULL
, 0x80000BD3, Status
);
6227 OutString
->Buffer
= (PWSTR
)(((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->Data
);
6228 OutString
->Length
= ((PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
)->DataLength
- sizeof(UNICODE_NULL
);
6229 OutString
->MaximumLength
= OutString
->Length
;
6231 return STATUS_SUCCESS
;
6237 PRDBSS_DEVICE_OBJECT
6238 RxGetTopDeviceObjectIfRdbssIrp(
6242 PRDBSS_DEVICE_OBJECT TopDevice
= NULL
;
6244 TopLevelIrp
= IoGetTopLevelIrp();
6245 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6247 TopDevice
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->RxDeviceObject
;
6257 RxGetTopIrpIfRdbssIrp(
6261 PRX_TOPLEVELIRP_CONTEXT TopLevel
;
6263 TopLevel
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
6264 if (RxIsThisAnRdbssTopLevelContext(TopLevel
))
6266 Irp
= TopLevel
->Irp
;
6277 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
)
6280 PACCESS_TOKEN Token
;
6284 Token
= SeQuerySubjectContextToken(SubjectSecurityContext
);
6285 SeQueryAuthenticationIdToken(Token
, &Luid
);
6292 RxIndicateChangeOfBufferingStateForSrvOpen(
6293 PMRX_SRV_CALL SrvCall
,
6294 PMRX_SRV_OPEN SrvOpen
,
6303 RxInitializeDebugSupport(
6314 RxInitializeDispatchVectors(
6315 PDRIVER_OBJECT DriverObject
)
6321 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
6323 DriverObject
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)RxFsdDispatch
;
6326 RxDeviceFCB
.PrivateDispatchVector
= RxDeviceFCBVector
;
6327 ASSERT(RxFsdDispatchVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6328 ASSERT(RxDeviceFCBVector
[IRP_MJ_MAXIMUM_FUNCTION
].CommonRoutine
!= NULL
);
6330 DriverObject
->FastIoDispatch
= &RxFastIoDispatch
;
6331 RxFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(RxFastIoDispatch
);
6332 RxFastIoDispatch
.FastIoCheckIfPossible
= RxFastIoCheckIfPossible
;
6333 RxFastIoDispatch
.FastIoRead
= RxFastIoRead
;
6334 RxFastIoDispatch
.FastIoWrite
= RxFastIoWrite
;
6335 RxFastIoDispatch
.FastIoQueryBasicInfo
= NULL
;
6336 RxFastIoDispatch
.FastIoQueryStandardInfo
= NULL
;
6337 RxFastIoDispatch
.FastIoLock
= NULL
;
6338 RxFastIoDispatch
.FastIoUnlockSingle
= NULL
;
6339 RxFastIoDispatch
.FastIoUnlockAll
= NULL
;
6340 RxFastIoDispatch
.FastIoUnlockAllByKey
= NULL
;
6341 RxFastIoDispatch
.FastIoDeviceControl
= RxFastIoDeviceControl
;
6342 RxFastIoDispatch
.AcquireFileForNtCreateSection
= RxAcquireFileForNtCreateSection
;
6343 RxFastIoDispatch
.ReleaseFileForNtCreateSection
= RxReleaseFileForNtCreateSection
;
6344 RxFastIoDispatch
.AcquireForCcFlush
= RxAcquireForCcFlush
;
6345 RxFastIoDispatch
.ReleaseForCcFlush
= RxReleaseForCcFlush
;
6347 RxInitializeTopLevelIrpPackage();
6349 RxData
.CacheManagerCallbacks
.AcquireForLazyWrite
= RxAcquireFcbForLazyWrite
;
6350 RxData
.CacheManagerCallbacks
.ReleaseFromLazyWrite
= RxReleaseFcbFromLazyWrite
;
6351 RxData
.CacheManagerCallbacks
.AcquireForReadAhead
= RxAcquireFcbForReadAhead
;
6352 RxData
.CacheManagerCallbacks
.ReleaseFromReadAhead
= RxReleaseFcbFromReadAhead
;
6354 RxData
.CacheManagerNoOpCallbacks
.AcquireForLazyWrite
= RxNoOpAcquire
;
6355 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromLazyWrite
= RxNoOpRelease
;
6356 RxData
.CacheManagerNoOpCallbacks
.AcquireForReadAhead
= RxNoOpAcquire
;
6357 RxData
.CacheManagerNoOpCallbacks
.ReleaseFromReadAhead
= RxNoOpRelease
;
6366 return STATUS_NOT_IMPLEMENTED
;
6373 RxInitializeMinirdrDispatchTable(
6374 IN PDRIVER_OBJECT DriverObject
)
6384 RxInitializeRegistrationStructures(
6389 ExInitializeFastMutex(&RxData
.MinirdrRegistrationMutex
);
6390 RxData
.NumberOfMinirdrsRegistered
= 0;
6391 RxData
.NumberOfMinirdrsStarted
= 0;
6392 InitializeListHead(&RxData
.RegisteredMiniRdrs
);
6394 return STATUS_SUCCESS
;
6402 RxInitializeTopLevelIrpPackage(
6405 KeInitializeSpinLock(&TopLevelIrpSpinLock
);
6406 InitializeListHead(&TopLevelIrpAllocatedContextsList
);
6412 PDRIVER_OBJECT DriverObject
,
6422 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6423 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6426 PLIST_ENTRY NextEntry
;
6427 BOOLEAN Found
= FALSE
;
6428 PRX_TOPLEVELIRP_CONTEXT ListContext
;
6430 /* Browse all the allocated TLC to find ours */
6431 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
6432 for (NextEntry
= TopLevelIrpAllocatedContextsList
.Flink
;
6433 NextEntry
!= &TopLevelIrpAllocatedContextsList
;
6434 NextEntry
= NextEntry
->Flink
)
6436 ListContext
= CONTAINING_RECORD(NextEntry
, RX_TOPLEVELIRP_CONTEXT
, ListEntry
);
6437 ASSERT(ListContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
6438 ASSERT(BooleanFlagOn(ListContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
6441 if (ListContext
== TopLevelContext
)
6447 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
6461 /* No associated SRV_OPEN, it's OK to purge */
6462 if (IsListEmpty(&Fcb
->SrvOpenList
))
6467 /* Only allow to purge if all the associated SRV_OPEN
6468 * - have no outstanding opens ongoing
6469 * - have only read attribute set
6471 for (Entry
= Fcb
->SrvOpenList
.Flink
;
6472 Entry
!= &Fcb
->SrvOpenList
;
6473 Entry
= Entry
->Flink
)
6477 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenQLinks
);
6479 /* Failing previous needs, don't allow purge */
6480 if (SrvOpen
->UncleanFobxCount
!= 0 ||
6481 (SrvOpen
->DesiredAccess
& 0xFFEFFFFF) != FILE_READ_ATTRIBUTES
)
6487 /* All correct, allow purge */
6495 RxIsThisAnRdbssTopLevelContext(
6496 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
6498 ULONG_PTR StackTop
, StackBottom
;
6500 /* Bail out for flags */
6501 if ((ULONG_PTR
)TopLevelContext
<= FSRTL_FAST_IO_TOP_LEVEL_IRP
)
6506 /* Is our provided TLC allocated on stack? */
6507 IoGetStackLimits(&StackTop
, &StackBottom
);
6508 if ((ULONG_PTR
)TopLevelContext
<= StackBottom
- sizeof(RX_TOPLEVELIRP_CONTEXT
) &&
6509 (ULONG_PTR
)TopLevelContext
>= StackTop
)
6511 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6512 if (!BooleanFlagOn((ULONG_PTR
)TopLevelContext
, 0x3) && TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
)
6520 /* No, use the helper function */
6521 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext
);
6528 RxIsThisTheTopLevelIrp(
6533 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6534 TopLevelIrp
= IoGetTopLevelIrp();
6535 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
))
6537 TopLevelIrp
= ((PRX_TOPLEVELIRP_CONTEXT
)TopLevelIrp
)->Irp
;
6540 return (TopLevelIrp
== Irp
);
6545 RxLockOperationCompletion(
6550 return STATUS_NOT_IMPLEMENTED
;
6559 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6560 IN PUNICODE_STRING OriginatorId
,
6565 PUNICODE_STRING Originator
= OriginatorId
;
6566 LARGE_INTEGER LargeLine
;
6568 /* Set optional parameters */
6569 LargeLine
.QuadPart
= Line
;
6570 if (OriginatorId
== NULL
|| OriginatorId
->Length
== 0)
6572 Originator
= (PUNICODE_STRING
)&unknownId
;
6576 RxLogEventWithAnnotation(DeviceObject
, EventId
, Status
, &LargeLine
, sizeof(LargeLine
), Originator
, 1);
6581 RxLogEventWithAnnotation(
6582 IN PRDBSS_DEVICE_OBJECT DeviceObject
,
6585 IN PVOID DataBuffer
,
6586 IN USHORT DataBufferLength
,
6587 IN PUNICODE_STRING Annotation
,
6588 IN ULONG AnnotationCount
)
6596 PRX_CONTEXT RxContext
)
6599 return STATUS_NOT_IMPLEMENTED
;
6607 RxLowIoIoCtlShellCompletion(
6608 PRX_CONTEXT RxContext
)
6615 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext
);
6617 Irp
= RxContext
->CurrentIrp
;
6618 Status
= RxContext
->IoStatusBlock
.Status
;
6620 /* Set information and status */
6621 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
6623 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6626 Irp
->IoStatus
.Status
= Status
;
6632 RxLowIoLockControlShell(
6633 IN PRX_CONTEXT RxContext
)
6636 return STATUS_NOT_IMPLEMENTED
;
6644 RxLowIoNotifyChangeDirectoryCompletion(
6645 PRX_CONTEXT RxContext
)
6649 DPRINT("Completing NCD with: %lx, %lx\n", RxContext
->IoStatusBlock
.Status
, RxContext
->IoStatusBlock
.Information
);
6651 /* Just copy back the IO_STATUS to the IRP */
6652 RxSetIoStatusStatus(RxContext
, RxContext
->IoStatusBlock
.Status
);
6653 RxSetIoStatusInfo(RxContext
, RxContext
->IoStatusBlock
.Information
);
6655 return RxContext
->IoStatusBlock
.Status
;
6663 PRX_CONTEXT RxContext
)
6670 DPRINT("RxLowIoReadShell(%p)\n", RxContext
);
6672 Fcb
= (PFCB
)RxContext
->pFcb
;
6673 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
6675 return STATUS_MORE_PROCESSING_REQUIRED
;
6678 /* Always update stats for disks */
6679 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
6681 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkReadBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
6684 /* And forward the read to the mini-rdr */
6685 Status
= RxLowIoSubmit(RxContext
, RxLowIoReadShellCompletion
);
6686 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext
, Status
);
6693 RxLowIoReadShellCompletion(
6694 PRX_CONTEXT RxContext
)
6699 BOOLEAN PagingIo
, IsPipe
;
6700 PIO_STACK_LOCATION Stack
;
6701 PLOWIO_CONTEXT LowIoContext
;
6705 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext
);
6707 Status
= RxContext
->IoStatusBlock
.Status
;
6708 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
6710 Irp
= RxContext
->CurrentIrp
;
6711 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
6713 /* Set IRP information from the RX_CONTEXT status block */
6714 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6716 /* Fixup status for paging file if nothing was read */
6719 if (NT_SUCCESS(Status
) && RxContext
->IoStatusBlock
.Information
== 0)
6721 Status
= STATUS_END_OF_FILE
;
6725 LowIoContext
= &RxContext
->LowIoContext
;
6726 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
6728 /* Check broken cases that should never happen */
6729 Fcb
= (PFCB
)RxContext
->pFcb
;
6730 if (Status
== STATUS_FILE_LOCK_CONFLICT
)
6732 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED
))
6735 return STATUS_RETRY
;
6738 else if (Status
== STATUS_SUCCESS
)
6740 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_RECURSIVE_CALL
))
6742 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
) ||
6743 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
))
6749 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
))
6755 /* Readahead should go through Cc and not finish here */
6756 ASSERT(!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_READAHEAD
));
6758 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
6759 if (BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
6764 Stack
= RxContext
->CurrentIrpSp
;
6765 IsPipe
= BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
);
6766 /* Release lock if required */
6769 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
6773 /* Set FastIo if read was a success */
6774 if (NT_SUCCESS(Status
) && !IsPipe
)
6776 SetFlag(Stack
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
6779 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
6781 RxResumeBlockedOperations_Serially(RxContext
, &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.ReadSerializationQueue
);
6785 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
6794 /* Final sanity checks */
6795 ASSERT(Status
!= STATUS_RETRY
);
6796 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Read
.Length
);
6797 ASSERT(RxContext
->MajorFunction
== IRP_MJ_READ
);
6807 IN PRX_CONTEXT RxContext
)
6814 DPRINT("RxLowIoWriteShell(%p)\n", RxContext
);
6816 Fcb
= (PFCB
)RxContext
->pFcb
;
6818 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
6819 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
6821 /* Always update stats for disks */
6822 if (Fcb
->CachedNetRootType
== NET_ROOT_DISK
)
6824 ExInterlockedAddLargeStatistic(&RxContext
->RxDeviceObject
->NetworkWriteBytesRequested
, RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
);
6827 /* And forward the write to the mini-rdr */
6828 Status
= RxLowIoSubmit(RxContext
, RxLowIoWriteShellCompletion
);
6829 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext
, Status
);
6836 RxLowIoWriteShellCompletion(
6837 PRX_CONTEXT RxContext
)
6843 PLOWIO_CONTEXT LowIoContext
;
6847 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext
);
6849 Status
= RxContext
->IoStatusBlock
.Status
;
6850 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext
, Status
, RxContext
->IoStatusBlock
.Information
);
6852 Irp
= RxContext
->CurrentIrp
;
6854 /* Set IRP information from the RX_CONTEXT status block */
6855 Irp
->IoStatus
.Information
= RxContext
->IoStatusBlock
.Information
;
6857 LowIoContext
= &RxContext
->LowIoContext
;
6858 ASSERT(RxLowIoIsBufferLocked(LowIoContext
));
6860 /* Perform a few sanity checks */
6861 Fcb
= (PFCB
)RxContext
->pFcb
;
6862 if (Status
== STATUS_SUCCESS
)
6864 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED
))
6866 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_BUF_COMPRESSED
) &&
6867 !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_DISK_COMPRESSED
));
6870 ASSERT(!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILE_IS_SHADOWED
));
6873 PagingIo
= BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
6874 if (Status
!= STATUS_SUCCESS
&& PagingIo
)
6876 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb
, Fcb
->NetRoot
, Status
);
6879 /* In case of async call, perform last bits not done in RxCommonWrite */
6880 if (!BooleanFlagOn(LowIoContext
->Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
6882 PFILE_OBJECT FileObject
;
6883 PIO_STACK_LOCATION Stack
;
6885 /* We only succeed if we wrote what was asked for */
6886 if (NT_SUCCESS(Status
) && !BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
6888 ASSERT(Irp
->IoStatus
.Information
== LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
6891 /* If write succeed, ,also update FILE_OBJECT flags */
6892 Stack
= RxContext
->CurrentIrpSp
;
6893 FileObject
= Stack
->FileObject
;
6896 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
6899 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE
))
6901 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
6904 /* If VDL was extended, fix attributes */
6905 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_EXTENDING_VDL
))
6907 LONGLONG LastOffset
, FileSize
;
6909 LastOffset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
+
6910 Irp
->IoStatus
.Information
;
6911 RxGetFileSizeWithLock(Fcb
, &FileSize
);
6913 if (FileSize
< LastOffset
)
6915 LastOffset
= FileSize
;
6918 Fcb
->Header
.ValidDataLength
.QuadPart
= LastOffset
;
6921 /* One less outstanding write */
6922 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
6924 PNON_PAGED_FCB NonPagedFcb
;
6926 NonPagedFcb
= LowIoContext
->ParamsFor
.ReadWrite
.NonPagedFcb
;
6927 if (NonPagedFcb
!= NULL
)
6929 if (ExInterlockedAddUlong(&NonPagedFcb
->OutstandingAsyncWrites
,
6930 -1, &RxStrucSupSpinLock
) == 1)
6932 KeSetEvent(NonPagedFcb
->OutstandingAsyncEvent
, IO_NO_INCREMENT
, FALSE
);
6937 /* Release paging resource if acquired */
6938 if (RxContext
->FcbPagingIoResourceAcquired
)
6940 RxReleasePagingIoResourceForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
6943 /* Resume blocked operations for pipes */
6944 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
6946 RxResumeBlockedOperations_Serially(RxContext
,
6947 &((PFOBX
)RxContext
->pFobx
)->Specific
.NamedPipe
.WriteSerializationQueue
);
6951 /* And release FCB only for files */
6952 if (RxContext
->FcbResourceAcquired
)
6954 RxReleaseFcbForThread(RxContext
, Fcb
, LowIoContext
->ResourceThreadId
);
6958 /* Final sanity checks */
6959 ASSERT(Status
!= STATUS_RETRY
);
6960 ASSERT((Status
!= STATUS_SUCCESS
) || (Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
));
6961 ASSERT(RxContext
->MajorFunction
== IRP_MJ_WRITE
);
6963 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION
))
6976 RxNotifyChangeDirectory(
6977 PRX_CONTEXT RxContext
)
6981 PIO_STACK_LOCATION Stack
;
6985 /* The IRP can abviously wait */
6986 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
6988 /* Initialize its lowio */
6989 RxInitializeLowIoContext(&RxContext
->LowIoContext
, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
);
6993 /* Lock user buffer */
6994 Stack
= RxContext
->CurrentIrpSp
;
6995 RxLockUserBuffer(RxContext
, IoWriteAccess
, Stack
->Parameters
.NotifyDirectory
.Length
);
6997 /* Copy parameters from IO_STACK */
6998 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.WatchTree
= BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
);
6999 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.CompletionFilter
= Stack
->Parameters
.NotifyDirectory
.CompletionFilter
;
7000 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.NotificationBufferLength
= Stack
->Parameters
.NotifyDirectory
.Length
;
7002 /* If we have an associated MDL */
7003 Irp
= RxContext
->CurrentIrp
;
7004 if (Irp
->MdlAddress
!= NULL
)
7006 /* Then, call mini-rdr */
7007 RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
7008 if (RxContext
->LowIoContext
.ParamsFor
.NotifyChangeDirectory
.pNotificationBuffer
!= NULL
)
7010 Status
= RxLowIoSubmit(RxContext
, RxLowIoNotifyChangeDirectoryCompletion
);
7014 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7019 Status
= STATUS_INVALID_PARAMETER
;
7032 RxPostStackOverflowRead (
7033 IN PRX_CONTEXT RxContext
)
7038 return STATUS_NOT_IMPLEMENTED
;
7045 RxpPrepareCreateContextForReuse(
7046 PRX_CONTEXT RxContext
)
7048 /* Reuse can only happen for open operations (STATUS_RETRY) */
7049 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7051 /* Release the FCB if it was acquired */
7052 if (RxContext
->Create
.FcbAcquired
)
7054 RxReleaseFcb(RxContext
, RxContext
->pFcb
);
7055 RxContext
->Create
.FcbAcquired
= FALSE
;
7058 /* Free the canonical name */
7059 RxFreeCanonicalNameBuffer(RxContext
);
7061 /* If we have a VNetRoot associated */
7062 if (RxContext
->Create
.pVNetRoot
!= NULL
|| RxContext
->Create
.NetNamePrefixEntry
!= NULL
)
7064 /* Remove our link and thus, dereference the VNetRoot */
7065 RxpAcquirePrefixTableLockShared(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
, TRUE
);
7066 if (RxContext
->Create
.pVNetRoot
!= NULL
)
7068 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
, TRUE
);
7069 RxContext
->Create
.pVNetRoot
= NULL
;
7071 RxpReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
7074 DPRINT("RxContext: %p prepared for reuse\n", RxContext
);
7081 RxpQueryInfoMiniRdr(
7082 PRX_CONTEXT RxContext
,
7083 FILE_INFORMATION_CLASS FileInfoClass
,
7089 Fcb
= (PFCB
)RxContext
->pFcb
;
7091 /* Set the RX_CONTEXT */
7092 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7093 RxContext
->Info
.Buffer
= Buffer
;
7096 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryFileInfo
, (RxContext
));
7106 IN PRX_CONTEXT RxContext
)
7110 NET_ROOT_TYPE NetRootType
;
7111 UNICODE_STRING CanonicalName
, FileName
, NetRootName
;
7115 Irp
= RxContext
->CurrentIrp
;
7117 /* This has to come from MUP */
7118 if (Irp
->RequestorMode
== UserMode
)
7120 return STATUS_INVALID_DEVICE_REQUEST
;
7123 if (RxContext
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
7125 PQUERY_PATH_REQUEST QueryRequest
;
7127 /* Get parameters */
7128 QueryRequest
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7130 /* Don't overflow allocation */
7131 if (QueryRequest
->PathNameLength
>= MAXUSHORT
- 1)
7133 return STATUS_INVALID_DEVICE_REQUEST
;
7136 /* Forcefully rewrite IRP MJ */
7137 RxContext
->MajorFunction
= IRP_MJ_CREATE
;
7139 /* Fake canon name */
7140 RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
, QueryRequest
->PathNameLength
, RX_MISC_POOLTAG
);
7141 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
== NULL
)
7143 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7147 /* Copy the prefix to look for */
7148 RtlCopyMemory(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, &QueryRequest
->FilePathName
[0], QueryRequest
->PathNameLength
);
7149 RxContext
->PrefixClaim
.SuppliedPathName
.Length
= QueryRequest
->PathNameLength
;
7150 RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
= QueryRequest
->PathNameLength
;
7152 /* Zero the create parameters */
7153 RtlZeroMemory(&RxContext
->Create
.NtCreateParameters
,
7154 FIELD_OFFSET(RX_CONTEXT
, AlsoCanonicalNameBuffer
) - FIELD_OFFSET(RX_CONTEXT
, Create
.NtCreateParameters
));
7155 RxContext
->Create
.ThisIsATreeConnectOpen
= TRUE
;
7156 RxContext
->Create
.NtCreateParameters
.SecurityContext
= QueryRequest
->SecurityContext
;
7160 /* If not devcontrol, it comes from open, name was already copied */
7161 ASSERT(RxContext
->MajorFunction
== IRP_MJ_CREATE
);
7162 ASSERT(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
);
7165 /* Canonilize name */
7166 NetRootType
= NET_ROOT_WILD
;
7167 RtlInitEmptyUnicodeString(&CanonicalName
, NULL
, 0);
7168 FileName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7169 FileName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7170 FileName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7171 NetRootName
.Length
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
;
7172 NetRootName
.MaximumLength
= RxContext
->PrefixClaim
.SuppliedPathName
.MaximumLength
;
7173 NetRootName
.Buffer
= RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
;
7174 Status
= RxFirstCanonicalize(RxContext
, &FileName
, &CanonicalName
, &NetRootType
);
7175 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7176 if (NT_SUCCESS(Status
))
7178 Status
= RxFindOrConstructVirtualNetRoot(RxContext
, &CanonicalName
, NetRootType
, &NetRootName
);
7180 if (Status
== STATUS_PENDING
)
7185 if (NT_SUCCESS(Status
))
7187 PQUERY_PATH_RESPONSE QueryResponse
;
7189 /* We accept the length that was canon (minus netroot) */
7190 QueryResponse
= RxContext
->CurrentIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
7191 QueryResponse
->LengthAccepted
= RxContext
->PrefixClaim
.SuppliedPathName
.Length
- NetRootName
.Length
;
7195 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7196 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7198 if (RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
!= NULL
)
7200 RxFreePoolWithTag(RxContext
->PrefixClaim
.SuppliedPathName
.Buffer
, RX_MISC_POOLTAG
);
7203 RxpPrepareCreateContextForReuse(RxContext
);
7205 RxContext
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
7213 RxPrepareToReparseSymbolicLink(
7214 PRX_CONTEXT RxContext
,
7215 BOOLEAN SymbolicLinkEmbeddedInOldPath
,
7216 PUNICODE_STRING NewPath
,
7217 BOOLEAN NewPathIsAbsolute
,
7218 PBOOLEAN ReparseRequired
)
7221 return STATUS_NOT_IMPLEMENTED
;
7232 LOCK_OPERATION Lock
;
7233 PIO_STACK_LOCATION Stack
;
7234 PRX_CONTEXT RxContext
= Context
;
7236 /* NULL IRP is no option */
7242 /* Check whether preparation was really needed */
7243 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
))
7247 /* Mark the context as prepared */
7248 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
);
7250 /* Just lock the user buffer, with the correct length, depending on the MJ */
7251 Lock
= IoReadAccess
;
7252 Stack
= RxContext
->CurrentIrpSp
;
7253 if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
7255 if (!BooleanFlagOn(RxContext
->MinorFunction
, IRP_MN_MDL
))
7257 if (RxContext
->MajorFunction
== IRP_MJ_READ
)
7259 Lock
= IoWriteAccess
;
7261 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.Read
.Length
);
7266 if ((RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) ||
7267 RxContext
->MajorFunction
== IRP_MJ_QUERY_EA
)
7269 Lock
= IoWriteAccess
;
7270 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.QueryDirectory
.Length
);
7272 else if (RxContext
->MajorFunction
== IRP_MJ_SET_EA
)
7274 RxLockUserBuffer(RxContext
, Lock
, Stack
->Parameters
.SetEa
.Length
);
7278 /* As it will be posted (async), mark the IRP pending */
7279 IoMarkIrpPending(Irp
);
7284 RxpUnregisterMinirdr(
7285 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7296 PRX_CONTEXT LocalContext
)
7303 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7305 /* And force close */
7306 RxReleaseFcb(NULL
, Fcb
);
7307 MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7308 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
7309 ASSERT(Status
== STATUS_SUCCESS
);
7313 RxQueryAlternateNameInfo(
7314 PRX_CONTEXT RxContext
,
7315 PFILE_NAME_INFORMATION AltNameInfo
)
7318 return STATUS_NOT_IMPLEMENTED
;
7326 PRX_CONTEXT RxContext
,
7327 PFILE_BASIC_INFORMATION BasicInfo
)
7331 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext
, BasicInfo
);
7333 /* Simply zero and forward to mini-rdr */
7334 RtlZeroMemory(BasicInfo
, sizeof(FILE_BASIC_INFORMATION
));
7335 return RxpQueryInfoMiniRdr(RxContext
, FileBasicInformation
, BasicInfo
);
7339 RxQueryCompressedInfo(
7340 PRX_CONTEXT RxContext
,
7341 PFILE_COMPRESSION_INFORMATION CompressionInfo
)
7344 return STATUS_NOT_IMPLEMENTED
;
7352 PRX_CONTEXT RxContext
)
7359 BOOLEAN LockNotGranted
;
7360 ULONG Length
, FileIndex
;
7361 PUNICODE_STRING FileName
;
7362 PIO_STACK_LOCATION Stack
;
7363 FILE_INFORMATION_CLASS FileInfoClass
;
7367 DPRINT("RxQueryDirectory(%p)\n", RxContext
);
7369 /* Get parameters */
7370 Stack
= RxContext
->CurrentIrpSp
;
7371 Length
= Stack
->Parameters
.QueryDirectory
.Length
;
7372 FileName
= Stack
->Parameters
.QueryDirectory
.FileName
;
7373 FileInfoClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
7374 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7375 FlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
), Length
,
7376 FileName
, FileInfoClass
);
7378 Irp
= RxContext
->CurrentIrp
;
7379 Flags
= Stack
->Flags
;
7380 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
7381 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex
, Irp
->UserBuffer
, Flags
);
7383 if (FileName
!= NULL
)
7385 DPRINT("FileName: %wZ\n", FileName
);
7388 /* No FOBX: not a standard file/directory */
7389 Fobx
= (PFOBX
)RxContext
->pFobx
;
7392 return STATUS_OBJECT_NAME_INVALID
;
7395 /* We can only deal with a disk */
7396 Fcb
= (PFCB
)RxContext
->pFcb
;
7397 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
7399 DPRINT1("Not a disk! %x\n", Fcb
->pNetRoot
->Type
);
7400 return STATUS_INVALID_DEVICE_REQUEST
;
7403 /* Setup RX_CONTEXT related fields */
7404 RxContext
->QueryDirectory
.FileIndex
= FileIndex
;
7405 RxContext
->QueryDirectory
.RestartScan
= BooleanFlagOn(Flags
, SL_RESTART_SCAN
);
7406 RxContext
->QueryDirectory
.ReturnSingleEntry
= BooleanFlagOn(Flags
, SL_RETURN_SINGLE_ENTRY
);
7407 RxContext
->QueryDirectory
.IndexSpecified
= BooleanFlagOn(Flags
, SL_INDEX_SPECIFIED
);
7408 RxContext
->QueryDirectory
.InitialQuery
= (Fobx
->UnicodeQueryTemplate
.Buffer
== NULL
) && !BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7410 /* We don't support (yet?) a specific index being set */
7411 if (RxContext
->QueryDirectory
.IndexSpecified
)
7413 return STATUS_NOT_IMPLEMENTED
;
7416 /* Try to lock FCB */
7417 LockNotGranted
= TRUE
;
7418 if (RxContext
->QueryDirectory
.InitialQuery
)
7420 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7421 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7423 if (!NT_SUCCESS(Status
))
7428 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7430 RxContext
->QueryDirectory
.InitialQuery
= FALSE
;
7431 RxConvertToSharedFcb(RxContext
, Fcb
);
7434 LockNotGranted
= FALSE
;
7439 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
7440 if (Status
!= STATUS_LOCK_NOT_GRANTED
)
7442 if (!NT_SUCCESS(Status
))
7447 LockNotGranted
= FALSE
;
7451 /* If it failed, post request */
7454 return RxFsdPostRequest(RxContext
);
7457 /* This cannot be done on a orphaned directory */
7458 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
7460 RxReleaseFcb(RxContext
, Fcb
);
7461 return STATUS_FILE_CLOSED
;
7467 if (!RxContext
->QueryDirectory
.IndexSpecified
&& RxContext
->QueryDirectory
.RestartScan
)
7469 RxContext
->QueryDirectory
.FileIndex
= 0;
7472 /* Assume success */
7473 Status
= STATUS_SUCCESS
;
7474 /* If initial query, prepare FOBX */
7475 if (RxContext
->QueryDirectory
.InitialQuery
)
7477 /* We cannot have a template already! */
7478 ASSERT(!BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
));
7480 /* If we have a file name and a correct one, duplicate it in the FOBX */
7481 if (FileName
!= NULL
&& FileName
->Length
!= 0 && FileName
->Buffer
!= NULL
&&
7482 (FileName
->Length
!= sizeof(WCHAR
) || FileName
->Buffer
[0] != '*') &&
7483 (FileName
->Length
!= 12 * sizeof(WCHAR
) ||
7484 RtlCompareMemory(FileName
->Buffer
, Rx8QMdot3QM
, 12 * sizeof(WCHAR
)) != 12 * sizeof(WCHAR
)))
7486 Fobx
->ContainsWildCards
= FsRtlDoesNameContainWildCards(FileName
);
7488 Fobx
->UnicodeQueryTemplate
.Buffer
= RxAllocatePoolWithTag(PagedPool
, FileName
->Length
, RX_DIRCTL_POOLTAG
);
7489 if (Fobx
->UnicodeQueryTemplate
.Buffer
!= NULL
)
7491 /* UNICODE_STRING; length has to be even */
7492 if ((FileName
->Length
& 1) != 0)
7494 Status
= STATUS_INVALID_PARAMETER
;
7495 RxFreePoolWithTag(Fobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
7499 Fobx
->UnicodeQueryTemplate
.Length
= FileName
->Length
;
7500 Fobx
->UnicodeQueryTemplate
.MaximumLength
= FileName
->Length
;
7501 RtlMoveMemory(Fobx
->UnicodeQueryTemplate
.Buffer
, FileName
->Buffer
, FileName
->Length
);
7503 SetFlag(Fobx
->Flags
, FOBX_FLAG_FREE_UNICODE
);
7508 Status
= STATUS_INSUFFICIENT_RESOURCES
;
7511 /* No name specified, or a match all wildcard? Match everything */
7514 Fobx
->ContainsWildCards
= TRUE
;
7516 Fobx
->UnicodeQueryTemplate
.Buffer
= &RxStarForTemplate
;
7517 Fobx
->UnicodeQueryTemplate
.Length
= sizeof(WCHAR
);
7518 Fobx
->UnicodeQueryTemplate
.MaximumLength
= sizeof(WCHAR
);
7520 SetFlag(Fobx
->Flags
, FOBX_FLAG_MATCH_ALL
);
7523 /* No need for exclusive any longer */
7524 if (NT_SUCCESS(Status
))
7526 RxConvertToSharedFcb(RxContext
, Fcb
);
7530 /* Lock user buffer and forward to mini-rdr */
7531 if (NT_SUCCESS(Status
))
7533 RxLockUserBuffer(RxContext
, IoModifyAccess
, Length
);
7534 RxContext
->Info
.FileInformationClass
= FileInfoClass
;
7535 RxContext
->Info
.Buffer
= RxNewMapUserBuffer(RxContext
);
7536 RxContext
->Info
.Length
= Length
;
7538 if (RxContext
->Info
.Buffer
!= NULL
)
7540 MINIRDR_CALL(Status
, RxContext
, Fcb
->MRxDispatch
, MRxQueryDirectory
, (RxContext
));
7543 /* Post if mini-rdr asks to */
7544 if (RxContext
->PostRequest
)
7546 RxFsdPostRequest(RxContext
);
7550 Irp
->IoStatus
.Information
= Length
- RxContext
->Info
.LengthRemaining
;
7556 RxReleaseFcb(RxContext
, Fcb
);
7565 PRX_CONTEXT RxContext
,
7566 PFILE_EA_INFORMATION EaInfo
)
7569 return STATUS_NOT_IMPLEMENTED
;
7573 RxQueryInternalInfo(
7574 PRX_CONTEXT RxContext
,
7575 PFILE_INTERNAL_INFORMATION InternalInfo
)
7578 return STATUS_NOT_IMPLEMENTED
;
7583 PRX_CONTEXT RxContext
,
7584 PFILE_NAME_INFORMATION NameInfo
)
7587 return STATUS_NOT_IMPLEMENTED
;
7592 PRX_CONTEXT RxContext
,
7593 PFILE_PIPE_INFORMATION PipeInfo
)
7596 return STATUS_NOT_IMPLEMENTED
;
7600 RxQueryPositionInfo(
7601 PRX_CONTEXT RxContext
,
7602 PFILE_POSITION_INFORMATION PositionInfo
)
7605 return STATUS_NOT_IMPLEMENTED
;
7612 RxQueryStandardInfo(
7613 PRX_CONTEXT RxContext
,
7614 PFILE_STANDARD_INFORMATION StandardInfo
)
7622 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext
, StandardInfo
);
7624 /* Zero output buffer */
7625 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
7627 Fcb
= (PFCB
)RxContext
->pFcb
;
7628 Fobx
= (PFOBX
)RxContext
->pFobx
;
7629 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
7630 if ((NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&& NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
) ||
7631 BooleanFlagOn(Fobx
->pSrvOpen
->CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
7633 return RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
7636 /* Otherwise, fill what we can already */
7637 Status
= STATUS_SUCCESS
;
7638 StandardInfo
->NumberOfLinks
= Fcb
->NumberOfLinks
;
7639 StandardInfo
->DeletePending
= BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
7640 StandardInfo
->Directory
= (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
);
7641 if (StandardInfo
->NumberOfLinks
== 0)
7643 StandardInfo
->NumberOfLinks
= 1;
7646 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
7648 StandardInfo
->AllocationSize
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
7649 RxGetFileSizeWithLock(Fcb
, &StandardInfo
->EndOfFile
.QuadPart
);
7652 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
7653 if (RxForceQFIPassThrough
|| !BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FILESIZECACHEING_ENABLED
))
7655 Status
= RxpQueryInfoMiniRdr(RxContext
, FileStandardInformation
, StandardInfo
);
7659 RxContext
->IoStatusBlock
.Information
-= sizeof(FILE_STANDARD_INFORMATION
);
7670 RxReadRegistryParameters(
7677 UNICODE_STRING KeyName
, ParamName
;
7678 OBJECT_ATTRIBUTES ObjectAttributes
;
7679 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
7683 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
7684 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
7685 Status
= ZwOpenKey(&KeyHandle
, READ_CONTROL
| KEY_NOTIFY
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
7686 if (!NT_SUCCESS(Status
))
7691 PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
7692 RtlInitUnicodeString(&ParamName
, L
"DisableByteRangeLockingOnReadOnlyFiles");
7693 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
7694 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
7696 DisableByteRangeLockingOnReadOnlyFiles
= (*(PULONG
)PartialInfo
->Data
!= 0);
7699 RtlInitUnicodeString(&ParamName
, L
"ReadAheadGranularity");
7700 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
7701 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
7703 ULONG Granularity
= *(PULONG
)PartialInfo
->Data
;
7705 if (Granularity
> 16)
7710 ReadAheadGranularity
= Granularity
<< PAGE_SHIFT
;
7713 RtlInitUnicodeString(&ParamName
, L
"DisableFlushOnCleanup");
7714 Status
= ZwQueryValueKey(KeyHandle
, &ParamName
, KeyValuePartialInformation
, PartialInfo
, sizeof(Buffer
), &ResultLength
);
7715 if (NT_SUCCESS(Status
) && PartialInfo
->Type
== REG_DWORD
)
7717 DisableFlushOnCleanup
= (*(PULONG
)PartialInfo
->Data
!= 0);
7729 OUT PRDBSS_DEVICE_OBJECT
*DeviceObject
,
7730 IN OUT PDRIVER_OBJECT DriverObject
,
7731 IN PMINIRDR_DISPATCH MrdrDispatch
,
7733 IN PUNICODE_STRING DeviceName
,
7734 IN ULONG DeviceExtensionSize
,
7735 IN DEVICE_TYPE DeviceType
,
7736 IN ULONG DeviceCharacteristics
)
7739 PRDBSS_DEVICE_OBJECT RDBSSDevice
;
7745 return STATUS_INVALID_PARAMETER
;
7748 /* Create device object with provided parameters */
7749 Status
= IoCreateDevice(DriverObject
,
7750 DeviceExtensionSize
+ sizeof(RDBSS_DEVICE_OBJECT
),
7753 DeviceCharacteristics
,
7755 (PDEVICE_OBJECT
*)&RDBSSDevice
);
7756 if (!NT_SUCCESS(Status
))
7761 if (!RxData
.DriverObject
)
7763 return STATUS_UNSUCCESSFUL
;
7766 /* Initialize our DO extension */
7767 RDBSSDevice
->RDBSSDeviceObject
= NULL
;
7768 ++RxFileSystemDeviceObject
->ReferenceCount
;
7769 *DeviceObject
= RDBSSDevice
;
7770 RDBSSDevice
->RdbssExports
= &RxExports
;
7771 RDBSSDevice
->Dispatch
= MrdrDispatch
;
7772 RDBSSDevice
->RegistrationControls
= Controls
;
7773 RDBSSDevice
->DeviceName
= *DeviceName
;
7774 RDBSSDevice
->RegisterUncProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS
);
7775 RDBSSDevice
->RegisterMailSlotProvider
= !BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
7776 InitializeListHead(&RDBSSDevice
->OverflowQueue
[0]);
7777 InitializeListHead(&RDBSSDevice
->OverflowQueue
[1]);
7778 InitializeListHead(&RDBSSDevice
->OverflowQueue
[2]);
7779 KeInitializeSpinLock(&RDBSSDevice
->OverflowQueueSpinLock
);
7780 RDBSSDevice
->NetworkProviderPriority
= RxGetNetworkProviderPriority(DeviceName
);
7782 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName
, RDBSSDevice
->NetworkProviderPriority
);
7784 ExAcquireFastMutex(&RxData
.MinirdrRegistrationMutex
);
7785 InsertTailList(&RxData
.RegisteredMiniRdrs
, &RDBSSDevice
->MiniRdrListLinks
);
7786 ExReleaseFastMutex(&RxData
.MinirdrRegistrationMutex
);
7788 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
7789 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH
))
7791 RxInitializeMinirdrDispatchTable(DriverObject
);
7794 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
7795 if (!BooleanFlagOn(Controls
, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER
))
7797 LARGE_INTEGER ScavengerTimeLimit
;
7799 RDBSSDevice
->pRxNetNameTable
= &RDBSSDevice
->RxNetNameTableInDeviceObject
;
7800 RxInitializePrefixTable(RDBSSDevice
->pRxNetNameTable
, 0, FALSE
);
7801 RDBSSDevice
->RxNetNameTableInDeviceObject
.IsNetNameTable
= TRUE
;
7802 ScavengerTimeLimit
.QuadPart
= MrdrDispatch
->ScavengerTimeout
* 10000000LL;
7803 RDBSSDevice
->pRdbssScavenger
= &RDBSSDevice
->RdbssScavengerInDeviceObject
;
7804 RxInitializeRdbssScavenger(RDBSSDevice
->pRdbssScavenger
, ScavengerTimeLimit
);
7807 RDBSSDevice
->pAsynchronousRequestsCompletionEvent
= NULL
;
7809 return STATUS_SUCCESS
;
7814 RxReleaseFcbFromLazyWrite(
7822 RxReleaseFcbFromReadAhead(
7830 RxReleaseFileForNtCreateSection(
7831 PFILE_OBJECT FileObject
)
7838 RxReleaseForCcFlush(
7839 PFILE_OBJECT FileObject
,
7840 PDEVICE_OBJECT DeviceObject
)
7843 return STATUS_NOT_IMPLEMENTED
;
7850 RxRemoveFromTopLevelIrpAllocatedContextsList(
7851 PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
7855 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
7856 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
7857 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
7859 KeAcquireSpinLock(&TopLevelIrpSpinLock
, &OldIrql
);
7860 RemoveEntryList(&TopLevelContext
->ListEntry
);
7861 KeReleaseSpinLock(&TopLevelIrpSpinLock
, OldIrql
);
7868 RxRemoveOverflowEntry(
7869 PRDBSS_DEVICE_OBJECT DeviceObject
,
7870 WORK_QUEUE_TYPE Queue
)
7873 PRX_CONTEXT Context
;
7875 KeAcquireSpinLock(&DeviceObject
->OverflowQueueSpinLock
, &OldIrql
);
7876 if (DeviceObject
->OverflowQueueCount
[Queue
] <= 0)
7878 /* No entries left, nothing to return */
7879 InterlockedDecrement(&DeviceObject
->PostedRequestCount
[Queue
]);
7886 /* Decrement count */
7887 --DeviceObject
->OverflowQueueCount
[Queue
];
7890 Entry
= RemoveHeadList(&DeviceObject
->OverflowQueue
[Queue
]);
7891 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, OverflowListEntry
);
7892 ClearFlag(Context
->Flags
, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE
| RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE
));
7893 Context
->OverflowListEntry
.Flink
= NULL
;
7895 KeReleaseSpinLock(&DeviceObject
->OverflowQueueSpinLock
, OldIrql
);
7904 RxRemoveShareAccess(
7905 _Inout_ PFILE_OBJECT FileObject
,
7906 _Inout_ PSHARE_ACCESS ShareAccess
,
7908 _In_ PSZ wherelogtag
)
7912 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
7913 IoRemoveShareAccess(FileObject
, ShareAccess
);
7914 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
7921 RxRemoveShareAccessPerSrvOpens(
7922 IN OUT PSRV_OPEN SrvOpen
)
7924 ACCESS_MASK DesiredAccess
;
7926 BOOLEAN WriteAccess
;
7927 BOOLEAN DeleteAccess
;
7931 /* Get access that were granted to SRV_OPEN */
7932 DesiredAccess
= SrvOpen
->DesiredAccess
;
7933 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
7934 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
7935 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
7937 /* If any, drop them */
7938 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
7941 BOOLEAN SharedWrite
;
7942 BOOLEAN SharedDelete
;
7943 ULONG DesiredShareAccess
;
7944 PSHARE_ACCESS ShareAccess
;
7946 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
7947 DesiredShareAccess
= SrvOpen
->ShareAccess
;
7949 ShareAccess
->Readers
-= ReadAccess
;
7950 ShareAccess
->Writers
-= WriteAccess
;
7951 ShareAccess
->Deleters
-= DeleteAccess
;
7953 ShareAccess
->OpenCount
--;
7955 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
7956 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
7957 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
7958 ShareAccess
->SharedRead
-= SharedRead
;
7959 ShareAccess
->SharedWrite
-= SharedWrite
;
7960 ShareAccess
->SharedDelete
-= SharedDelete
;
7965 RxSearchForCollapsibleOpen(
7966 PRX_CONTEXT RxContext
,
7967 ACCESS_MASK DesiredAccess
,
7972 PLIST_ENTRY ListEntry
;
7973 BOOLEAN ShouldTry
, Purged
, Scavenged
;
7977 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext
, DesiredAccess
, ShareAccess
);
7979 Fcb
= (PFCB
)RxContext
->pFcb
;
7981 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
7982 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
7984 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
7986 RxScavengeRelatedFobxs(Fcb
);
7987 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
7989 return STATUS_NOT_FOUND
;
7992 /* If basic open, ask the mini-rdr if we should try to collapse */
7993 if (RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN
||
7994 RxContext
->Create
.NtCreateParameters
.Disposition
== FILE_OPEN_IF
)
7998 if (Fcb
->MRxDispatch
!= NULL
)
8000 ASSERT(RxContext
->pRelevantSrvOpen
== NULL
);
8001 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8003 ShouldTry
= NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
));
8011 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_DELETE_ON_CLOSE
))
8016 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8019 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
)))
8021 return STATUS_NOT_FOUND
;
8024 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8026 RxScavengeRelatedFobxs(Fcb
);
8027 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8029 return STATUS_NOT_FOUND
;
8032 /* Only collapse for matching NET_ROOT & disks */
8033 if (Fcb
->pNetRoot
!= RxContext
->Create
.pNetRoot
||
8034 Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
)
8036 return STATUS_NOT_FOUND
;
8041 Status
= STATUS_NOT_FOUND
;
8043 /* Browse all our SRV_OPEN to find the matching one */
8044 for (ListEntry
= Fcb
->SrvOpenList
.Flink
;
8045 ListEntry
!= &Fcb
->SrvOpenList
;
8046 ListEntry
= ListEntry
->Flink
)
8050 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
8051 /* Not the same VNET_ROOT, move to the next one */
8052 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8054 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8058 /* Is there a sharing violation? */
8059 if (SrvOpen
->DesiredAccess
!= DesiredAccess
|| SrvOpen
->ShareAccess
!= ShareAccess
||
8060 BooleanFlagOn(SrvOpen
->Flags
, (SRVOPEN_FLAG_CLOSED
| SRVOPEN_FLAG_COLLAPSING_DISABLED
| SRVOPEN_FLAG_FILE_DELETED
| SRVOPEN_FLAG_FILE_RENAMED
)))
8062 if (SrvOpen
->pVNetRoot
!= RxContext
->Create
.pVNetRoot
)
8064 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8068 /* Check against the SRV_OPEN */
8069 Status
= RxCheckShareAccessPerSrvOpens(Fcb
, DesiredAccess
, ShareAccess
);
8070 if (!NT_SUCCESS(Status
))
8077 /* Don't allow collaspse for reparse point opening */
8078 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
^ SrvOpen
->CreateOptions
, FILE_OPEN_REPARSE_POINT
))
8082 Status
= STATUS_NOT_FOUND
;
8086 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8087 if (DisableByteRangeLockingOnReadOnlyFiles
|| !BooleanFlagOn(SrvOpen
->pFcb
->Attributes
, FILE_ATTRIBUTE_READONLY
))
8089 RxContext
->pRelevantSrvOpen
= (PMRX_SRV_OPEN
)SrvOpen
;
8091 ASSERT(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen
!= NULL
);
8092 if (NT_SUCCESS(Fcb
->MRxDispatch
->MRxShouldTryToCollapseThisOpen(RxContext
)))
8094 /* Is close delayed - great reuse*/
8095 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
8097 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen
);
8098 InterlockedDecrement(&((PSRV_CALL
)Fcb
->pNetRoot
->pSrvCall
)->NumberOfCloseDelayedFiles
);
8099 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
);
8102 return STATUS_SUCCESS
;
8105 Status
= STATUS_NOT_FOUND
;
8110 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8111 if (ListEntry
== &Fcb
->SrvOpenList
)
8113 Status
= STATUS_NOT_FOUND
;
8116 /* Only required access: read attributes? Don't reuse */
8117 if ((DesiredAccess
& 0xFFEFFFFF) == FILE_READ_ATTRIBUTES
)
8119 return STATUS_NOT_FOUND
;
8122 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8125 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
8127 RxScavengeRelatedFobxs(Fcb
);
8131 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8132 if (!Purged
&& RxIsOkToPurgeFcb(Fcb
))
8134 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, FALSE
, TRUE
);
8139 /* If sharing violation, keep track of it */
8140 if (Status
== STATUS_SHARING_VIOLATION
)
8142 RxContext
->Create
.TryForScavengingOnSharingViolation
= TRUE
;
8145 DPRINT("Status: %x\n", Status
);
8154 _In_ ACCESS_MASK DesiredAccess
,
8155 _In_ ULONG DesiredShareAccess
,
8156 _Inout_ PFILE_OBJECT FileObject
,
8157 _Out_ PSHARE_ACCESS ShareAccess
,
8159 _In_ PSZ wherelogtag
)
8163 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8164 IoSetShareAccess(DesiredAccess
, DesiredShareAccess
, FileObject
, ShareAccess
);
8165 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8172 RxSetupNetFileObject(
8173 PRX_CONTEXT RxContext
)
8177 PFILE_OBJECT FileObject
;
8178 PIO_STACK_LOCATION Stack
;
8182 /* Assert FOBX is FOBX or NULL */
8183 Fobx
= (PFOBX
)RxContext
->pFobx
;
8184 ASSERT((Fobx
== NULL
) || (NodeType(Fobx
) == RDBSS_NTC_FOBX
));
8186 Fcb
= (PFCB
)RxContext
->pFcb
;
8187 Stack
= RxContext
->CurrentIrpSp
;
8188 FileObject
= Stack
->FileObject
;
8189 /* If it's temporary mark FO as such */
8190 if (Fcb
!= NULL
&& NodeType(Fcb
) != RDBSS_NTC_VCB
&&
8191 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TEMPORARY
))
8193 if (FileObject
== NULL
)
8198 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
8201 /* No FO, nothing to setup */
8202 if (FileObject
== NULL
)
8207 /* Assign FCB & CCB (FOBX) to FO */
8208 FileObject
->FsContext
= Fcb
;
8209 FileObject
->FsContext2
= Fobx
;
8212 ULONG_PTR StackTop
, StackBottom
;
8214 /* If FO is allocated on pool, keep track of it */
8215 IoGetStackLimits(&StackTop
, &StackBottom
);
8216 if ((ULONG_PTR
)FileObject
<= StackBottom
|| (ULONG_PTR
)FileObject
>= StackTop
)
8218 Fobx
->AssociatedFileObject
= FileObject
;
8222 Fobx
->AssociatedFileObject
= NULL
;
8225 /* Make sure to mark FOBX if it's a DFS open */
8226 if (RxContext
->Create
.NtCreateParameters
.DfsContext
== UIntToPtr(DFS_OPEN_CONTEXT
))
8228 SetFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8232 ClearFlag(Fobx
->Flags
, FOBX_FLAG_DFS_OPEN
);
8236 /* Set Cc pointers */
8237 FileObject
->SectionObjectPointer
= &Fcb
->NonPaged
->SectionObjectPointers
;
8239 /* Update access state */
8240 if (Stack
->Parameters
.Create
.SecurityContext
!= NULL
)
8242 PACCESS_STATE AccessState
;
8244 AccessState
= Stack
->Parameters
.Create
.SecurityContext
->AccessState
;
8245 AccessState
->PreviouslyGrantedAccess
|= AccessState
->RemainingDesiredAccess
;
8246 AccessState
->RemainingDesiredAccess
= 0;
8256 IN PRX_CONTEXT RxContext
,
8257 OUT PBOOLEAN PostToFsp
)
8260 BOOLEAN Wait
, AlreadyStarted
;
8261 PRDBSS_DEVICE_OBJECT DeviceObject
;
8263 /* If we've not been post, then, do it */
8264 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
8266 SECURITY_SUBJECT_CONTEXT SubjectContext
;
8268 SeCaptureSubjectContext(&SubjectContext
);
8269 RxContext
->FsdUid
= RxGetUid(&SubjectContext
);
8270 SeReleaseSubjectContext(&SubjectContext
);
8273 return STATUS_PENDING
;
8276 /* Acquire all the required locks */
8277 Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8278 if (!ExAcquireResourceExclusiveLite(&RxData
.Resource
, Wait
))
8281 return STATUS_PENDING
;
8284 if (!RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, Wait
))
8286 ExReleaseResourceLite(&RxData
.Resource
);
8288 return STATUS_PENDING
;
8291 AlreadyStarted
= FALSE
;
8292 DeviceObject
= RxContext
->RxDeviceObject
;
8295 /* MUP handle set, means already registered */
8296 if (DeviceObject
->MupHandle
!= NULL
)
8298 AlreadyStarted
= TRUE
;
8299 Status
= STATUS_REDIRECTOR_STARTED
;
8303 /* If we're asked to register to MUP, then do it */
8304 Status
= STATUS_SUCCESS
;
8305 if (DeviceObject
->RegisterUncProvider
)
8307 Status
= FsRtlRegisterUncProvider(&DeviceObject
->MupHandle
,
8308 &DeviceObject
->DeviceName
,
8309 DeviceObject
->RegisterMailSlotProvider
);
8311 if (!NT_SUCCESS(Status
))
8313 DeviceObject
->MupHandle
= NULL
;
8317 /* Register as file system */
8318 IoRegisterFileSystem(&DeviceObject
->DeviceObject
);
8319 DeviceObject
->RegisteredAsFileSystem
= TRUE
;
8321 /* Inform mini-rdr it has to start */
8322 MINIRDR_CALL(Status
, RxContext
, DeviceObject
->Dispatch
, MRxStart
, (RxContext
, DeviceObject
));
8323 if (NT_SUCCESS(Status
))
8325 ++DeviceObject
->StartStopContext
.Version
;
8326 RxSetRdbssState(DeviceObject
, RDBSS_STARTED
);
8327 InterlockedExchangeAdd(&RxData
.NumberOfMinirdrsStarted
, 1);
8329 Status
= RxInitializeMRxDispatcher(DeviceObject
);
8334 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status
))
8336 if (!AlreadyStarted
)
8338 RxUnstart(RxContext
, DeviceObject
);
8342 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
8343 ExReleaseResourceLite(&RxData
.Resource
);
8353 IN PRX_CONTEXT RxContext
,
8354 OUT PBOOLEAN PostToFsp
)
8357 return STATUS_NOT_IMPLEMENTED
;
8362 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8366 return STATUS_NOT_IMPLEMENTED
;
8373 RxTryToBecomeTheTopLevelIrp(
8374 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
,
8376 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
8377 IN BOOLEAN ForceTopLevel
8380 BOOLEAN FromPool
= FALSE
;
8384 /* If not top level, and not have to be, quit */
8385 if (IoGetTopLevelIrp() && !ForceTopLevel
)
8390 /* If not TLC provider, allocate one */
8391 if (TopLevelContext
== NULL
)
8393 TopLevelContext
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(RX_TOPLEVELIRP_CONTEXT
), RX_TLC_POOLTAG
);
8394 if (TopLevelContext
== NULL
)
8403 __RxInitializeTopLevelIrpContext(TopLevelContext
, Irp
, RxDeviceObject
, FromPool
);
8405 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8408 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8411 /* Make it top level IRP */
8412 IoSetTopLevelIrp((PIRP
)TopLevelContext
);
8420 RxUpdateShareAccess(
8421 _Inout_ PFILE_OBJECT FileObject
,
8422 _Inout_ PSHARE_ACCESS ShareAccess
,
8424 _In_ PSZ wherelogtag
)
8428 RxDumpCurrentAccess(where
, "before", wherelogtag
, ShareAccess
);
8429 IoUpdateShareAccess(FileObject
, ShareAccess
);
8430 RxDumpCurrentAccess(where
, "after", wherelogtag
, ShareAccess
);
8437 RxUninitializeCacheMap(
8438 PRX_CONTEXT RxContext
,
8439 PFILE_OBJECT FileObject
,
8440 PLARGE_INTEGER TruncateSize
)
8444 CACHE_UNINITIALIZE_EVENT UninitEvent
;
8448 Fcb
= FileObject
->FsContext
;
8449 ASSERT(NodeTypeIsFcb(Fcb
));
8450 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
8452 KeInitializeEvent(&UninitEvent
.Event
, SynchronizationEvent
, FALSE
);
8453 CcUninitializeCacheMap(FileObject
, TruncateSize
, &UninitEvent
);
8455 /* Always release the FCB before waiting for the uninit event */
8456 RxReleaseFcb(RxContext
, Fcb
);
8458 KeWaitForSingleObject(&UninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
8460 /* Re-acquire it afterwards */
8461 Status
= RxAcquireExclusiveFcb(RxContext
, Fcb
);
8462 ASSERT(NT_SUCCESS(Status
));
8468 IN PDRIVER_OBJECT DriverObject
)
8477 IN PFILE_LOCK_INFO LockInfo
)
8484 PRX_CONTEXT Context
,
8485 PRDBSS_DEVICE_OBJECT DeviceObject
)
8494 RxUnwindTopLevelIrp(
8495 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
)
8497 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext
);
8499 /* No TLC provided? Ask the system for ours! */
8500 if (TopLevelContext
== NULL
)
8502 TopLevelContext
= (PRX_TOPLEVELIRP_CONTEXT
)IoGetTopLevelIrp();
8503 if (TopLevelContext
== NULL
)
8508 /* In that case, just assert it's really ours */
8509 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext
));
8510 ASSERT(BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
));
8513 ASSERT(TopLevelContext
->Signature
== RX_TOPLEVELIRP_CONTEXT_SIGNATURE
);
8514 ASSERT(TopLevelContext
->Thread
== PsGetCurrentThread());
8515 /* Restore the previous top level IRP */
8516 IoSetTopLevelIrp(TopLevelContext
->Previous
);
8517 /* If TLC was allocated from pool, remove it from list and release it */
8518 if (BooleanFlagOn(TopLevelContext
->Flags
, RX_TOPLEVELCTX_FLAG_FROM_POOL
))
8520 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext
);
8521 RxFreePoolWithTag(TopLevelContext
, RX_TLC_POOLTAG
);
8529 RxUpdateShareAccessPerSrvOpens(
8530 IN PSRV_OPEN SrvOpen
)
8532 ACCESS_MASK DesiredAccess
;
8534 BOOLEAN WriteAccess
;
8535 BOOLEAN DeleteAccess
;
8539 /* If already updated, no need to continue */
8540 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
))
8545 /* Check if any access wanted */
8546 DesiredAccess
= SrvOpen
->DesiredAccess
;
8547 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
8548 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
8549 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
8551 /* In that case, update it */
8552 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
8555 BOOLEAN SharedWrite
;
8556 BOOLEAN SharedDelete
;
8557 ULONG DesiredShareAccess
;
8558 PSHARE_ACCESS ShareAccess
;
8560 ShareAccess
= &((PFCB
)SrvOpen
->pFcb
)->ShareAccessPerSrvOpens
;
8561 DesiredShareAccess
= SrvOpen
->ShareAccess
;
8563 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
8564 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
8565 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
8567 ShareAccess
->OpenCount
++;
8569 ShareAccess
->Readers
+= ReadAccess
;
8570 ShareAccess
->Writers
+= WriteAccess
;
8571 ShareAccess
->Deleters
+= DeleteAccess
;
8572 ShareAccess
->SharedRead
+= SharedRead
;
8573 ShareAccess
->SharedWrite
+= SharedWrite
;
8574 ShareAccess
->SharedDelete
+= SharedDelete
;
8577 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_SHAREACCESS_UPDATED
);
8584 RxXXXControlFileCallthru(
8585 PRX_CONTEXT Context
)
8591 DPRINT("RxXXXControlFileCallthru(%p)\n", Context
);
8593 /* No dispatch table? Nothing to dispatch */
8594 if (Context
->RxDeviceObject
->Dispatch
== NULL
)
8596 Context
->pFobx
= NULL
;
8597 return STATUS_INVALID_DEVICE_REQUEST
;
8600 /* Init the lowio context */
8601 Status
= RxLowIoPopulateFsctlInfo(Context
);
8602 if (!NT_SUCCESS(Status
))
8607 /* Check whether we're consistent: a length means a buffer */
8608 if ((Context
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
8609 (Context
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
> 0 && Context
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
8611 return STATUS_INVALID_PARAMETER
;
8614 /* Forward the call to the mini-rdr */
8615 DPRINT("Calling: %p\n", Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile
);
8616 Status
= Context
->RxDeviceObject
->Dispatch
->MRxDevFcbXXXControlFile(Context
);
8617 if (Status
!= STATUS_PENDING
)
8619 Context
->CurrentIrp
->IoStatus
.Information
= Context
->InformationToReturn
;
8622 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context
->CurrentIrp
->IoStatus
.Status
, Context
->CurrentIrp
->IoStatus
.Information
);