ReactOS  0.4.13-dev-464-g6b95727
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 
40 typedef
44 
46 {
49 
50 VOID
51 NTAPI
54 
56 NTAPI
60 
61 VOID
63  PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64 
65 VOID
66 RxAssert(
67  PVOID Assert,
68  PVOID File,
69  ULONG Line,
70  PVOID Message);
71 
73 NTAPI
76 
78 NTAPI
81 
83 NTAPI
86 
88 NTAPI
91 
93 NTAPI
96 
98 NTAPI
101 
102 NTSTATUS
103 NTAPI
106 
107 NTSTATUS
108 NTAPI
111 
112 NTSTATUS
113 NTAPI
116 
117 NTSTATUS
118 NTAPI
121 
122 NTSTATUS
123 NTAPI
126 
127 NTSTATUS
128 NTAPI
131 
132 NTSTATUS
133 NTAPI
136 
137 NTSTATUS
138 NTAPI
141 
142 NTSTATUS
143 NTAPI
146 
147 NTSTATUS
148 NTAPI
151 
152 NTSTATUS
153 NTAPI
156 
157 NTSTATUS
158 NTAPI
161 
162 NTSTATUS
163 NTAPI
166 
167 NTSTATUS
168 NTAPI
171 
172 NTSTATUS
173 NTAPI
176 
177 NTSTATUS
178 NTAPI
181 
182 NTSTATUS
183 NTAPI
186 
187 NTSTATUS
188 NTAPI
191 
192 NTSTATUS
193 NTAPI
196 
197 NTSTATUS
198 NTAPI
201 
202 NTSTATUS
203 NTAPI
206 
207 VOID
209  IN PRX_CONTEXT RxContext);
210 
211 NTSTATUS
214  PUNICODE_STRING NetRootName);
215 
216 NTSTATUS
218  IN PRX_CONTEXT RxContext);
219 
220 BOOLEAN
221 NTAPI
229 
230 BOOLEAN
231 NTAPI
234  BOOLEAN Wait,
242 
243 BOOLEAN
244 NTAPI
248  ULONG Length,
249  BOOLEAN Wait,
250  ULONG LockKey,
251  PVOID Buffer,
254 
255 BOOLEAN
256 NTAPI
260  ULONG Length,
261  BOOLEAN Wait,
262  ULONG LockKey,
263  PVOID Buffer,
266 
267 NTSTATUS
269  PRX_CONTEXT RxContext,
270  PUNICODE_STRING NetRootName);
271 
272 NTSTATUS
274  PRX_CONTEXT RxContext,
276  PUNICODE_STRING CanonicalName,
277  PNET_ROOT_TYPE NetRootType);
278 
279 VOID
282 
283 VOID
284 NTAPI
286  IN PVOID Context);
287 
288 VOID
289 NTAPI
292 
293 NTSTATUS
294 NTAPI
297  IN PCWSTR KeyName,
298  OUT PUNICODE_STRING OutString,
299  IN PUCHAR Buffer,
301  IN BOOLEAN LogFailure);
302 
303 VOID
304 NTAPI
306  VOID);
307 
308 VOID
309 NTAPI
312 
313 NTSTATUS
314 NTAPI
316  VOID);
317 
318 VOID
319 NTAPI
321  VOID);
322 
323 VOID
324 NTAPI
327  USHORT State);
328 
329 BOOLEAN
331  PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332 
333 NTSTATUS
334 NTAPI
336  PRX_CONTEXT RxContext);
337 
338 NTSTATUS
340  PRX_CONTEXT RxContext);
341 
342 NTSTATUS
343 NTAPI
345  PRX_CONTEXT RxContext);
346 
347 NTSTATUS
349  IN PRX_CONTEXT RxContext);
350 
351 NTSTATUS
352 NTAPI
354  PRX_CONTEXT RxContext);
355 
356 PVOID
358  PRX_CONTEXT RxContext);
359 
360 NTSTATUS
362  PRX_CONTEXT RxContext);
363 
364 VOID
365 NTAPI
367  PVOID Context);
368 
369 NTSTATUS
371  PRX_CONTEXT RxContext,
372  FILE_INFORMATION_CLASS FileInfoClass,
373  PVOID Buffer);
374 
375 VOID
377  PFCB Fcb,
378  PRX_CONTEXT LocalContext);
379 
380 NTSTATUS
382  PRX_CONTEXT RxContext,
383  PFILE_NAME_INFORMATION AltNameInfo);
384 
385 NTSTATUS
387  PRX_CONTEXT RxContext,
388  PFILE_BASIC_INFORMATION BasicInfo);
389 
390 NTSTATUS
392  PRX_CONTEXT RxContext,
393  PFILE_COMPRESSION_INFORMATION CompressionInfo);
394 
395 NTSTATUS
397  PRX_CONTEXT RxContext);
398 
399 NTSTATUS
401  PRX_CONTEXT RxContext,
402  PFILE_EA_INFORMATION EaInfo);
403 
404 NTSTATUS
406  PRX_CONTEXT RxContext,
407  PFILE_INTERNAL_INFORMATION InternalInfo);
408 
409 NTSTATUS
411  PRX_CONTEXT RxContext,
412  PFILE_NAME_INFORMATION NameInfo);
413 
414 NTSTATUS
416  PRX_CONTEXT RxContext,
418 
419 NTSTATUS
421  PRX_CONTEXT RxContext,
422  PFILE_POSITION_INFORMATION PositionInfo);
423 
424 NTSTATUS
426  PRX_CONTEXT RxContext,
427  PFILE_STANDARD_INFORMATION StandardInfo);
428 
429 VOID
430 NTAPI
432  VOID);
433 
434 VOID
435 NTAPI
438 
439 NTSTATUS
440 NTAPI
444 
448  WORK_QUEUE_TYPE Queue);
449 
450 NTSTATUS
452  PRX_CONTEXT RxContext,
455 
456 NTSTATUS
458  PRX_CONTEXT RxContext);
459 
460 NTSTATUS
462  PRX_CONTEXT RxContext);
463 
464 NTSTATUS
466  PRX_CONTEXT RxContext);
467 
468 NTSTATUS
470  PRX_CONTEXT RxContext);
471 
472 NTSTATUS
474  PRX_CONTEXT RxContext);
475 
476 NTSTATUS
478  PRX_CONTEXT RxContext);
479 
480 NTSTATUS
482  PRX_CONTEXT RxContext);
483 
484 NTSTATUS
486  PRX_CONTEXT RxContext);
487 
488 VOID
490  PRX_CONTEXT RxContext);
491 
492 NTSTATUS
494  IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
495  IN PIRP Irp);
496 
497 VOID
499  PRX_CONTEXT RxContext,
501  PLARGE_INTEGER TruncateSize);
502 
503 VOID
504 RxUnstart(
507 
508 NTSTATUS
511 
512 PVOID
513 NTAPI
517  _In_ ULONG Tag);
518 
519 VOID
520 NTAPI
522  _In_ PVOID Buffer);
523 
524 VOID
525 NTAPI
527  _In_ PVOID Buffer,
528  _In_ ULONG Tag);
529 
531 WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
541 {
570 };
575 {
576  { RxCommonCreate },
578  { RxCommonClose },
579  { RxCommonRead },
580  { RxCommonWrite },
583  { RxCommonQueryEa },
584  { RxCommonSetEa },
594  { RxCommonCleanup },
604 };
610 UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
615 
616 DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
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  */
646 VOID
648  PRX_CONTEXT RxContext)
649 {
650  RxCaptureFcb;
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  */
673 VOID
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  */
700 VOID
702  PRX_CONTEXT RxContext,
703  BOOLEAN ResourceOwnerSet,
705  PCSTR FileName,
707 {
708  RxCaptureFcb;
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  {
741  RxReleasePagingIoResource(RxContext, capFcb);
742  }
743 
744  /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
745  }
746 }
747 
748 /*
749  * @implemented
750  */
751 VOID
753  PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
754 {
755  KIRQL OldIrql;
756 
757  DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
758 
761 
765 }
766 
767 /*
768  * @implemented
769  */
770 VOID
771 NTAPI
773  IN PRX_CONTEXT RxContext,
774  IN PIRP Irp)
775 {
776  ULONG Queued;
777  KIRQL OldIrql;
778  WORK_QUEUE_TYPE Queue;
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  {
788  Queue = DelayedWorkQueue;
790  }
791  else
792  {
793  Queue = CriticalWorkQueue;
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  */
824 VOID
826  PRX_CONTEXT RxContext)
827 {
829  LARGE_INTEGER CurrentTime;
830  FILE_BASIC_INFORMATION FileBasicInfo;
831  FILE_END_OF_FILE_INFORMATION FileEOFInfo;
832  BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
833 
834  RxCaptureFcb;
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  */
923 NTSTATUS
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  */
962 VOID
964  PFOBX Fobx)
965 {
966  KIRQL OldIrql;
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  */
1039 NTSTATUS
1041  PV_NET_ROOT VNetRoot,
1042  BOOLEAN ForceFilesClosed)
1043 {
1044  KIRQL OldIrql;
1045  NTSTATUS Status;
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  */
1138 BOOLEAN
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 */
1158  RemoveEntryList(&RxContext->OverflowListEntry);
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  {
1185  RxCompleteRequest(RxContext, STATUS_CANCELLED);
1186  }
1187 
1188  return OperationToCancel;
1189 }
1190 
1191 /*
1192  * @implemented
1193  */
1194 VOID
1195 NTAPI
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  */
1260 NTSTATUS
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 
1351 NTSTATUS
1353  PRX_CONTEXT RxContext,
1355  PUNICODE_STRING NetRootName)
1356 {
1357  NTSTATUS Status;
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  {
1388  return STATUS_INVALID_PARAMETER;
1389  }
1390 
1391  if (!NodeTypeIsFcb(Fcb))
1392  {
1393  return STATUS_INVALID_PARAMETER;
1394  }
1395 
1396  UNIMPLEMENTED;
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  */
1445 VOID
1446 NTAPI
1448  VOID)
1449 {
1450  PAGED_CODE();
1451 }
1452 
1453 #if DBG
1454 NTSTATUS
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  */
1476 NTSTATUS
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  {
1516  return STATUS_SHARING_VIOLATION;
1517  }
1518  }
1519 
1520  return STATUS_SUCCESS;
1521 }
1522 
1523 VOID
1526 {
1527  UNIMPLEMENTED;
1528 }
1529 
1530 /*
1531  * @implemented
1532  */
1533 NTSTATUS
1535  IN PFOBX Fobx,
1536  IN PRX_CONTEXT RxContext OPTIONAL)
1537 {
1538  PFCB Fcb;
1539  NTSTATUS Status;
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  */
1731 NTSTATUS
1733  PRX_CONTEXT RxContext)
1734 {
1735  NTSTATUS Status;
1737  PSRV_OPEN SrvOpen;
1740  RX_BLOCK_CONDITION FcbCondition;
1741 
1742  RxCaptureFcb;
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  {
1796  RxAcquirePagingIoResource(RxContext, capFcb);
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);
1802  RxReleasePagingIoResource(RxContext, capFcb);
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 */
1859  RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
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  */
1913 NTSTATUS
1914 NTAPI
1917 {
1918 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1919  PFCB Fcb;
1920  PFOBX Fobx;
1921  ULONG OpenCount;
1922  NTSTATUS Status;
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  {
2030  RxReleaseFcbTableLock(&NetRoot->FcbTable);
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  {
2044  RxReleaseFcbTableLock(&NetRoot->FcbTable);
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  {
2202  RxReleaseFcbTableLock(&NetRoot->FcbTable);
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  {
2273  RxReleaseFcbTableLock(&NetRoot->FcbTable);
2274  }
2275  }
2276  _SEH2_END;
2277 
2278  return Status;
2279 #undef BugCheckFileId
2280 }
2281 
2282 NTSTATUS
2283 NTAPI
2286 {
2287 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2288  PFCB Fcb;
2289  PFOBX Fobx;
2290  NTSTATUS Status;
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 
2374  RxReleaseFcbTableLock(&NetRoot->FcbTable);
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  */
2438 NTSTATUS
2439 NTAPI
2442 {
2443  PIRP Irp;
2444  NTSTATUS Status;
2446  PIO_STACK_LOCATION Stack;
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);
2479  return STATUS_INVALID_PARAMETER;
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 */
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  {
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  */
2646 NTSTATUS
2647 NTAPI
2650 {
2651  PMRX_FCB Fcb;
2652  NTSTATUS Status;
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  */
2683 NTSTATUS
2684 NTAPI
2687 {
2688  PMRX_FCB Fcb;
2689  NTSTATUS Status;
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 
2724 NTSTATUS
2725 NTAPI
2728 {
2729  UNIMPLEMENTED;
2730  return STATUS_NOT_IMPLEMENTED;
2731 }
2732 
2733 /*
2734  * @implemented
2735  */
2736 NTSTATUS
2737 NTAPI
2740 {
2741  NTSTATUS Status;
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 
2773 NTSTATUS
2774 NTAPI
2777 {
2778  UNIMPLEMENTED;
2779  return STATUS_NOT_IMPLEMENTED;
2780 }
2781 
2782 /*
2783  * @implemented
2784  */
2785 NTSTATUS
2786 NTAPI
2789 {
2790  NTSTATUS Status;
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  */
2814 NTSTATUS
2815 NTAPI
2818 {
2819  PFCB Fcb;
2820  PFOBX Fobx;
2821  NTSTATUS Status;
2822  PIO_STACK_LOCATION Stack;
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 
2852 NTSTATUS
2853 NTAPI
2856 {
2857  UNIMPLEMENTED;
2858  return STATUS_NOT_IMPLEMENTED;
2859 }
2860 
2861 NTSTATUS
2862 NTAPI
2865 {
2866  PIRP Irp;
2868  PIO_STACK_LOCATION Stack;
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 
2878  UNIMPLEMENTED;
2879  return STATUS_NOT_IMPLEMENTED;
2880 }
2881 
2882 NTSTATUS
2883 NTAPI
2886 {
2887  UNIMPLEMENTED;
2888  return STATUS_NOT_IMPLEMENTED;
2889 }
2890 
2891 NTSTATUS
2892 NTAPI
2895 {
2896  UNIMPLEMENTED;
2897  return STATUS_NOT_IMPLEMENTED;
2898 }
2899 
2900 NTSTATUS
2901 NTAPI
2904 {
2905  UNIMPLEMENTED;
2906  return STATUS_NOT_IMPLEMENTED;
2907 }
2908 
2909 /*
2910  * @implemented
2911  */
2912 NTSTATUS
2913 NTAPI
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;
2924  BOOLEAN Locked;
2925  NTSTATUS Status;
2926  PIO_STACK_LOCATION Stack;
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  {
2953  _SEH2_LEAVE;
2954  }
2955  /* Zero it */
2956  RtlZeroMemory(Buffer, Context->Info.Length);
2957 
2958  /* Validate file type */
2960  {
2962  {
2964  _SEH2_LEAVE;
2965  }
2967  {
2969  {
2971  }
2972  else
2973  {
2975  }
2976 
2977  _SEH2_LEAVE;
2978  }
2979  }
2980 
2981  /* Acquire the right lock */
2983  FileInfoClass != FileNameInformation)
2984  {
2985  if (FileInfoClass == FileCompressionInformation)
2986  {
2988  }
2989  else
2990  {
2992  }
2993 
2995  {
2997  _SEH2_LEAVE;
2998  }
2999  else if (!NT_SUCCESS(Status))
3000  {
3001  _SEH2_LEAVE;
3002  }
3003 
3004  Locked = TRUE;
3005  }
3006 
3007  /* Dispatch to the right helper */
3008  switch (FileInfoClass)
3009  {
3010  case FileBasicInformation:
3012  break;
3013 
3016  break;
3017 
3020  break;
3021 
3022  case FileEaInformation:
3024  break;
3025 
3026  case FileNameInformation:
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 
3051  sizeof(FILE_STANDARD_INFORMATION) +
3053  if (!NT_SUCCESS(Status))
3054  {
3055  break;
3056  }
3057 
3059  sizeof(FILE_STANDARD_INFORMATION) +
3060  sizeof(FILE_INTERNAL_INFORMATION) +
3062  if (!NT_SUCCESS(Status))
3063  {
3064  break;
3065  }
3066 
3068  sizeof(FILE_STANDARD_INFORMATION) +
3069  sizeof(FILE_INTERNAL_INFORMATION) +
3070  sizeof(FILE_EA_INFORMATION) +
3072  break;
3073 
3076  break;
3077 
3078  case FilePipeInformation:
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 
3117 NTSTATUS
3118 NTAPI
3121 {
3122  UNIMPLEMENTED;
3123  return STATUS_NOT_IMPLEMENTED;
3124 }
3125 
3126 NTSTATUS
3127 NTAPI
3130 {
3131  UNIMPLEMENTED;
3132  return STATUS_NOT_IMPLEMENTED;
3133 }
3134 
3135 /*
3136  * @implemented
3137  */
3138 NTSTATUS
3139 NTAPI
3142 {
3143  PIRP Irp;
3144  PFCB Fcb;
3145  PFOBX Fobx;
3146  NTSTATUS Status;
3147  PIO_STACK_LOCATION Stack;
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 
3182 NTSTATUS
3183 NTAPI
3185  PRX_CONTEXT RxContext)
3186 {
3187  PFCB Fcb;
3188  PIRP Irp;
3189  PFOBX Fobx;
3190  NTSTATUS Status;
3191  PNET_ROOT NetRoot;
3192  PVOID SystemBuffer;
3195  PIO_STACK_LOCATION Stack;
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);
3229  if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3230  {
3231  DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3232  ByteOffset, ReadLength,
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  {
3250  ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
3251  }
3252  else if (NoCache)
3253  {
3254  ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
3255  }
3256  else
3257  {
3258  ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
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 */
3282  RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
3283 
3284  PostRequest = FALSE;
3285  ReadCachingDisabled = FALSE;
3286  OwnerSet = FALSE;
3287  ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
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;
3301  _SEH2_LEAVE;
3302  }
3303  else if (Status != STATUS_SUCCESS)
3304  {
3305  _SEH2_LEAVE;
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;
3315  _SEH2_LEAVE;
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;
3330  _SEH2_LEAVE;
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  {
3344  Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
3346  {
3347  DPRINT1("RdAsyLNG %x\n", RxContext);
3348  PostRequest = TRUE;
3349  _SEH2_LEAVE;
3350  }
3351  if (Status != STATUS_SUCCESS)
3352  {
3353  DPRINT1("RdAsyOthr %x\n", RxContext);
3354  _SEH2_LEAVE;
3355  }
3356 
3357  if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3358  {
3359  LowIoContext->Resource = Fcb->Header.Resource;
3360  }
3361  else
3362  {
3363  PostRequest = TRUE;
3364  _SEH2_LEAVE;
3365  }
3366  }
3367  else
3368  {
3369  Status = RxAcquireSharedFcb(RxContext, Fcb);
3371  {
3372  PostRequest = TRUE;
3373  _SEH2_LEAVE;
3374  }
3375  else if (Status != STATUS_SUCCESS)
3376  {
3377  _SEH2_LEAVE;
3378  }
3379  }
3380  }
3381  }
3382 
3384 
3385  ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3386  if (IsPipe)
3387  {
3388  UNIMPLEMENTED;
3389  }
3390 
3392 
3393  /* Make sure FLOCK doesn't conflict */
3394  if (!PagingIo)
3395  {
3396  if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
3397  {
3399  _SEH2_LEAVE;
3400  }
3401  }
3402 
3403  /* Validate byteoffset vs length */
3405  {
3406  if (ByteOffset.QuadPart >= FileSize)
3407  {
3409  _SEH2_LEAVE;
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  {
3428  _SEH2_LEAVE;
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  {
3466  _SEH2_LEAVE;
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;
3484  _SEH2_LEAVE;
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;
3532  _SEH2_LEAVE;
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 
3638 NTSTATUS
3639 NTAPI
3642 {
3643  UNIMPLEMENTED;
3644  return STATUS_NOT_IMPLEMENTED;
3645 }
3646 
3647 /*
3648  * @implemented
3649  */
3650 NTSTATUS
3651 NTAPI
3654 {
3655  PIRP Irp;
3656  PFCB Fcb;
3657  PFOBX Fobx;
3658  NTSTATUS Status;
3659  PNET_ROOT NetRoot;
3660  PIO_STACK_LOCATION Stack;
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);
3726  RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
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  {
3748  _SEH2_LEAVE;
3749  }
3750 
3751  FcbAcquired = TRUE;
3752  }
3753 
3755 
3756  /* And now, perform the job! */
3757  switch (Class)
3758  {
3759  case FileBasicInformation:
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 
3783  RxReleaseFcbTableLock(&NetRoot->FcbTable);
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 
3809  case FilePipeInformation:
3813  break;
3814 
3815  case FileRenameInformation:
3816  case FileLinkInformation:
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 
3862 try_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  {
3882  RxReleaseFcbTableLock(&NetRoot->FcbTable);
3883  }
3884  }
3885  _SEH2_END;
3886 
3887 #undef _SEH2_TRY_RETURN
3888 
3889  return Status;
3890 }
3891 
3892 NTSTATUS
3893 NTAPI
3896 {
3897  UNIMPLEMENTED;
3898  return STATUS_NOT_IMPLEMENTED;
3899 }
3900 
3901 NTSTATUS
3902 NTAPI
3905 {
3906  UNIMPLEMENTED;
3907  return STATUS_NOT_IMPLEMENTED;
3908 }
3909 
3910 NTSTATUS
3911 NTAPI
3914 {
3915  UNIMPLEMENTED;
3916  return STATUS_NOT_IMPLEMENTED;
3917 }
3918 
3919 NTSTATUS
3920 NTAPI
3923 {
3924  UNIMPLEMENTED;
3925  return STATUS_NOT_IMPLEMENTED;
3926 }
3927 
3928 NTSTATUS
3929 NTAPI
3931  PRX_CONTEXT RxContext)
3932 {
3933  PIRP Irp;
3934  PFCB Fcb;
3935  PFOBX Fobx;
3936  NTSTATUS Status;
3937  PNET_ROOT NetRoot;
3938  PSRV_OPEN SrvOpen;
3940  PIO_STACK_LOCATION Stack;
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 */
3965  if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
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;
3989  RxContext->FcbPagingIoResourceAcquired = FALSE;
3990 
3991  LowIoContext = &RxContext->LowIoContext;
3992  CheckForLoudOperations(RxContext);
3993  if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3994  {
3995  DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3996  ByteOffset, WriteLength,
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  {
4014  ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength);
4015  }
4016  else if (NoCache)
4017  {
4018  ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength);
4019  }
4020  else
4021  {
4022  ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength);
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  {
4047  return STATUS_INVALID_PARAMETER;
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  {
4071  if (!CcCanIWrite(FileObject, WriteLength,
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 
4083  CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
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  {
4140  Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
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 */
4181  if (RxIsFcbAcquiredShared(Fcb) &&
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  {
4248  UNIMPLEMENTED;
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  {
4321  if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp))
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  {
4530  CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
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 
4553  ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
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 */
4643  CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength,
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 
4663 
4664  /* And deal with Cc */
4665  if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait,
4666  SystemBuffer))
4667  {
4668  RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4669 
4671 
4672  DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4673  FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4674 
4675  PostIrp = TRUE;
4676  }
4677  else
4678  {
4679  Irp->IoStatus.Status = STATUS_SUCCESS;
4680  Irp->IoStatus.Information = WriteLength;
4681 
4682  RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4683 
4685 
4686  DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4687  FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4688  }
4689  }
4690  }
4691 
4692 try_exit: NOTHING;
4693 
4694  /* If we've to post the IRP */
4695  if (PostIrp)
4696  {
4697  /* Reset the file size if required */
4698  if (ExtendingFile && !IsPipe)
4699  {
4700  ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen));
4701  ASSERT(Fcb->Header.PagingIoResource != NULL);
4702 
4703  RxAcquirePagingIoResource(RxContext, Fcb);
4704  RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4705  RxReleasePagingIoResource(RxContext, Fcb);
4706 
4707  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4708  {
4709  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4710  }
4711  }
4712 
4713  InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
4714  ContextReferenced = TRUE;
4715 
4716  /* Release locks */
4717  ASSERT(!ResourceOwnerSet);
4718  RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4719 
4720 #ifdef RDBSS_TRACKER
4721  ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
4722 #endif
4723 
4724  /* And post the request */
4725  Status = RxFsdPostRequest(RxContext);
4726  }
4727  else
4728  {
4729  if (!IsPipe)
4730  {
4731  /* Update FILE_OBJECT if synchronous write succeed */
4732  if (!PagingIo)
4733  {
4735  {
4736  FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
4737  }
4738  }
4739 
4740  /* If write succeed, ,also update FILE_OBJECT flags */
4742  {
4743  /* File was modified */
4744  if (!PagingIo)
4745  {
4747  }
4748 
4749  /* If was even extended */
4750  if (ExtendingFile)
4751  {
4753  }
4754 
4755  /* If VDL was extended, update FCB and inform Cc */
4756  if (ExtendingValidData)
4757  {
4758  LONGLONG LastOffset;
4759 
4760  LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information;
4761  if (FileSize < LastOffset)
4762  {
4763  LastOffset = FileSize;
4764  }
4765 
4766  Fcb->Header.ValidDataLength.QuadPart = LastOffset;
4767 
4768  if (NoCache && CcIsFileCached(FileObject))
4769  {
4770  CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
4771  }
4772  }
4773  }
4774  }
4775  }
4776  }
4778  {
4779  /* Finally, if we failed while extension was required */
4780  if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData))
4781  {
4782  /* Rollback! */
4783  if (!IsPipe)
4784  {
4785  ASSERT(Fcb->Header.PagingIoResource != NULL);
4786 
4787  RxAcquirePagingIoResource(RxContext, Fcb);
4788  RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4789  Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
4790  RxReleasePagingIoResource(RxContext, Fcb);
4791 
4792  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4793  {
4794  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4795  }
4796  }
4797  }
4798 
4799  /* One async write less */
4800  if (UnwindOutstandingAsync)
4801  {
4802  ASSERT(!IsPipe);
4803 
4806  }
4807 
4808  /* And now, cleanup everything */
4809  if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp)
4810  {
4811  /* If we didn't post, release every lock (for posting, it's already done) */
4812  if (!PostIrp)
4813  {
4814  RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4815  }
4816 
4817  /* If the context was referenced - posting, dereference it */
4818  if (ContextReferenced)
4819  {
4821  }
4822 
4823  /* If that's a pipe operation, resume any blocked one */
4824  if (!PostIrp)
4825  {
4827  {
4828  RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
4829  }
4830  }
4831 
4832  /* Sanity check for write */
4833  if (Status == STATUS_SUCCESS)
4834  {
4835  ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
4836  }
4837  }
4838  /* Just dereference our context */
4839  else
4840  {
4841  ASSERT(!Sync);
4843  }
4844  }
4845  _SEH2_END;
4846 
4847 #undef _SEH2_TRY_RETURN
4848 
4849  return Status;
4850 }
4851 
4852 /*
4853  * @implemented
4854  */
4855 NTSTATUS
4856 NTAPI
4858  IN PRX_CONTEXT RxContext)
4859 {
4860  PIRP Irp;
4862  PIO_STACK_LOCATION Stack;
4863 
4864 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4865 
4866  PAGED_CODE();
4867 
4868  Irp = RxContext->CurrentIrp;
4869  Stack = RxContext->CurrentIrpSp;
4870  FileObject = Stack->FileObject;
4871 
4872  /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4873  switch (RxContext->MajorFunction)
4874  {
4875  /* Call the Cc function */
4876  case IRP_MJ_READ:
4877  CcMdlReadComplete(FileObject, Irp->MdlAddress);
4878  break;
4879 
4880  case IRP_MJ_WRITE:
4881  /* If here, we can wait */
4882  ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
4883 
4884  /* Call the Cc function */
4885  CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
4886 
4887  Irp->IoStatus.Status = STATUS_SUCCESS;
4888  break;
4889 
4890  default:
4891  DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction);
4892  RxBugCheck(RxContext->MajorFunction, 0, 0);
4893  break;
4894  }
4895 
4896  /* MDL was freed */
4897  Irp->MdlAddress = NULL;
4898 
4899  /* And complete the IRP */
4900  RxCompleteRequest(RxContext, STATUS_SUCCESS);
4901 
4902 #undef BugCheckFileId
4903 
4904  return STATUS_SUCCESS;
4905 }
4906 
4907 /*
4908  * @implemented
4909  */
4910 VOID
4912  PFCB Fcb,
4913  PFOBX Fobx,
4914  PULONG ActualNameLength,
4915  PWCHAR OriginalName,
4916  PLONG LengthRemaining,
4917  RX_NAME_CONJURING_METHODS NameConjuringMethod)
4918 {
4919  PWSTR Prefix, Name;
4920  PV_NET_ROOT VNetRoot;
4921  USHORT PrefixLength, NameLength, ToCopy;
4922 
4923  PAGED_CODE();
4924 
4925  VNetRoot = Fcb->VNetRoot;
4926  /* We will use the prefix contained in NET_ROOT, if we don't have
4927  * a V_NET_ROOT, or if it wasn't null deviced or if we already have
4928  * a UNC path */
4929  if (VNetRoot == NULL || VNetRoot->PrefixEntry.Prefix.Buffer[1] != L';' ||
4930  BooleanFlagOn(Fobx->Flags, FOBX_FLAG_UNC_NAME))
4931  {
4932  Prefix = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Buffer;
4933  PrefixLength = ((PNET_ROOT)Fcb->pNetRoot)->PrefixEntry.Prefix.Length;
4934  NameLength = 0;
4935 
4936  /* In that case, keep track that we will have a prefix as buffer */
4937  NameConjuringMethod = VNetRoot_As_Prefix;
4938  }
4939  else
4940  {
4941  ASSERT(NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
4942 
4943  /* Otherwise, return the prefix from our V_NET_ROOT */
4944  Prefix = VNetRoot->PrefixEntry.Prefix.Buffer;
4945  PrefixLength = VNetRoot->PrefixEntry.Prefix.Length;
4946  NameLength = VNetRoot->NamePrefix.Length;
4947 
4948  /* If we want a UNC path, skip potential device */
4949  if (NameConjuringMethod == VNetRoot_As_UNC_Name)
4950  {
4951  do
4952  {
4953  ++Prefix;
4954  PrefixLength -= sizeof(WCHAR);
4955  } while (PrefixLength > 0 && Prefix[0] != L'\\');
4956  }
4957  }
4958 
4959  /* If we added an extra backslash, skip it */
4961  {
4962  NameLength += sizeof(WCHAR);
4963  }
4964 
4965  /* If we're asked for a drive letter, skip the prefix */
4966  if (NameConjuringMethod == VNetRoot_As_DriveLetter)
4967  {
4968  PrefixLength = 0;
4969 
4970  /* And make sure we arrive at a backslash */
4971  if (Fcb->FcbTableEntry.Path.Length > NameLength &&
4972  Fcb->FcbTableEntry.Path.Buffer[NameLength / sizeof(WCHAR)] != L'\\')
4973  {
4974  NameLength -= sizeof(WCHAR);
4975  }
4976  }
4977  else
4978  {
4979  /* Prepare to copy the prefix, make sure not to overflow */
4980  if (*LengthRemaining >= PrefixLength)
4981  {
4982  /* Copy everything */
4983  ToCopy = PrefixLength;
4984  *LengthRemaining = *LengthRemaining - PrefixLength;
4985  }
4986  else
4987  {
4988  /* Copy as much as we can */
4989  ToCopy = *LengthRemaining;
4990  /* And return failure */
4991  *LengthRemaining = -1;
4992  }
4993 
4994  /* Copy the prefix */
4995  RtlCopyMemory(OriginalName, Prefix, ToCopy);
4996  }
4997 
4998  /* Do we have a name to copy now? */
4999  if (Fcb->FcbTableEntry.Path.Length > NameLength)
5000  {
5001  ToCopy = Fcb->FcbTableEntry.Path.Length - NameLength;
5003  }
5004  else
5005  {
5006  /* Just use slash for now */
5007  ToCopy = sizeof(WCHAR);
5008  NameLength = 0;
5009  Name = L"\\";
5010  }
5011 
5012  /* Total length we will have in the output buffer (if everything is alright) */
5013  *ActualNameLength = ToCopy + PrefixLength;
5014  /* If we still have room to write data */
5015  if (*LengthRemaining != -1)
5016  {
5017  /* If we can copy everything, it's fine! */
5018  if (*LengthRemaining > ToCopy)
5019  {
5020  *LengthRemaining = *LengthRemaining - ToCopy;
5021  }
5022  /* Otherwise, copy as much as possible, and return failure */
5023  else
5024  {
5025  ToCopy = *LengthRemaining;
5026  *LengthRemaining = -1;
5027  }
5028 
5029  /* Copy name after the prefix */
5030  RtlCopyMemory(Add2Ptr(OriginalName, PrefixLength),
5031  Add2Ptr(Name, NameLength), ToCopy);
5032  }
5033 }
5034 
5035 /*
5036  * @implemented
5037  */
5038 VOID
5040  IN PRX_CONTEXT RxContext)
5041 {
5042  PIRP Irp;
5043  PVOID DfsContext;
5045  PIO_STACK_LOCATION Stack;
5046  PDFS_NAME_CONTEXT DfsNameContext;
5047  PIO_SECURITY_CONTEXT SecurityContext;
5048 
5049  Irp = RxContext->CurrentIrp;
5050  Stack = RxContext->CurrentIrpSp;
5051  FileObject = Stack->FileObject;
5052  SecurityContext = Stack->Parameters.Create.SecurityContext;
5053 
5054  RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext;
5055  if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL)
5056  {
5057  RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor);
5058  DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext,
5059  RxContext->Create.SdLength);
5060  }
5061  if (SecurityContext->SecurityQos != NULL)
5062  {
5063  RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel;
5064  }
5065  else
5066  {
5067  RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation;
5068  }
5069  RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
5070 
5071  RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart;
5072  RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
5073  RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
5074  RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
5075  RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
5076 
5077  DfsContext = FileObject->FsContext2;
5078  DfsNameContext = FileObject->FsContext;
5079  RxContext->Create.NtCreateParameters.DfsContext = DfsContext;
5080  RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext;
5081  ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) ||
5082  DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) ||
5083  DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) ||
5084  DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT));
5085  ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT ||
5086  DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT ||
5087  DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT ||
5088  DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT);
5089  FileObject->FsContext2 = NULL;
5090  FileObject->FsContext = NULL;
5091 
5092  RxContext->pFcb = NULL;
5093  RxContext->Create.ReturnedCreateInform