ReactOS 0.4.15-dev-8241-g63935f8
rdbss.c
Go to the documentation of this file.
1/*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19/*
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)
25 */
26
27/* INCLUDES *****************************************************************/
28
29#include <rx.h>
30#include <pseh/pseh2.h>
31#include <limits.h>
32#include <dfs.h>
33#include <copysup.h>
34
35#define NDEBUG
36#include <debug.h>
37
38#define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
39
40typedef
44
46{
49
50VOID
54
60
61VOID
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64
65VOID
68 PVOID File,
69 ULONG Line,
71
76
81
86
91
96
101
103NTAPI
106
108NTAPI
111
113NTAPI
116
118NTAPI
121
123NTAPI
126
128NTAPI
131
133NTAPI
136
138NTAPI
141
143NTAPI
146
148NTAPI
151
153NTAPI
156
158NTAPI
161
163NTAPI
166
168NTAPI
171
173NTAPI
176
178NTAPI
181
183NTAPI
186
188NTAPI
191
193NTAPI
196
198NTAPI
201
203NTAPI
206
207VOID
209 IN PRX_CONTEXT RxContext);
210
214 PUNICODE_STRING NetRootName);
215
218 IN PRX_CONTEXT RxContext);
219
221NTAPI
229
231NTAPI
242
244NTAPI
254
256NTAPI
266
269 PRX_CONTEXT RxContext,
270 PUNICODE_STRING NetRootName);
271
274 PRX_CONTEXT RxContext,
276 PUNICODE_STRING CanonicalName,
277 PNET_ROOT_TYPE NetRootType);
278
279VOID
282
283VOID
284NTAPI
287
288VOID
289NTAPI
292
294NTAPI
298 OUT PUNICODE_STRING OutString,
301 IN BOOLEAN LogFailure);
302
303VOID
304NTAPI
306 VOID);
307
308VOID
309NTAPI
312
314NTAPI
316 VOID);
317
318VOID
319NTAPI
321 VOID);
322
323VOID
324NTAPI
327 USHORT State);
328
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332
334NTAPI
336 PRX_CONTEXT RxContext);
337
340 PRX_CONTEXT RxContext);
341
343NTAPI
345 PRX_CONTEXT RxContext);
346
349 IN PRX_CONTEXT RxContext);
350
352NTAPI
354 PRX_CONTEXT RxContext);
355
356PVOID
358 PRX_CONTEXT RxContext);
359
362 PRX_CONTEXT RxContext);
363
364VOID
365NTAPI
367 PVOID Context);
368
371 PRX_CONTEXT RxContext,
372 FILE_INFORMATION_CLASS FileInfoClass,
373 PVOID Buffer);
374
375VOID
377 PFCB Fcb,
378 PRX_CONTEXT LocalContext);
379
382 PRX_CONTEXT RxContext,
383 PFILE_NAME_INFORMATION AltNameInfo);
384
387 PRX_CONTEXT RxContext,
388 PFILE_BASIC_INFORMATION BasicInfo);
389
392 PRX_CONTEXT RxContext,
393 PFILE_COMPRESSION_INFORMATION CompressionInfo);
394
397 PRX_CONTEXT RxContext);
398
401 PRX_CONTEXT RxContext,
402 PFILE_EA_INFORMATION EaInfo);
403
406 PRX_CONTEXT RxContext,
407 PFILE_INTERNAL_INFORMATION InternalInfo);
408
411 PRX_CONTEXT RxContext,
412 PFILE_NAME_INFORMATION NameInfo);
413
416 PRX_CONTEXT RxContext,
418
421 PRX_CONTEXT RxContext,
422 PFILE_POSITION_INFORMATION PositionInfo);
423
426 PRX_CONTEXT RxContext,
427 PFILE_STANDARD_INFORMATION StandardInfo);
428
429VOID
430NTAPI
432 VOID);
433
434VOID
435NTAPI
438
440NTAPI
444
449
452 PRX_CONTEXT RxContext,
455
458 PRX_CONTEXT RxContext);
459
462 PRX_CONTEXT RxContext);
463
466 PRX_CONTEXT RxContext);
467
470 PRX_CONTEXT RxContext);
471
474 PRX_CONTEXT RxContext);
475
478 PRX_CONTEXT RxContext);
479
482 PRX_CONTEXT RxContext);
483
486 PRX_CONTEXT RxContext);
487
488VOID
490 PRX_CONTEXT RxContext);
491
494 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
495 IN PIRP Irp);
496
497VOID
499 PRX_CONTEXT RxContext,
501 PLARGE_INTEGER TruncateSize);
502
503VOID
507
511
512PVOID
513NTAPI
517 _In_ ULONG Tag);
518
519VOID
520NTAPI
523
524VOID
525NTAPI
528 _In_ ULONG Tag);
529
531WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
541{
570};
575{
576 { RxCommonCreate },
578 { RxCommonClose },
579 { RxCommonRead },
580 { RxCommonWrite },
583 { RxCommonQueryEa },
584 { RxCommonSetEa },
594 { RxCommonCleanup },
604};
610UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
615
617
618#if RDBSS_ASSERTS
619#ifdef ASSERT
620#undef ASSERT
621#endif
622
623#define ASSERT(exp) \
624 if (!(exp)) \
625 { \
626 RxAssert(#exp, __FILE__, __LINE__, NULL); \
627 }
628#endif
629
630#if RX_POOL_WRAPPER
631#undef RxAllocatePool
632#undef RxAllocatePoolWithTag
633#undef RxFreePool
634
635#define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
636#define RxAllocatePoolWithTag _RxAllocatePoolWithTag
637#define RxFreePool _RxFreePool
638#define RxFreePoolWithTag _RxFreePoolWithTag
639#endif
640
641/* FUNCTIONS ****************************************************************/
642
643/*
644 * @implemented
645 */
646VOID
648 PRX_CONTEXT RxContext)
649{
651
652 PAGED_CODE();
653
654#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
655
656 /* Are loud operations enabled? */
658 {
659 /* If so, the operation will be loud only if filename ends with all.scr */
660 if (RtlCompareMemory(Add2Ptr(capFcb->PrivateAlreadyPrefixedName.Buffer,
661 (capFcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
662 L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
663 {
665 }
666 }
667#undef ALLSCR_LENGTH
668}
669
670/*
671 * @implemented
672 */
673VOID
675 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
676 IN PIRP Irp,
677 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
678 IN ULONG Flags)
679{
680 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
681
682 RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
683 TopLevelContext->Irp = Irp;
684 TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
685 TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
686 TopLevelContext->RxDeviceObject = RxDeviceObject;
687 TopLevelContext->Previous = IoGetTopLevelIrp();
688 TopLevelContext->Thread = PsGetCurrentThread();
689
690 /* We cannot add to list something that'd come from stack */
691 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
692 {
694 }
695}
696
697/*
698 * @implemented
699 */
700VOID
702 PRX_CONTEXT RxContext,
703 BOOLEAN ResourceOwnerSet,
707{
709
710 PAGED_CODE();
711
712 ASSERT(RxContext != NULL);
713 ASSERT(capFcb != NULL);
714
715 /* If FCB resource was acquired, release it */
716 if (RxContext->FcbResourceAcquired)
717 {
718 /* Taking care of owner */
719 if (ResourceOwnerSet)
720 {
722 }
723 else
724 {
725 RxReleaseFcb(RxContext, capFcb);
726 }
727
728 RxContext->FcbResourceAcquired = FALSE;
729 }
730
731 /* If FCB paging resource was acquired, release it */
732 if (RxContext->FcbPagingIoResourceAcquired)
733 {
734 /* Taking care of owner */
735 if (ResourceOwnerSet)
736 {
738 }
739 else
740 {
742 }
743
744 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
745 }
746}
747
748/*
749 * @implemented
750 */
751VOID
753 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
754{
756
757 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
758
761
765}
766
767/*
768 * @implemented
769 */
770VOID
771NTAPI
773 IN PRX_CONTEXT RxContext,
774 IN PIRP Irp)
775{
776 ULONG Queued;
779
781
782 RxContext->PostRequest = FALSE;
783
784 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
785 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
786 capPARAMS->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
787 {
790 }
791 else
792 {
795 }
796
797 /* Check for overflow */
798 if (capPARAMS->FileObject != NULL)
799 {
801
803 /* In case of an overflow, add the new queued call to the overflow list */
804 if (Queued > 1)
805 {
807 InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
809
811 return;
812 }
813
815 }
816
817 ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
818 ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
819}
820
821/*
822 * @implemented
823 */
824VOID
826 PRX_CONTEXT RxContext)
827{
829 LARGE_INTEGER CurrentTime;
830 FILE_BASIC_INFORMATION FileBasicInfo;
832 BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
833
838
839 PAGED_CODE();
840
841 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
842 if (capFileObject->PrivateCacheMap == NULL)
843 {
844 return;
845 }
846
847 /* Get now */
848 KeQuerySystemTime(&CurrentTime);
849
850 /* Was the file modified? */
851 FileModified = BooleanFlagOn(capFileObject->Flags, FO_FILE_MODIFIED);
852 /* We'll set last write if it was modified and user didn't update yet */
853 SetLastWrite = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
854 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
855 SetLastAccess = SetLastWrite ||
858 /* We'll set last change if it was modified and user didn't update yet */
859 SetLastChange = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
860
861 /* Nothing to update? Job done */
862 if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
863 {
864 return;
865 }
866
867 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
868 NeedUpdate = FALSE;
869 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
870
871 /* Update lastwrite time if required */
872 if (SetLastWrite)
873 {
874 NeedUpdate = TRUE;
875 capFcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
876 FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
877 }
878
879 /* Update lastaccess time if required */
880 if (SetLastAccess)
881 {
882 NeedUpdate = TRUE;
883 capFcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
884 FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
885 }
886
887 /* Update lastchange time if required */
888 if (SetLastChange)
889 {
890 NeedUpdate = TRUE;
891 capFcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
892 FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
893 }
894
895 /* If one of the date was modified, issue a call to mini-rdr */
896 if (NeedUpdate)
897 {
898 RxContext->Info.FileInformationClass = FileBasicInformation;
899 RxContext->Info.Buffer = &FileBasicInfo;
900 RxContext->Info.Length = sizeof(FileBasicInfo);
901
902 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
903 (void)Status;
904 }
905
906 /* If the file was modified, update its EOF */
907 if (FileModified)
908 {
909 FileEOFInfo.EndOfFile.QuadPart = capFcb->Header.FileSize.QuadPart;
910
911 RxContext->Info.FileInformationClass = FileEndOfFileInformation;
912 RxContext->Info.Buffer = &FileEOFInfo;
913 RxContext->Info.Length = sizeof(FileEOFInfo);
914
915 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
916 (void)Status;
917 }
918}
919
920/*
921 * @implemented
922 */
925 PRX_CONTEXT RxContext,
926 PUNICODE_STRING CanonicalName,
927 USHORT CanonicalLength)
928{
929 PAGED_CODE();
930
931 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
932
933 /* Context must be free of any already allocated name */
934 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
935
936 /* Validate string length */
937 if (CanonicalLength > USHRT_MAX - 1)
938 {
939 CanonicalName->Buffer = NULL;
941 }
942
943 CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
944 if (CanonicalName->Buffer == NULL)
945 {
947 }
948
949 CanonicalName->Length = 0;
950 CanonicalName->MaximumLength = CanonicalLength;
951
952 /* Set the two places - they must always be identical */
953 RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
954 RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
955
956 return STATUS_SUCCESS;
957}
958
959/*
960 * @implemented
961 */
962VOID
964 PFOBX Fobx)
965{
969 LIST_ENTRY ContextsToCancel;
970
971 /* Init a list for the contexts to cancel */
972 InitializeListHead(&ContextsToCancel);
973
974 /* Lock our list lock */
976
977 /* Now, browse all the active contexts, to find the associated ones */
979 while (Entry != &RxActiveContexts)
980 {
981 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
982 Entry = Entry->Flink;
983
984 /* Not the IRP we're looking for, ignore */
985 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
986 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
987 {
988 continue;
989 }
990
991 /* Not the FOBX we're looking for, ignore */
992 if ((PFOBX)Context->pFobx != Fobx)
993 {
994 continue;
995 }
996
997 /* No cancel routine (can't be cancel, then), ignore */
998 if (Context->MRxCancelRoutine == NULL)
999 {
1000 continue;
1001 }
1002
1003 /* Mark our context as cancelled */
1005
1006 /* Move it to our list */
1007 RemoveEntryList(&Context->ContextListEntry);
1008 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1009
1010 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1011 }
1012
1013 /* Done with the contexts */
1015
1016 /* Now, handle all our "extracted" contexts */
1017 while (!IsListEmpty(&ContextsToCancel))
1018 {
1019 Entry = RemoveHeadList(&ContextsToCancel);
1020 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1021
1022 /* If they had an associated IRP (should be always true) */
1023 if (Context->CurrentIrp != NULL)
1024 {
1025 /* Then, call cancel routine */
1026 ASSERT(Context->MRxCancelRoutine != NULL);
1027 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1028 Context->MRxCancelRoutine(Context);
1029 }
1030
1031 /* And delete the context */
1033 }
1034}
1035
1036/*
1037 * @implemented
1038 */
1041 PV_NET_ROOT VNetRoot,
1042 BOOLEAN ForceFilesClosed)
1043{
1044 KIRQL OldIrql;
1048 LIST_ENTRY ContextsToCancel;
1049
1050 /* Init a list for the contexts to cancel */
1051 InitializeListHead(&ContextsToCancel);
1052
1053 /* Lock our list lock */
1055
1056 /* Assume success */
1058
1059 /* Now, browse all the active contexts, to find the associated ones */
1061 while (Entry != &RxActiveContexts)
1062 {
1063 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1064 Entry = Entry->Flink;
1065
1066 /* Not the IRP we're looking for, ignore */
1067 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
1068 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
1069 {
1070 continue;
1071 }
1072
1073 /* Not the VNetRoot we're looking for, ignore */
1074 if (Context->pFcb == NULL ||
1075 (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
1076 {
1077 continue;
1078 }
1079
1080 /* No cancel routine (can't be cancel, then), ignore */
1081 if (Context->MRxCancelRoutine == NULL)
1082 {
1083 continue;
1084 }
1085
1086 /* At that point, we found a matching context
1087 * If we're not asked to force close, then fail - it's still open
1088 */
1089 if (!ForceFilesClosed)
1090 {
1092 break;
1093 }
1094
1095 /* Mark our context as cancelled */
1097
1098 /* Move it to our list */
1099 RemoveEntryList(&Context->ContextListEntry);
1100 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1101
1102 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1103 }
1104
1105 /* Done with the contexts */
1107
1108 if (Status != STATUS_SUCCESS)
1109 {
1110 return Status;
1111 }
1112
1113 /* Now, handle all our "extracted" contexts */
1114 while (!IsListEmpty(&ContextsToCancel))
1115 {
1116 Entry = RemoveHeadList(&ContextsToCancel);
1117 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1118
1119 /* If they had an associated IRP (should be always true) */
1120 if (Context->CurrentIrp != NULL)
1121 {
1122 /* Then, call cancel routine */
1123 ASSERT(Context->MRxCancelRoutine != NULL);
1124 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1125 Context->MRxCancelRoutine(Context);
1126 }
1127
1128 /* And delete the context */
1130 }
1131
1132 return Status;
1133}
1134
1135/*
1136 * @implemented
1137 */
1138BOOLEAN
1140 PRX_CONTEXT RxContext)
1141{
1142 KIRQL OldIrql;
1143 BOOLEAN OperationToCancel;
1144
1145 /* By default, nothing cancelled */
1146 OperationToCancel = FALSE;
1147
1148 /* Acquire the overflow spinlock */
1150
1151 /* Is our context in any queue? */
1153 {
1154 /* Make sure flag is consistent with facts... */
1155 if (RxContext->OverflowListEntry.Flink != NULL)
1156 {
1157 /* Remove it from the list */
1159 RxContext->OverflowListEntry.Flink = NULL;
1160
1161 /* Decrement appropriate count */
1163 {
1165 }
1166 else
1167 {
1169 }
1170
1171 /* Clear the flag */
1173
1174 /* Time to cancel! */
1175 OperationToCancel = TRUE;
1176 }
1177 }
1178
1180
1181 /* We have something to cancel & complete */
1182 if (OperationToCancel)
1183 {
1186 }
1187
1188 return OperationToCancel;
1189}
1190
1191/*
1192 * @implemented
1193 */
1194VOID
1195NTAPI
1198 PIRP Irp)
1199{
1200 KIRQL OldIrql;
1202 PRX_CONTEXT RxContext;
1203
1204 /* Lock our contexts list */
1206
1207 /* Now, find a context that matches the cancelled IRP */
1209 while (Entry != &RxActiveContexts)
1210 {
1211 RxContext = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1212 Entry = Entry->Flink;
1213
1214 /* Found! */
1215 if (RxContext->CurrentIrp == Irp)
1216 {
1217 break;
1218 }
1219 }
1220
1221 /* If we reached the end of the list, we didn't find any context, so zero the buffer
1222 * If the context is already under cancellation, forget about it too
1223 */
1225 {
1226 RxContext = NULL;
1227 }
1228 else
1229 {
1230 /* Otherwise, reference it and mark it cancelled */
1232 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
1233 }
1234
1235 /* Done with the contexts list */
1237
1238 /* And done with the cancellation, we'll do it now */
1239 IoReleaseCancelSpinLock(Irp->CancelIrql);
1240
1241 /* If we have a context to cancel */
1242 if (RxContext != NULL)
1243 {
1244 /* We cannot executed at dispatch, so queue a deferred cancel */
1246 {
1248 }
1249 /* Cancel now! */
1250 else
1251 {
1252 RxpCancelRoutine(RxContext);
1253 }
1254 }
1255}
1256
1257/*
1258 * @implemented
1259 */
1262 PRX_CONTEXT RxContext,
1263 PUNICODE_STRING NetRootName)
1264{
1265 USHORT NextChar, CurChar;
1266 USHORT MaxChars;
1267
1268 PAGED_CODE();
1269
1270 /* Validate file name is not empty */
1271 MaxChars = NetRootName->Length / sizeof(WCHAR);
1272 if (MaxChars == 0)
1273 {
1275 }
1276
1277 /* Validate name is correct */
1278 for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
1279 {
1280 USHORT i;
1281
1282 for (i = NextChar + 1; i < MaxChars; ++i)
1283 {
1284 if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
1285 {
1286 break;
1287 }
1288 }
1289
1290 CurChar = i - 1;
1291 if (CurChar == NextChar)
1292 {
1293 if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
1294 {
1295 continue;
1296 }
1297
1298 if (CurChar != 0)
1299 {
1300 if (CurChar >= MaxChars - 1)
1301 {
1302 continue;
1303 }
1304
1305 if (NetRootName->Buffer[CurChar + 1] != ':')
1306 {
1308 }
1309 }
1310 else
1311 {
1312 if (NetRootName->Buffer[1] != ':')
1313 {
1315 }
1316 }
1317 }
1318 else
1319 {
1320 if ((CurChar - NextChar) == 1)
1321 {
1322 if (NetRootName->Buffer[NextChar + 2] != '.')
1323 {
1324 continue;
1325 }
1326
1327 if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
1328 {
1330 }
1331 }
1332 else
1333 {
1334 if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
1335 || NetRootName->Buffer[NextChar + 1] != '.')
1336 {
1337 continue;
1338 }
1339
1340 if (NetRootName->Buffer[NextChar + 2] == '.')
1341 {
1343 }
1344 }
1345 }
1346 }
1347
1349}
1350
1353 PRX_CONTEXT RxContext,
1355 PUNICODE_STRING NetRootName)
1356{
1358 NET_ROOT_TYPE NetRootType;
1359 UNICODE_STRING CanonicalName;
1360
1363
1364 PAGED_CODE();
1365
1366 NetRootType = NET_ROOT_WILD;
1367
1368 RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1369 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1370
1371 /* if not relative opening, just handle the passed name */
1372 if (capFileObject->RelatedFileObject == NULL)
1373 {
1374 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1375 if (!NT_SUCCESS(Status))
1376 {
1377 return Status;
1378 }
1379 }
1380 else
1381 {
1382 PFCB Fcb;
1383
1384 /* Make sure we have a valid FCB and a FOBX */
1385 Fcb = capFileObject->RelatedFileObject->FsContext;
1386 if (Fcb == NULL || capFileObject->RelatedFileObject->FsContext2 == NULL)
1387 {
1389 }
1390
1391 if (!NodeTypeIsFcb(Fcb))
1392 {
1394 }
1395
1397 }
1398
1399 /* Get/Create the associated VNetRoot for opening */
1400 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1401 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1403 {
1404 ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1405
1406 RxFreeCanonicalNameBuffer(RxContext);
1407 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1408 if (NT_SUCCESS(Status))
1409 {
1410 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1411 }
1412 }
1413
1414 /* Filename cannot contain wildcards */
1415 if (FsRtlDoesNameContainWildCards(NetRootName))
1416 {
1418 }
1419
1420 /* Make sure file name is correct */
1421 if (NT_SUCCESS(Status))
1422 {
1423 Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1424 }
1425
1426 /* Give the mini-redirector a chance to prepare the name */
1428 {
1429 if (RxContext->Create.pNetRoot != NULL)
1430 {
1431 NTSTATUS IgnoredStatus;
1432
1433 MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1434 MRxPreparseName, (RxContext, NetRootName));
1435 (void)IgnoredStatus;
1436 }
1437 }
1438
1439 return Status;
1440}
1441
1442/*
1443 * @implemented
1444 */
1445VOID
1446NTAPI
1448 VOID)
1449{
1450 PAGED_CODE();
1451}
1452
1453#if DBG
1461 _In_ PSZ where,
1462 _In_ PSZ wherelogtag)
1463{
1464 PAGED_CODE();
1465
1466 RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1467 RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1468
1470}
1471#endif
1472
1473/*
1474 * @implemented
1475 */
1478 IN PFCB Fcb,
1481{
1484 BOOLEAN DeleteAccess;
1486
1487 PAGED_CODE();
1488
1490
1491 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1492 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1493
1494 /* Check if any access wanted */
1497 DeleteAccess = (DesiredAccess & DELETE) != 0;
1498
1499 if (ReadAccess || WriteAccess || DeleteAccess)
1500 {
1501 BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1502 BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1503 BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1504
1505 /* Check whether there's a violation */
1506 if ((ReadAccess &&
1507 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1508 (WriteAccess &&
1509 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1510 (DeleteAccess &&
1511 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1512 ((ShareAccess->Readers != 0) && !SharedRead) ||
1513 ((ShareAccess->Writers != 0) && !SharedWrite) ||
1514 ((ShareAccess->Deleters != 0) && !SharedDelete))
1515 {
1517 }
1518 }
1519
1520 return STATUS_SUCCESS;
1521}
1522
1523VOID
1526{
1528}
1529
1530/*
1531 * @implemented
1532 */
1535 IN PFOBX Fobx,
1536 IN PRX_CONTEXT RxContext OPTIONAL)
1537{
1538 PFCB Fcb;
1540 PSRV_OPEN SrvOpen;
1541 BOOLEAN CloseSrvOpen;
1542 PRX_CONTEXT LocalContext;
1543
1544 PAGED_CODE();
1545
1546 /* Assume SRV_OPEN is already closed */
1547 CloseSrvOpen = FALSE;
1548 /* If we have a FOBX, we'll have to close it */
1549 if (Fobx != NULL)
1550 {
1551 /* If the FOBX isn't closed yet */
1552 if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1553 {
1554 SrvOpen = Fobx->SrvOpen;
1555 Fcb = (PFCB)SrvOpen->pFcb;
1556 /* Check whether we've to close SRV_OPEN first */
1557 if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1558 {
1559 CloseSrvOpen = TRUE;
1560 }
1561 else
1562 {
1564
1565 /* Not much to do */
1566 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1567
1568 if (SrvOpen->OpenCount > 0)
1569 {
1570 --SrvOpen->OpenCount;
1571 }
1572 }
1573 }
1574
1575 /* No need to close SRV_OPEN, so close FOBX */
1576 if (!CloseSrvOpen)
1577 {
1578 RxMarkFobxOnClose(Fobx);
1579
1580 return STATUS_SUCCESS;
1581 }
1582 }
1583 else
1584 {
1585 /* No FOBX? No RX_CONTEXT, ok, job done! */
1586 if (RxContext == NULL)
1587 {
1588 return STATUS_SUCCESS;
1589 }
1590
1591 /* Get the FCB from RX_CONTEXT */
1592 Fcb = (PFCB)RxContext->pFcb;
1593 SrvOpen = NULL;
1594 }
1595
1596 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1597 if (RxContext == NULL)
1598 {
1599 ASSERT(Fobx != NULL);
1600
1602 if (LocalContext == NULL)
1603 {
1605 }
1606
1607 LocalContext->MajorFunction = 2;
1608 LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1609 LocalContext->pFobx = (PMRX_FOBX)Fobx;
1610 LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1611 }
1612 else
1613 {
1614 LocalContext = RxContext;
1615 }
1616
1618
1619 /* Now, close the FOBX */
1620 if (Fobx != NULL)
1621 {
1622 RxMarkFobxOnClose(Fobx);
1623 }
1624 else
1625 {
1626 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1627 }
1628
1629 /* If not a "standard" file, SRV_OPEN can be null */
1630 if (SrvOpen == NULL)
1631 {
1634
1635 if (LocalContext != RxContext)
1636 {
1637 RxDereferenceAndDeleteRxContext(LocalContext);
1638 }
1639
1640 return STATUS_SUCCESS;
1641 }
1642
1643 /* If SRV_OPEN isn't in a good condition, nothing to close */
1644 if (SrvOpen->Condition != Condition_Good)
1645 {
1646 if (LocalContext != RxContext)
1647 {
1648 RxDereferenceAndDeleteRxContext(LocalContext);
1649 }
1650
1651 return STATUS_SUCCESS;
1652 }
1653
1654 /* Decrease open count */
1655 if (SrvOpen->OpenCount > 0)
1656 {
1657 --SrvOpen->OpenCount;
1658 }
1659
1660 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1661 if (SrvOpen->OpenCount == 1)
1662 {
1663 if (!IsListEmpty(&SrvOpen->FobxList))
1664 {
1665 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1666 {
1667 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1668 }
1669 }
1670 }
1671
1672 /* Nothing left, purge FCB */
1673 if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1674 {
1675 RxPurgeNetFcb(Fcb, LocalContext);
1676 }
1677
1678 /* Already closed? Job done! */
1679 SrvOpen = Fobx->SrvOpen;
1680 if (SrvOpen == NULL ||
1681 (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1682 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1683 {
1684 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1685 if (LocalContext != RxContext)
1686 {
1687 RxDereferenceAndDeleteRxContext(LocalContext);
1688 }
1689
1690 return STATUS_SUCCESS;
1691 }
1692
1694
1695 /* Inform mini-rdr about closing */
1696 MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1697 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1698 Status, RxContext, Fobx, Fcb, SrvOpen);
1699
1700 /* And mark as such */
1701 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1702 SrvOpen->Key = (PVOID)-1;
1703
1704 /* If we were delayed, we're not! */
1705 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1706 {
1707 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1708 }
1709
1710 /* Clear access */
1713
1714 /* Dereference */
1716
1717 /* Mark the FOBX closed as well */
1718 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1719
1720 if (LocalContext != RxContext)
1721 {
1722 RxDereferenceAndDeleteRxContext(LocalContext);
1723 }
1724
1725 return Status;
1726}
1727
1728/*
1729 * @implemented
1730 */
1733 PRX_CONTEXT RxContext)
1734{
1737 PSRV_OPEN SrvOpen;
1740 RX_BLOCK_CONDITION FcbCondition;
1741
1744
1745 PAGED_CODE();
1746
1747 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1748
1750 ++capFcb->UncleanCount;
1751
1752 DesiredAccess = capPARAMS->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1753 ShareAccess = capPARAMS->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1754
1755 Disposition = RxContext->Create.NtCreateParameters.Disposition;
1756
1757 /* Try to find a reusable SRV_OPEN */
1759 if (Status == STATUS_NOT_FOUND)
1760 {
1761 /* If none found, create one */
1762 SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, capFcb);
1763 if (SrvOpen == NULL)
1764 {
1766 }
1767 else
1768 {
1769 SrvOpen->DesiredAccess = DesiredAccess;
1770 SrvOpen->ShareAccess = ShareAccess;
1772 }
1773
1774 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1775
1776 if (Status != STATUS_SUCCESS)
1777 {
1778 FcbCondition = Condition_Bad;
1779 }
1780 else
1781 {
1783
1784 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1785 RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1786 /* Inform the mini-rdr we're handling a create */
1787 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCreate, (RxContext));
1788 ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1789
1790 DPRINT("MRxCreate returned: %x\n", Status);
1791 if (Status == STATUS_SUCCESS)
1792 {
1793 /* In case of overwrite, reset file size */
1795 {
1797 capFcb->Header.AllocationSize.QuadPart = 0LL;
1798 capFcb->Header.FileSize.QuadPart = 0LL;
1799 capFcb->Header.ValidDataLength.QuadPart = 0LL;
1800 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
1801 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
1803 }
1804 else
1805 {
1806 /* Otherwise, adjust sizes */
1807 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
1808 if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1809 {
1811 }
1812 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
1813 }
1814 }
1815
1816 /* Set the IoStatus with information returned by mini-rdr */
1817 RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1818
1819 SrvOpen->OpenStatus = Status;
1820 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1822
1824
1826
1827 if (Status == STATUS_SUCCESS)
1828 {
1829 if (BooleanFlagOn(capPARAMS->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1830 {
1832 }
1833 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1834 FcbCondition = Condition_Good;
1835 }
1836 else
1837 {
1838 FcbCondition = Condition_Bad;
1840 RxContext->pRelevantSrvOpen = NULL;
1841
1842 if (RxContext->pFobx != NULL)
1843 {
1845 RxContext->pFobx = NULL;
1846 }
1847 }
1848 }
1849
1850 /* Set FCB state - good or bad - depending on whether create succeed */
1851 DPRINT("Transitioning FCB %p to condition %lx\n", capFcb, capFcb->Condition);
1852 RxTransitionNetFcb(capFcb, FcbCondition);
1853 }
1854 else if (Status == STATUS_SUCCESS)
1855 {
1856 BOOLEAN IsGood, ExtraOpen;
1857
1858 /* A reusable SRV_OPEN was found */
1860 ExtraOpen = FALSE;
1861
1862 SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1863
1864 IsGood = (SrvOpen->Condition == Condition_Good);
1865 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1866 if (!StableCondition(SrvOpen->Condition))
1867 {
1868 RxReferenceSrvOpen(SrvOpen);
1869 ++SrvOpen->OpenCount;
1870 ExtraOpen = TRUE;
1871
1872 RxReleaseFcb(RxContext, capFcb);
1873 RxContext->Create.FcbAcquired = FALSE;
1874
1875 RxWaitForStableSrvOpen(SrvOpen, RxContext);
1876
1877 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, capFcb)))
1878 {
1879 RxContext->Create.FcbAcquired = TRUE;
1880 }
1881
1882 IsGood = (SrvOpen->Condition == Condition_Good);
1883 }
1884
1885 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1886 if (IsGood)
1887 {
1888 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1889
1891 }
1892 else
1893 {
1894 Status = SrvOpen->OpenStatus;
1895 }
1896
1897 if (ExtraOpen)
1898 {
1899 --SrvOpen->OpenCount;
1901 }
1902 }
1903
1904 --capFcb->UncleanCount;
1905
1906 DPRINT("Status: %x\n", Status);
1907 return Status;
1908}
1909
1910/*
1911 * @implemented
1912 */
1914NTAPI
1917{
1918#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1919 PFCB Fcb;
1920 PFOBX Fobx;
1923 PNET_ROOT NetRoot;
1925 LARGE_INTEGER TruncateSize;
1926 PLARGE_INTEGER TruncateSizePtr;
1927 BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1928
1929 PAGED_CODE();
1930
1931 Fcb = (PFCB)Context->pFcb;
1932 Fobx = (PFOBX)Context->pFobx;
1933 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1934
1935 /* File system closing, it's OK */
1936 if (Fobx == NULL)
1937 {
1938 if (Fcb->UncleanCount > 0)
1939 {
1940 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1941 }
1942
1943 return STATUS_SUCCESS;
1944 }
1945
1946 /* Check we have a correct FCB type */
1951 {
1952 DPRINT1("Invalid Fcb type for %p\n", Fcb);
1953 RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1954 }
1955
1956 FileObject = Context->CurrentIrpSp->FileObject;
1958
1959 RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1960
1962 if (!NT_SUCCESS(Status))
1963 {
1964 return Status;
1965 }
1966
1967 FcbAcquired = TRUE;
1968
1969 Fobx->AssociatedFileObject = NULL;
1970
1971 /* In case it was already orphaned */
1973 {
1974 ASSERT(Fcb->UncleanCount != 0);
1975 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1976
1978 {
1979 --Fcb->UncachedUncleanCount;
1980 }
1981
1982 /* Inform mini-rdr */
1983 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1984
1985 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1986 --Fobx->SrvOpen->UncleanFobxCount;
1987
1989
1991
1992 return STATUS_SUCCESS;
1993 }
1994
1995 /* Report the fact that file could be set as delete on close */
1996 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1997 {
1999 }
2000
2001 /* Cancel any pending notification */
2003
2004 /* Backup open count before we start playing with it */
2006
2007 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2008 FcbTableAcquired = FALSE;
2009 LeftForDelete = FALSE;
2010 OneLeft = (Fcb->UncleanCount == 1);
2011
2012 _SEH2_TRY
2013 {
2014 /* Unclean count and delete on close? Verify whether we're the one */
2016 {
2018 {
2019 FcbTableAcquired = TRUE;
2020 }
2021 else
2022 {
2024
2026
2028 if (Status != STATUS_SUCCESS)
2029 {
2031 return Status;
2032 }
2033
2034 FcbTableAcquired = TRUE;
2035 }
2036
2037 /* That means we'll perform the delete on close! */
2038 if (Fcb->UncleanCount == 1)
2039 {
2040 LeftForDelete = TRUE;
2041 }
2042 else
2043 {
2045 FcbTableAcquired = FALSE;
2046 }
2047 }
2048
2049 IsFile = FALSE;
2050 TruncateSizePtr = NULL;
2051 /* Handle cleanup for pipes and printers */
2052 if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
2053 {
2055 }
2056 /* Handle cleanup for files */
2057 else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
2058 {
2059 Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
2061 {
2062 /* First, unlock */
2064
2065 /* If there are still locks to release, proceed */
2066 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
2067 {
2069 Context->LowIoContext.ParamsFor.Locks.Flags = 0;
2071 }
2072
2073 /* Fix times and size */
2075
2076 /* If we're the only one left... */
2077 if (OneLeft)
2078 {
2079 /* And if we're supposed to delete on close */
2080 if (LeftForDelete)
2081 {
2082 /* Update the sizes */
2084 Fcb->Header.FileSize.QuadPart = 0;
2085 Fcb->Header.ValidDataLength.QuadPart = 0;
2087 }
2088 /* Otherwise, call the mini-rdr to adjust sizes */
2089 else
2090 {
2091 /* File got grown up, fill with zeroes */
2093 (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
2094 {
2095 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
2096 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
2097 }
2098
2099 /* File was truncated, let mini-rdr proceed */
2101 {
2102 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
2104
2105 /* Keep track of file change for Cc uninit */
2106 TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
2107 TruncateSizePtr = &TruncateSize;
2108 }
2109 }
2110 }
2111
2112 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
2113 if (NeedPurge)
2114 {
2115 if (!OneLeft)
2116 {
2117 NeedPurge = FALSE;
2118 }
2119 }
2120 /* Otherwise, try to see whether we can purge */
2121 else
2122 {
2123 NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
2124 }
2125
2126 IsFile = TRUE;
2127 }
2128 }
2129
2130 /* We have to still be there! */
2131 ASSERT(Fcb->UncleanCount != 0);
2132 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
2133
2135 {
2136 --Fcb->UncachedUncleanCount;
2137 }
2138
2139 /* Inform mini-rdr about ongoing cleanup */
2140 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
2141
2142 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
2143 --Fobx->SrvOpen->UncleanFobxCount;
2144
2145 /* Flush cache */
2147 {
2148 /* Only if we're the last standing */
2150 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
2151 {
2152 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
2154 }
2155 }
2156 else
2157 {
2158 /* Always */
2160 {
2161 DPRINT("Flushing %p on cleanup\n", Context);
2163 }
2164 }
2165
2166 /* If only remaining uncached & unclean, then flush and purge */
2168 {
2169 if (Fcb->UncachedUncleanCount != 0)
2170 {
2171 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
2173 {
2174 DPRINT("Flushing FCB in system cache for %p\n", Context);
2176 }
2177 }
2178 }
2179
2180 /* If purge required, and not about to delete, flush */
2181 if (!LeftForDelete && NeedPurge)
2182 {
2183 DPRINT("Flushing FCB in system cache for %p\n", Context);
2185 }
2186
2187 /* If it was a file, drop cache */
2188 if (IsFile)
2189 {
2190 DPRINT("Uninit cache map for file\n");
2191 RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
2192 }
2193
2194 /* If that's the one left for deletion, or if it needs purge, flush */
2195 if (LeftForDelete || NeedPurge)
2196 {
2197 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
2198 /* If that's for deletion, also remove from FCB table */
2199 if (LeftForDelete)
2200 {
2203 FcbTableAcquired = FALSE;
2204 }
2205 }
2206
2207 /* Remove any share access */
2208 if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
2209 {
2210 RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
2211 }
2212
2213 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2214 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
2215 RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
2216 {
2217 NTSTATUS InternalStatus;
2218 PRX_CONTEXT InternalContext;
2219
2220 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2221 InternalStatus = STATUS_UNSUCCESSFUL;
2222 InternalContext = RxCreateRxContext(Context->CurrentIrp,
2225 if (InternalContext != NULL)
2226 {
2228
2229 InternalStatus = STATUS_SUCCESS;
2230
2231 /* Initialize the context for file information set */
2232 InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
2233 InternalContext->pFobx = (PMRX_FOBX)Fobx;
2234 InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
2235
2236 /* Get EOF from the FCB */
2237 FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
2238 InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
2239 InternalContext->Info.Buffer = &FileEOF;
2240 InternalContext->Info.Length = sizeof(FileEOF);
2241
2242 /* Call the mini-rdr */
2243 MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
2244
2245 /* We're done */
2246 RxDereferenceAndDeleteRxContext(InternalContext);
2247 }
2248
2249 /* We tried, so, clean the FOBX flag */
2250 ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
2251 /* If it failed, then, disable collapsing on the FCB */
2252 if (!NT_SUCCESS(InternalStatus))
2253 {
2255 }
2256 }
2257
2258 /* We're clean! */
2260
2261 FcbAcquired = FALSE;
2263 }
2265 {
2266 if (FcbAcquired)
2267 {
2269 }
2270
2271 if (FcbTableAcquired)
2272 {
2274 }
2275 }
2276 _SEH2_END;
2277
2278 return Status;
2279#undef BugCheckFileId
2280}
2281
2283NTAPI
2286{
2287#define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2288 PFCB Fcb;
2289 PFOBX Fobx;
2292 BOOLEAN DereferenceFobx, AcquiredFcb;
2293
2294 PAGED_CODE();
2295
2296 Fcb = (PFCB)Context->pFcb;
2297 Fobx = (PFOBX)Context->pFobx;
2298 FileObject = Context->CurrentIrpSp->FileObject;
2299 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
2300
2302 if (!NT_SUCCESS(Status))
2303 {
2304 return Status;
2305 }
2306
2307 AcquiredFcb = TRUE;
2308 _SEH2_TRY
2309 {
2310 BOOLEAN Freed;
2311
2312 /* Check our FCB type is expected */
2316 {
2317 RxBugCheck(NodeType(Fcb), 0, 0);
2318 }
2319
2321
2322 DereferenceFobx = FALSE;
2323 /* If we're not closing FS */
2324 if (Fobx != NULL)
2325 {
2326 PSRV_OPEN SrvOpen;
2327 PSRV_CALL SrvCall;
2328
2329 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
2330 SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
2331 /* Handle delayed close */
2333 {
2335 {
2337 {
2338 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
2339
2340 if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
2341 {
2342 if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
2343 {
2345 }
2346 else
2347 {
2348 DereferenceFobx = TRUE;
2349 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
2350 }
2351 }
2352 }
2353 }
2354 }
2355
2356 /* If we reach maximum of delayed close/or if there are no delayed close */
2357 if (!DereferenceFobx)
2358 {
2359 PNET_ROOT NetRoot;
2360
2361 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2362 if (NetRoot->Type != NET_ROOT_PRINT)
2363 {
2364 /* Delete if asked */
2365 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
2366 {
2369
2371
2375
2378 }
2379 }
2380 }
2381
2382 RxMarkFobxOnClose(Fobx);
2383 }
2384
2385 if (DereferenceFobx)
2386 {
2387 ASSERT(Fobx != NULL);
2389 }
2390 else
2391 {
2393 if (Fobx != NULL)
2394 {
2396 }
2397 }
2398
2400 AcquiredFcb = !Freed;
2401
2402 FileObject->FsContext = (PVOID)-1;
2403
2404 if (Freed)
2405 {
2406 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2407 }
2408 else
2409 {
2411 AcquiredFcb = FALSE;
2412 }
2413 }
2415 {
2417 {
2418 if (AcquiredFcb)
2419 {
2421 }
2422 }
2423 else
2424 {
2425 ASSERT(!AcquiredFcb);
2426 }
2427 }
2428 _SEH2_END;
2429
2430 DPRINT("Status: %x\n", Status);
2431 return Status;
2432#undef BugCheckFileId
2433}
2434
2435/*
2436 * @implemented
2437 */
2439NTAPI
2442{
2443 PIRP Irp;
2447
2448 PAGED_CODE();
2449
2450 DPRINT("RxCommonCreate(%p)\n", Context);
2451
2452 Irp = Context->CurrentIrp;
2453 Stack = Context->CurrentIrpSp;
2454 FileObject = Stack->FileObject;
2455
2456 /* Check whether that's a device opening */
2457 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2458 {
2459 FileObject->FsContext = &RxDeviceFCB;
2460 FileObject->FsContext2 = NULL;
2461
2462 ++RxDeviceFCB.NodeReferenceCount;
2464
2465 Irp->IoStatus.Information = FILE_OPENED;
2466 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2467
2469 }
2470 else
2471 {
2472 PFCB RelatedFcb = NULL;
2473
2474 /* Make sure caller is consistent */
2477 {
2478 DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2480 }
2481
2482 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2483 Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2484 Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2485 DPRINT("FileName: %wZ\n", &FileObject->FileName);
2486
2487 if (FileObject->RelatedFileObject != NULL)
2488 {
2489 RelatedFcb = FileObject->RelatedFileObject->FsContext;
2490 DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2491 }
2492
2493 /* Going to rename? */
2495 {
2496 DPRINT("TargetDir!\n");
2497 }
2498
2499 /* Copy create parameters to the context */
2501
2502 /* If the caller wants to establish a connection, go ahead */
2503 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2504 {
2506 }
2507 else
2508 {
2509 /* Validate file name */
2510 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2511 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2512 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2513 {
2514 FileObject->FileName.Length -= sizeof(WCHAR);
2515 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2516 FileObject->FileName.Length);
2517
2518 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2519 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2520 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2521 {
2523 }
2524 }
2525
2526 /* Attempt to open the file */
2527 do
2528 {
2529 UNICODE_STRING NetRootName;
2530
2531 /* Strip last \ if required */
2532 if (FileObject->FileName.Length != 0 &&
2533 FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2534 {
2535 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2536 {
2538 }
2539
2540 FileObject->FileName.Length -= sizeof(WCHAR);
2542 }
2543
2545 {
2546 FileObject->Flags |= FO_WRITE_THROUGH;
2547 }
2548
2549 /* Get the associated net root to opening */
2550 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2552 {
2553 break;
2554 }
2555
2556 /* And attempt to open */
2557 Status = RxCreateFromNetRoot(Context, &NetRootName);
2559 {
2561
2562 /* If that happens for file creation, fail for real */
2563 if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
2564 {
2566 }
2567 else
2568 {
2569 /* Otherwise, if possible, attempt to scavenger current FOBX
2570 * to check whether a dormant FOBX is the reason for sharing violation
2571 */
2572 if (Context->Create.TryForScavengingOnSharingViolation &&
2573 !Context->Create.ScavengingAlreadyTried)
2574 {
2575 /* Only doable with a VNetRoot */
2576 if (Context->Create.pVNetRoot != NULL)
2577 {
2578 PV_NET_ROOT VNetRoot;
2579 NT_CREATE_PARAMETERS SavedParameters;
2580
2581 /* Save create parameters */
2582 RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
2583
2584 /* Reference the VNetRoot for the scavenging time */
2585 VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
2586 RxReferenceVNetRoot(VNetRoot);
2587
2588 /* Prepare the RX_CONTEXT for reuse */
2591
2592 /* Copy what we saved */
2593 RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
2594
2595 /* And recopy what can be */
2597
2598 /* And start purging, then scavenging FOBX */
2599 RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
2601 RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
2602 NULL, TRUE);
2603
2604 /* Ask for a second round */
2606
2607 /* Keep track we already scavenged */
2608 Context->Create.ScavengingAlreadyTried = TRUE;
2609
2610 /* Reference our SRV_CALL for CBS handling */
2611 RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
2612 RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
2613
2614 /* Drop our extra reference */
2616 }
2617 }
2618 }
2619 }
2620 else if (Status == STATUS_REPARSE)
2621 {
2622 Context->CurrentIrp->IoStatus.Information = 0;
2623 }
2624 else
2625 {
2627 }
2628 }
2630 }
2631
2632 if (Status == STATUS_RETRY)
2633 {
2635 }
2637 }
2638
2639 DPRINT("Status: %lx\n", Status);
2640 return Status;
2641}
2642
2643/*
2644 * @implemented
2645 */
2647NTAPI
2650{
2651 PMRX_FCB Fcb;
2653
2654 PAGED_CODE();
2655
2656 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2657
2658 Fcb = Context->pFcb;
2661
2662 /* Our FOBX if set, has to be a VNetRoot */
2663 if (Context->pFobx != NULL)
2664 {
2665 RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2666 if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2667 {
2669 }
2670 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2671 }
2672 else
2673 {
2674 --Fcb->UncleanCount;
2675 }
2676
2677 return Status;
2678}
2679
2680/*
2681 * @implemented
2682 */
2684NTAPI
2687{
2688 PMRX_FCB Fcb;
2690 PMRX_V_NET_ROOT NetRoot;
2691
2692 PAGED_CODE();
2693
2694 DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2695
2696 Fcb = Context->pFcb;
2697 NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2700
2701 /* Our FOBX if set, has to be a VNetRoot */
2702 if (NetRoot != NULL)
2703 {
2704 RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2705 if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2706 {
2707 --NetRoot->NumberOfOpens;
2709 }
2710 else
2711 {
2713 }
2714 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2715 }
2716 else
2717 {
2718 --Fcb->OpenCount;
2719 }
2720
2721 return Status;
2722}
2723
2725NTAPI
2728{
2731}
2732
2733/*
2734 * @implemented
2735 */
2737NTAPI
2740{
2742
2743 PAGED_CODE();
2744
2745 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2746
2747 if (Context->pFobx != NULL)
2748 {
2749 return STATUS_INVALID_HANDLE;
2750 }
2751
2752 /* Is that a prefix claim from MUP? */
2753 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2754 {
2755 return RxPrefixClaim(Context);
2756 }
2757
2758 /* Otherwise, pass through the mini-rdr */
2760 if (Status != STATUS_PENDING)
2761 {
2762 if (Context->PostRequest)
2763 {
2764 Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2766 }
2767 }
2768
2769 DPRINT("Status: %lx\n", Status);
2770 return Status;
2771}
2772
2774NTAPI
2777{
2780}
2781
2782/*
2783 * @implemented
2784 */
2786NTAPI
2789{
2791
2792 PAGED_CODE();
2793
2794 /* Prefix claim is only allowed for device, not files */
2795 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2796 {
2798 }
2799
2800 /* Submit to mini-rdr */
2803 if (Status == STATUS_PENDING)
2804 {
2806 }
2807
2808 return Status;
2809}
2810
2811/*
2812 * @implemented
2813 */
2815NTAPI
2818{
2819 PFCB Fcb;
2820 PFOBX Fobx;
2823
2824 PAGED_CODE();
2825
2826 Fcb = (PFCB)Context->pFcb;
2827 Fobx = (PFOBX)Context->pFobx;
2828 Stack = Context->CurrentIrpSp;
2829 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2830
2831 /* Call the appropriate helper */
2832 if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2833 {
2835 }
2836 else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2837 {
2839 if (Status == STATUS_PENDING)
2840 {
2842 }
2843 }
2844 else
2845 {
2847 }
2848
2849 return Status;
2850}
2851
2853NTAPI
2856{
2859}
2860
2862NTAPI
2865{
2866 PIRP Irp;
2869
2870 PAGED_CODE();
2871
2872 Irp = Context->CurrentIrp;
2873 Stack = Context->CurrentIrpSp;
2874 ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
2875
2876 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
2877
2880}
2881
2883NTAPI
2886{
2889}
2890
2892NTAPI
2895{
2898}
2899
2901NTAPI
2904{
2907}
2908
2909/*
2910 * @implemented
2911 */
2913NTAPI
2916{
2917#define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2918 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2919 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2920
2921 PFCB Fcb;
2922 PIRP Irp;
2923 PFOBX Fobx;
2927 FILE_INFORMATION_CLASS FileInfoClass;
2928
2929 PAGED_CODE();
2930
2931 Fcb = (PFCB)Context->pFcb;
2932 Fobx = (PFOBX)Context->pFobx;
2933 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2934
2935 Irp = Context->CurrentIrp;
2936 Stack = Context->CurrentIrpSp;
2937 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2938 Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2939
2940 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2941 FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2942
2943 Locked = FALSE;
2944 _SEH2_TRY
2945 {
2946 PVOID Buffer;
2947
2948 /* Get a writable buffer */
2950 if (Buffer == NULL)
2951 {
2954 }
2955 /* Zero it */
2956 RtlZeroMemory(Buffer, Context->Info.Length);
2957
2958 /* Validate file type */
2960 {
2962 {
2965 }
2967 {
2969 {
2971 }
2972 else
2973 {
2975 }
2976
2978 }
2979 }
2980
2981 /* Acquire the right lock */
2983 FileInfoClass != FileNameInformation)
2984 {
2985 if (FileInfoClass == FileCompressionInformation)
2986 {
2988 }
2989 else
2990 {
2992 }
2993
2995 {
2998 }
2999 else if (!NT_SUCCESS(Status))
3000 {
3002 }
3003
3004 Locked = TRUE;
3005 }
3006
3007 /* Dispatch to the right helper */
3008 switch (FileInfoClass)
3009 {
3012 break;
3013
3016 break;
3017
3020 break;
3021
3022 case FileEaInformation:
3024 break;
3025
3028 break;
3029
3030 case FileAllInformation:
3032 if (!NT_SUCCESS(Status))
3033 {
3034 break;
3035 }
3036
3038 if (!NT_SUCCESS(Status))
3039 {
3040 break;
3041 }
3042
3045 if (!NT_SUCCESS(Status))
3046 {
3047 break;
3048 }
3049
3053 if (!NT_SUCCESS(Status))
3054 {
3055 break;
3056 }
3057
3062 if (!NT_SUCCESS(Status))
3063 {
3064 break;
3065 }
3066
3070 sizeof(FILE_EA_INFORMATION) +
3072 break;
3073
3076 break;
3077
3082 break;
3083
3086 break;
3087
3088 default:
3089 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
3090 Status = Context->IoStatusBlock.Status;
3091 break;
3092 }
3093
3094 if (Context->Info.Length < 0)
3095 {
3097 Context->Info.Length = Stack->Parameters.QueryFile.Length;
3098 }
3099
3100 Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
3101 }
3103 {
3104 if (Locked)
3105 {
3107 }
3108 }
3109 _SEH2_END;
3110
3111 DPRINT("Status: %x\n", Status);
3112 return Status;
3113
3114#undef SET_SIZE_AND_QUERY
3115}
3116
3118NTAPI
3121{
3124}
3125
3127NTAPI
3130{
3133}
3134
3135/*
3136 * @implemented
3137 */
3139NTAPI
3142{
3143 PIRP Irp;
3144 PFCB Fcb;
3145 PFOBX Fobx;
3148
3149 PAGED_CODE();
3150
3151 Fcb = (PFCB)Context->pFcb;
3152 Fobx = (PFOBX)Context->pFobx;
3153
3154 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3155
3156 Irp = Context->CurrentIrp;
3157 Stack = Context->CurrentIrpSp;
3158 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
3159 Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
3160
3161 Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
3162 Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
3163 Context->Info.Length = Stack->Parameters.QueryVolume.Length;
3164
3165 /* Forward to mini-rdr */
3166 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
3167
3168 /* Post request if mini-rdr asked to */
3169 if (Context->PostRequest)
3170 {
3172 }
3173 else
3174 {
3175 Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
3176 }
3177
3178 DPRINT("Status: %x\n", Status);
3179 return Status;
3180}
3181
3183NTAPI
3185 PRX_CONTEXT RxContext)
3186{
3187 PFCB Fcb;
3188 PIRP Irp;
3189 PFOBX Fobx;
3191 PNET_ROOT NetRoot;
3192 PVOID SystemBuffer;
3196 PLOWIO_CONTEXT LowIoContext;
3197 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3198 ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3199 BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
3200
3201 PAGED_CODE();
3202
3203 Fcb = (PFCB)RxContext->pFcb;
3204 Fobx = (PFOBX)RxContext->pFobx;
3205 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3206
3207 /* Get some parameters */
3208 Irp = RxContext->CurrentIrp;
3209 Stack = RxContext->CurrentIrpSp;
3210 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3211 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3212 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3214 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3215 ReadLength = Stack->Parameters.Read.Length;
3216 ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
3217 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
3218 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3219
3221
3222 Irp->IoStatus.Information = 0;
3223
3224 /* Should the read be loud - so far, it's just ignored on ReactOS:
3225 * s/DPRINT/DPRINT1/g will make it loud
3226 */
3227 LowIoContext = &RxContext->LowIoContext;
3228 CheckForLoudOperations(RxContext);
3230 {
3231 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3233 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3234 }
3235
3236 RxDeviceObject = RxContext->RxDeviceObject;
3237 /* Update stats */
3238 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3239 {
3240 InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
3241
3242 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
3243 {
3244 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
3245 }
3246 Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
3247
3248 if (PagingIo)
3249 {
3251 }
3252 else if (NoCache)
3253 {
3255 }
3256 else
3257 {
3259 }
3260 }
3261
3262 /* A pagefile cannot be a pipe */
3263 IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
3264 if (IsPipe && PagingIo)
3265 {
3267 }
3268
3269 /* Null-length read is no-op */
3270 if (ReadLength == 0)
3271 {
3272 return STATUS_SUCCESS;
3273 }
3274
3275 /* Validate FCB type */
3277 {
3279 }
3280
3281 /* Init the lowio context for possible forward */
3283
3284 PostRequest = FALSE;
3285 ReadCachingDisabled = FALSE;
3286 OwnerSet = FALSE;
3288 FileObject = Stack->FileObject;
3289 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3290 _SEH2_TRY
3291 {
3293
3294 /* If no caching, make sure current Cc data have been flushed */
3295 if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
3296 {
3297 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
3299 {
3300 PostRequest = TRUE;
3302 }
3303 else if (Status != STATUS_SUCCESS)
3304 {
3306 }
3307
3308 ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
3309 CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
3310 RxReleasePagingIoResource(RxContext, Fcb);
3311
3312 if (!NT_SUCCESS(Irp->IoStatus.Status))
3313 {
3314 Status = Irp->IoStatus.Status;
3316 }
3317
3318 RxAcquirePagingIoResource(RxContext, Fcb);
3319 RxReleasePagingIoResource(RxContext, Fcb);
3320 }
3321
3322 /* Acquire the appropriate lock */
3323 if (PagingIo && !ReadCachingEnabled)
3324 {
3325 ASSERT(!IsPipe);
3326
3327 if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
3328 {
3329 PostRequest = TRUE;
3331 }
3332
3333 if (!CanWait)
3334 {
3335 LowIoContext->Resource = Fcb->Header.PagingIoResource;
3336 }
3337 }
3338 else
3339 {
3340 if (!ReadCachingEnabled)
3341 {
3342 if (!CanWait && NoCache)
3343 {
3346 {
3347 DPRINT1("RdAsyLNG %x\n", RxContext);
3348 PostRequest = TRUE;
3350 }
3351 if (Status != STATUS_SUCCESS)
3352 {
3353 DPRINT1("RdAsyOthr %x\n", RxContext);
3355 }
3356
3357 if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3358 {
3359 LowIoContext->Resource = Fcb->Header.Resource;
3360 }
3361 else
3362 {
3363 PostRequest = TRUE;
3365 }
3366 }
3367 else
3368 {
3369 Status = RxAcquireSharedFcb(RxContext, Fcb);
3371 {
3372 PostRequest = TRUE;
3374 }
3375 else if (Status != STATUS_SUCCESS)
3376 {
3378 }
3379 }
3380 }
3381 }
3382
3384
3385 ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3386 if (IsPipe)
3387 {
3389 }
3390
3392
3393 /* Make sure FLOCK doesn't conflict */
3394 if (!PagingIo)
3395 {
3397 {
3400 }
3401 }
3402
3403 /* Validate byteoffset vs length */
3405 {
3406 if (ByteOffset.QuadPart >= FileSize)
3407 {
3410 }
3411
3412 if (ReadLength > FileSize - ByteOffset.QuadPart)
3413 {
3414 ReadLength = FileSize - ByteOffset.QuadPart;
3415 }
3416 }
3417
3418 /* Read with Cc! */
3419 if (!PagingIo && !NoCache && ReadCachingEnabled &&
3420 !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
3421 {
3422 /* File was not cached yet, do it */
3423 if (FileObject->PrivateCacheMap == NULL)
3424 {
3426 {
3429 }
3430
3432
3435
3437 {
3439 }
3440 else
3441 {
3444 }
3445
3446 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3447 }
3448
3449 /* This should never happen - fix your RDR */
3450 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3451 {
3452 ASSERT(FALSE);
3453 ASSERT(CanWait);
3454
3455 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3456 Status = Irp->IoStatus.Status;
3458 }
3459 else
3460 {
3461 /* Map buffer */
3462 SystemBuffer = RxNewMapUserBuffer(RxContext);
3463 if (SystemBuffer == NULL)
3464 {
3467 }
3468
3470
3472
3473 /* Perform the read */
3474 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3475 {
3476 if (!ReadCachingEnabled)
3477 {
3479 }
3480
3482
3483 PostRequest = TRUE;
3485 }
3486
3487 if (!ReadCachingEnabled)
3488 {
3490 }
3491
3492 Status = Irp->IoStatus.Status;
3494 }
3495 }
3496 else
3497 {
3498 /* Validate the reading */
3499 if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3500 ByteOffset.QuadPart >= 4096)
3501 {
3504 }
3505
3506 /* If it's consistent, forward to mini-rdr */
3507 if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3508 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3509 {
3510 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3511 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3512
3514
3515 if (InFsp && ReadCachingDisabled)
3516 {
3517 ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3518 (PVOID)((ULONG_PTR)RxContext | 3));
3519 OwnerSet = TRUE;
3520 }
3521
3522 Status = RxLowIoReadShell(RxContext);
3523
3525 }
3526 else
3527 {
3528 if (ByteOffset.QuadPart > FileSize)
3529 {
3530 ReadLength = 0;
3531 Irp->IoStatus.Information = ReadLength;
3533 }
3534
3535 if (ByteOffset.QuadPart + ReadLength > FileSize)
3536 {
3537 ReadLength = FileSize - ByteOffset.QuadPart;
3538 }
3539
3540 SystemBuffer = RxNewMapUserBuffer(RxContext);
3541 RtlZeroMemory(SystemBuffer, ReadLength);
3542 Irp->IoStatus.Information = ReadLength;
3543 }
3544 }
3545 }
3547 {
3549
3550 /* Post if required */
3551 if (PostRequest)
3552 {
3553 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3554 Status = RxFsdPostRequest(RxContext);
3555 }
3556 else
3557 {
3558 /* Update FO in case of sync IO */
3559 if (!IsPipe && !PagingIo)
3560 {
3562 {
3563 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
3564 }
3565 }
3566 }
3567
3568 /* Set FastIo if read was a success */
3570 {
3571 if (!IsPipe && !PagingIo)
3572 {
3574 }
3575 }
3576
3577 /* In case we're done (not expected any further processing */
3578 if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
3579 {
3580 /* Release everything that can be */
3581 if (ReadCachingDisabled)
3582 {
3583 if (PagingIo)
3584 {
3585 if (OwnerSet)
3586 {
3587 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3588 }
3589 else
3590 {
3591 RxReleasePagingIoResource(RxContext, Fcb);
3592 }
3593 }
3594 else
3595 {
3596 if (OwnerSet)
3597 {
3598 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3599 }
3600 else
3601 {
3602 RxReleaseFcb(RxContext, Fcb);
3603 }
3604 }
3605 }
3606
3607 /* Dereference/Delete context */
3608 if (PostRequest)
3609 {
3611 }
3612 else
3613 {
3614 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
3615 {
3616 RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
3617 }
3618 }
3619
3620 /* We cannot return more than asked */
3621 if (Status == STATUS_SUCCESS)
3622 {
3623 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
3624 }
3625 }
3626 else
3627 {
3628 ASSERT(!Sync);
3629
3631 }
3632 }
3633 _SEH2_END;
3634
3635 return Status;
3636}
3637
3639NTAPI
3642{
3645}
3646
3647/*
3648 * @implemented
3649 */
3651NTAPI
3654{
3655 PIRP Irp;
3656 PFCB Fcb;
3657 PFOBX Fobx;
3659 PNET_ROOT NetRoot;
3662 BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
3663
3664 PAGED_CODE();
3665
3666 Fcb = (PFCB)Context->pFcb;
3667 Fobx = (PFOBX)Context->pFobx;
3668 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3669
3670 Irp = Context->CurrentIrp;
3671 Stack = Context->CurrentIrpSp;
3672 Class = Stack->Parameters.SetFile.FileInformationClass;
3673 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3674 Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
3675 Class, Stack->Parameters.SetFile.ReplaceIfExists);
3676
3678 CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
3679 FcbTableAcquired = FALSE;
3680 FcbAcquired = FALSE;
3681 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3682
3683#define _SEH2_TRY_RETURN(S) S; goto try_exit
3684
3685 _SEH2_TRY
3686 {
3687 /* Valide the node type first */
3690 {
3692 {
3694 {
3696 }
3697 }
3698 else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
3699 {
3701 {
3703 }
3704 else
3705 {
3706 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
3708 }
3709 }
3710 }
3711
3712 /* We don't autorize advance operation */
3713 if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
3714 {
3715 DPRINT1("Not allowed\n");
3716
3718 }
3719
3720 /* For these to classes, we'll have to deal with the FCB table (removal)
3721 * We thus need the exclusive FCB table lock
3722 */
3724 {
3725 RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
3727
3728 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
3729 {
3730 Context->PostRequest = TRUE;
3732 }
3733
3734 FcbTableAcquired = TRUE;
3735 }
3736
3737 /* Finally, if not paging file, we need exclusive FCB lock */
3739 {
3742 {
3743 Context->PostRequest = TRUE;
3745 }
3746 else if (Status != STATUS_SUCCESS)
3747 {
3749 }
3750
3751 FcbAcquired = TRUE;
3752 }
3753
3755
3756 /* And now, perform the job! */
3757 switch (Class)
3758 {
3761 break;
3762
3764 {
3766
3767 /* Check whether user wants deletion */
3768 FDI = Irp->AssociatedIrp.SystemBuffer;
3769 if (FDI->DeleteFile)
3770 {
3771 /* If so, check whether it's doable */
3772 if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
3773 {
3775 }
3776
3777 /* And if doable, already remove from FCB table */
3778 if (Status == STATUS_SUCCESS)
3779 {
3780 ASSERT(FcbAcquired && FcbTableAcquired);
3782
3784 FcbTableAcquired = FALSE;
3785 }
3786 }
3787
3788 /* If it succeed, perform the operation */
3789 if (Status == STATUS_SUCCESS)
3790 {
3792 }
3793
3794 break;
3795 }
3796
3799 break;
3800
3803 break;
3804
3807 break;
3808
3813 break;
3814
3818 /* If we can wait, try to perform the operation right now */
3819 if (CanWait)
3820 {
3821 /* Of course, collapsing is not doable anymore, file is
3822 * in an inbetween state
3823 */
3825
3826 /* Set the information */
3828 /* If it succeed, drop the current entry from FCB table */
3830 {
3831 ASSERT(FcbAcquired && FcbTableAcquired);
3833 }
3835 }
3836 /* Can't wait? Post for async retry */
3837 else
3838 {
3841 }
3842 break;
3843
3846 {
3848 }
3849 break;
3850
3853 break;
3854
3855 default:
3856 DPRINT1("Insupported class: %x\n", Class);
3858
3859 break;
3860 }
3861
3862try_exit: NOTHING;
3863 /* If mini-rdr was OK and wants a re-post on this, do it */
3864 if (Status == STATUS_SUCCESS)
3865 {
3866 if (Context->PostRequest)
3867 {
3869 }
3870 }
3871 }
3873 {
3874 /* Release any acquired lock */
3875 if (FcbAcquired)
3876 {
3878 }
3879
3880 if (FcbTableAcquired)
3881 {
3883 }
3884 }
3885 _SEH2_END;
3886
3887#undef _SEH2_TRY_RETURN
3888
3889 return Status;
3890}
3891
3893NTAPI
3896{
3899}
3900
3902NTAPI
3905{
3908}
3909
3911NTAPI
3914{
3917}
3918
3920NTAPI
3923{
3926}
3927
3929NTAPI
3931 PRX_CONTEXT RxContext)
3932{
3933 PIRP Irp;
3934 PFCB Fcb;
3935 PFOBX Fobx;
3937 PNET_ROOT NetRoot;
3938 PSRV_OPEN SrvOpen;
3942 NODE_TYPE_CODE NodeTypeCode;
3943 PLOWIO_CONTEXT LowIoContext;
3944 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3945 ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3946 LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
3947 BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
3948
3949 PAGED_CODE();
3950
3951 Fcb = (PFCB)RxContext->pFcb;
3952 NodeTypeCode = NodeType(Fcb);
3953 /* Validate FCB type */
3954 if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
3955 NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
3956 {
3958 }
3959
3960 /* We'll write to file, keep track of it */
3961 Fcb->IsFileWritten = TRUE;
3962
3963 Stack = RxContext->CurrentIrpSp;
3964 /* Set write through if asked */
3966 {
3968 }
3969
3970 Fobx = (PFOBX)RxContext->pFobx;
3971 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3972
3973 /* Get some parameters */
3974 Irp = RxContext->CurrentIrp;
3975 NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
3976 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3977 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3978 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3979 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3981 WriteLength = Stack->Parameters.Write.Length;
3982 ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
3983 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
3984 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3985
3987
3988 RxContext->FcbResourceAcquired = FALSE;
3990
3991 LowIoContext = &RxContext->LowIoContext;
3992 CheckForLoudOperations(RxContext);
3994 {
3995 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3997 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3998 }
3999
4000 RxDeviceObject = RxContext->RxDeviceObject;
4001 /* Update stats */
4002 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
4003 {
4004 InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
4005
4006 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
4007 {
4008 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
4009 }
4010 Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
4011
4012 if (PagingIo)
4013 {
4015 }
4016 else if (NoCache)
4017 {
4019 }
4020 else
4021 {
4023 }
4024 }
4025
4026 NetRoot = (PNET_ROOT)Fcb->NetRoot;
4027 IsPipe = (NetRoot->Type == NET_ROOT_PIPE);
4028 /* Keep track for normal writes */
4029 if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
4030 {
4031 NormalFile = TRUE;
4032 }
4033 else
4034 {
4035 NormalFile = FALSE;
4036 }
4037
4038 /* Zero-length write is immediate success */
4039 if (NormalFile && WriteLength == 0)
4040 {
4041 return STATUS_SUCCESS;
4042 }
4043
4044 /* Check whether we have input data */
4045 if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
4046 {
4048 }
4049
4050 /* Are we writting to EOF? */
4051 WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1));
4052 /* FIXME: validate length/offset */
4053
4054 /* Get our SRV_OPEN in case of normal write */
4055 if (Fobx != NULL)
4056 {
4057 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
4058 }
4059 else
4060 {
4061 SrvOpen = NULL;
4062 }
4063
4064 FileObject = Stack->FileObject;
4065
4066 /* If we have caching enabled, check whether we have to defer write */
4067 if (!NoCache)
4068 {
4069 if (RxWriteCacheingAllowed(Fcb, SrvOpen))
4070 {
4072 (CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)),
4074 {
4075 BOOLEAN Retrying;
4076
4077 Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
4078
4079 RxPrePostIrp(RxContext, Irp);
4080
4082
4084
4085 return STATUS_PENDING;
4086 }
4087 }
4088 }
4089
4090 /* Initialize the low IO context for write */
4092
4093 /* Initialize our (many) booleans */
4094 RecursiveWriteThrough = FALSE;
4095 CalledByLazyWriter = FALSE;
4096 SwitchBackToAsync = FALSE;
4097 ExtendingFile = FALSE;
4098 ExtendingValidData = FALSE;
4099 UnwindOutstandingAsync = FALSE;
4100 ResourceOwnerSet = FALSE;
4101 PostIrp = FALSE;
4102 ContextReferenced = FALSE;
4103
4104#define _SEH2_TRY_RETURN(S) S; goto try_exit
4105
4106 _SEH2_TRY
4107 {
4108 /* No volume FCB here! */
4109 ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) ||
4110 (NodeTypeCode == RDBSS_NTC_SPOOLFILE) ||
4111 (NodeTypeCode == RDBSS_NTC_MAILSLOT));
4112
4113 /* Writing to EOF on a paging file is non sense */
4114 ASSERT(!(WriteToEof && PagingIo));
4115
4117
4118 /* Start locking stuff */
4119 if (!PagingIo && !NoPreposting)
4120 {
4121 /* If it's already acquired, all fine */
4122 if (RxContext->FcbResourceAcquired)
4123 {
4124 ASSERT(!IsPipe);
4125 }
4126 else
4127 {
4128 /* Otherwise, try to acquire shared (excepted for pipes) */
4129 if (IsPipe)
4130 {
4131 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4132 }
4133 else if (CanWait ||
4134 (!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen)))
4135 {
4136 Status = RxAcquireSharedFcb(RxContext, Fcb);
4137 }
4138 else
4139 {
4141 }
4142
4143 /* We'll post IRP to retry */
4145 {
4146 PostIrp = TRUE;
4147 DPRINT1("Failed to acquire lock!\n");
4149 }
4150
4151 /* We'll just fail */
4152 if (Status != STATUS_SUCCESS)
4153 {
4155 }
4156
4157 /* Resource acquired */
4158 RxContext->FcbResourceAcquired = TRUE;
4159 }
4160
4161 /* At that point, resource is acquired */
4162 if (IsPipe)
4163 {
4164 ASSERT(RxContext->FcbResourceAcquired);
4165 }
4166 else
4167 {
4168 BOOLEAN IsDormant;
4169
4170 /* Now, check whether we have to promote shared lock */
4171 if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4172 {
4173 IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
4174 }
4175 else
4176 {
4177 IsDormant = FALSE;
4178 }
4179
4180 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4182 ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart)
4183 {
4184 if (!IsDormant)
4185 {
4186 RxReleaseFcb(RxContext, Fcb);
4187 RxContext->FcbResourceAcquired = FALSE;
4188
4189 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4191 {
4192 PostIrp = TRUE;
4193 DPRINT1("Failed to acquire lock!\n");
4195 }
4196
4197 if (Status != STATUS_SUCCESS)
4198 {
4200 }
4201
4202 RxContext->FcbResourceAcquired = TRUE;
4203 }
4204 }
4205
4206 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4207 if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart ||
4208 IsDormant)
4209 {
4211 {
4212 RxConvertToSharedFcb(RxContext, Fcb);
4213 }
4214 }
4215 else
4216 {
4217 /* We're extending file, disable collapsing */
4219
4220 DPRINT("Disabling collapsing\n");
4221
4222 if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4223 {
4224 SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
4225 }
4226 }
4227
4228 ASSERT(RxContext->FcbResourceAcquired);
4229 }
4230
4231 /* Keep track of the acquired resource */
4232 LowIoContext->Resource = Fcb->Header.Resource;
4233 }
4234 else
4235 {
4236 /* Paging IO */
4237 ASSERT(!IsPipe);
4238
4239 /* Lock the paging resource */
4241
4242 /* Keep track of the acquired resource */
4243 LowIoContext->Resource = Fcb->Header.PagingIoResource;
4244 }
4245
4246 if (IsPipe)
4247 {
4250 }
4251
4252 /* If it's a non cached write, or if caching is disallowed */
4253 if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4254 {
4255 /* If cache was previously enabled, we'll have to flush before writing */
4257 {
4258 LARGE_INTEGER FlushOffset;
4259
4260 /* FCB is lock */
4262
4263 /* If shared, we'll have to relock exclusive */
4265 {
4266 /* Release and retry exclusive */
4267 RxReleaseFcb(RxContext, Fcb);
4268 RxContext->FcbResourceAcquired = FALSE;
4269
4270 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4272 {
4273 PostIrp = TRUE;
4274 DPRINT1("Failed to acquire lock for flush!\n");
4276 }
4277
4278 if (Status != STATUS_SUCCESS)
4279 {
4281 }
4282
4283 RxContext->FcbResourceAcquired = TRUE;
4284 }
4285
4286 /* Get the length to flush */
4287 if (WriteToEof)
4288 {
4289 RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart);
4290 }
4291 else
4292 {
4293 FlushOffset.QuadPart = ByteOffset.QuadPart;
4294 }
4295
4296 /* Perform the flushing */
4297 RxAcquirePagingIoResource(RxContext, Fcb);
4299 WriteLength, &Irp->IoStatus);
4300 RxReleasePagingIoResource(RxContext, Fcb);
4301
4302 /* Cannot continue if flushing failed */
4303 if (!NT_SUCCESS(Irp->IoStatus.Status))
4304 {
4305 _SEH2_TRY_RETURN(Status = Irp->IoStatus.Status);
4306 }
4307
4308 /* Synchronize */
4309 RxAcquirePagingIoResource(RxContext, Fcb);
4310 RxReleasePagingIoResource(RxContext, Fcb);
4311
4312 /* And purge */
4314 &FlushOffset, WriteLength, FALSE);
4315 }
4316 }
4317
4318 /* If not paging IO, check if write is allowed */
4319 if (!PagingIo)
4320 {
4322 {
4324 }
4325 }
4326
4327 /* Get file sizes */
4328 ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4330 ASSERT(ValidDataLength <= FileSize);
4331
4332 /* If paging IO, we cannot write past file size
4333 * so fix write length if needed
4334 */
4335 if (PagingIo)
4336 {
4337 if (ByteOffset.QuadPart >= FileSize)
4338 {
4340 }
4341
4342 if (WriteLength > FileSize - ByteOffset.QuadPart)
4343 {
4344 WriteLength = FileSize - ByteOffset.QuadPart;
4345 }
4346 }
4347
4348 /* If we're being called by the lazywrite */
4349 if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread())
4350 {
4351 CalledByLazyWriter = TRUE;
4352
4353 /* Fail if we're beyong VDL */
4355 {
4356 if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) &&
4357 (ByteOffset.QuadPart < FileSize))
4358 {
4359 if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
4360 {
4362 }
4363 }
4364 }
4365 }
4366
4367 /* If that's a recursive synchronous page write */
4370 {
4371 PIRP TopIrp;
4372
4373 /* Check the top level IRP on the FastIO path */
4374 TopIrp = RxGetTopIrpIfRdbssIrp();
4375 if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP)
4376 {
4377 PIO_STACK_LOCATION IrpStack;
4378
4379 ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
4380
4381 /* If the top level IRP was a cached write for this file, keep track */
4382 IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
4383 if (IrpStack->MajorFunction == IRP_MJ_WRITE &&
4384 IrpStack->FileObject->FsContext == FileObject->FsContext)
4385 {
4386 RecursiveWriteThrough = TRUE;
4388 }
4389 }
4390 }
4391
4392 /* Now, deal with file size and VDL */
4393 if (!CalledByLazyWriter && !RecursiveWriteThrough &&
4394 (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength))
4395 {
4396 /* Not sync? Let's make it sync, just the time we extended */
4397 if (!Sync)
4398 {
4399 CanWait = TRUE;
4400 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
4402 Sync = TRUE;
4403
4404 /* Keep track we'll have to switch back to async */
4405 if (NoCache)
4406 {
4407 SwitchBackToAsync = TRUE;
4408 }
4409 }
4410
4411 /* Release all the locks */
4412 RxWriteReleaseResources(RxContext, 0);
4413
4414 /* Acquire exclusive */
4415 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4417 {
4418 PostIrp = TRUE;
4419 DPRINT1("Failed to acquire lock for extension!\n");
4421 }
4422
4423 if (Status != STATUS_SUCCESS)
4424 {
4426 }
4427
4428 RxContext->FcbResourceAcquired = TRUE;
4429
4431
4432 /* Get the sizes again, to be sure they didn't change in the meantime */
4433 ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4435 ASSERT(ValidDataLength <= FileSize);
4436
4437 /* Check we can switch back to async? */
4438 if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
4439 (ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync)
4440 {
4441 SwitchBackToAsync = FALSE;
4442 }
4443
4444 /* If paging IO, check we don't try to extend the file */
4445 if (PagingIo)
4446 {
4447 if (ByteOffset.QuadPart >= FileSize)
4448 {
4450 }
4451
4452 if (WriteLength > FileSize - ByteOffset.QuadPart)
4453 {
4454 WriteLength = FileSize - ByteOffset.QuadPart;
4455 }
4456 }
4457 }
4458
4459 /* Save our initial sizes for potential rollback */
4460 InitialFileSize = FileSize;
4461 InitialValidDataLength = ValidDataLength;
4462 /* If writing to EOF, update byte offset with file size */
4463 if (WriteToEof)
4464 {
4465 ByteOffset.QuadPart = FileSize;
4466 }
4467
4468 /* Check again whether we're allowed to write */
4469 if (!PagingIo)
4470 {
4471 if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp ))
4472 {
4474 }
4475
4476 /* Do we have to extend? */
4477 if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize))
4478 {
4479 DPRINT("Need to extend file\n");
4480 ExtendingFile = TRUE;
4482 }
4483 }
4484
4485 /* Let's start to extend */
4486 if (ExtendingFile)
4487 {
4488 /* If we're past allocating, inform mini-rdr */
4489 FileSize = ByteOffset.QuadPart + WriteLength;
4490 if (FileSize > Fcb->Header.AllocationSize.QuadPart)
4491 {
4492 LARGE_INTEGER NewAllocationSize;
4493
4494 DPRINT("Extending %p\n", RxContext);
4495
4496 if (NoCache)
4497 {
4498 C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4499 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache,
4500 (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4501 }
4502 else
4503 {
4504 C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4505 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache,
4506 (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4507 }
4508
4509 if (!NT_SUCCESS(Status))
4510 {
4512 }
4513
4514 if (FileSize > NewAllocationSize.QuadPart)
4515 {
4516 NewAllocationSize.QuadPart = FileSize;
4517 }
4518
4519 /* And update FCB */
4520 Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
4521 }
4522
4523 /* Set the new sizes */
4526
4527 /* And inform Cc */
4529 {
4531 }
4532 }
4533
4534 /* Do we have to extend VDL? */
4535 if (!CalledByLazyWriter && !RecursiveWriteThrough)
4536 {
4537 if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)
4538 {
4539 ExtendingValidData = TRUE;
4541 }
4542 }
4543
4544 /* If none cached write */
4545 if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4546 {
4547 /* Switch back to async, if asked to */
4548 if (SwitchBackToAsync)
4549 {
4550 CanWait = FALSE;
4551 Sync = FALSE;
4552
4555 }
4556
4557 /* If not synchronous, keep track of writes to be finished */
4558 if (!Sync)
4559 {
4561 {
4565 }
4566
4568 1,
4569 &RxStrucSupSpinLock) == 0)
4570 {
4572 }
4573
4574 UnwindOutstandingAsync = TRUE;
4575 LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
4576 }
4577
4578 /* Set our LOWIO_CONTEXT information */
4579 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
4580 LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
4581
4583
4584 /* We have to be locked */
4585 ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
4586
4587 /* Update thread ID if we're in FSP */
4588 if (InFsp)
4589 {
4590 LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
4591
4592 if (RxContext->FcbResourceAcquired)
4593 {
4594 ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3));
4595 }
4596
4597 if (RxContext->FcbPagingIoResourceAcquired)
4598 {
4599 ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3));
4600 }
4601
4602 ResourceOwnerSet = TRUE;
4603 }
4604
4605 /* And perform the write */
4606 Status = RxLowIoWriteShell(RxContext);
4607
4609
4610 /* Not outstanding write anymore */
4611 if (UnwindOutstandingAsync && Status == STATUS_PENDING)
4612 {
4613 UnwindOutstandingAsync = FALSE;
4614 }
4615 }
4616 /* Cached write */
4617 else
4618 {
4619 /* If cache wasn't enabled yet, do it */
4620 if (FileObject->PrivateCacheMap == NULL)
4621 {
4623 {
4625 }
4626
4628
4631
4632 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
4633 }
4634
4635 /* If that's a MDL backed write */
4636 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
4637 {
4638 /* Shouldn't happen */
4639 ASSERT(FALSE);
4640 ASSERT(CanWait);
4641
4642 /* Perform it, though */
4644 &Irp->MdlAddress, &Irp->IoStatus);
4645
4646 Status = Irp->IoStatus.Status;
4647 }
4648 else
4649 {
4650 PVOID SystemBuffer;
4651 ULONG BreakpointsSave;
4652
4653 /* Map the user buffer */
4654 SystemBuffer = RxNewMapUserBuffer(RxContext);
4655 if (SystemBuffer == NULL)
4656 {
4658 }
4659
4660 RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4661