f3771cf38c7c3e4cac13f2b470b181b1a96fe60f
[reactos.git] / reactos / sdk / lib / drivers / rdbsslib / rdbss.c
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
41 NTSTATUS
42 (NTAPI *PRX_FSD_DISPATCH) (
43 PRX_CONTEXT Context);
44
45 typedef struct _RX_FSD_DISPATCH_VECTOR
46 {
47 PRX_FSD_DISPATCH CommonRoutine;
48 } RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
49
50 VOID
51 NTAPI
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject);
54
55 NTSTATUS
56 NTAPI
57 RxAcquireForCcFlush(
58 PFILE_OBJECT FileObject,
59 PDEVICE_OBJECT DeviceObject);
60
61 VOID
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64
65 VOID
66 RxAssert(
67 PVOID Assert,
68 PVOID File,
69 ULONG Line,
70 PVOID Message);
71
72 NTSTATUS
73 NTAPI
74 RxCommonCleanup(
75 PRX_CONTEXT Context);
76
77 NTSTATUS
78 NTAPI
79 RxCommonClose(
80 PRX_CONTEXT Context);
81
82 NTSTATUS
83 NTAPI
84 RxCommonCreate(
85 PRX_CONTEXT Context);
86
87 NTSTATUS
88 NTAPI
89 RxCommonDevFCBCleanup(
90 PRX_CONTEXT Context);
91
92 NTSTATUS
93 NTAPI
94 RxCommonDevFCBClose(
95 PRX_CONTEXT Context);
96
97 NTSTATUS
98 NTAPI
99 RxCommonDevFCBFsCtl(
100 PRX_CONTEXT Context);
101
102 NTSTATUS
103 NTAPI
104 RxCommonDevFCBIoCtl(
105 PRX_CONTEXT Context);
106
107 NTSTATUS
108 NTAPI
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context);
111
112 NTSTATUS
113 NTAPI
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context);
116
117 NTSTATUS
118 NTAPI
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context);
121
122 NTSTATUS
123 NTAPI
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context);
126
127 NTSTATUS
128 NTAPI
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context);
131
132 NTSTATUS
133 NTAPI
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context);
136
137 NTSTATUS
138 NTAPI
139 RxCommonLockControl(
140 PRX_CONTEXT Context);
141
142 NTSTATUS
143 NTAPI
144 RxCommonQueryEa(
145 PRX_CONTEXT Context);
146
147 NTSTATUS
148 NTAPI
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context);
151
152 NTSTATUS
153 NTAPI
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context);
156
157 NTSTATUS
158 NTAPI
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context);
161
162 NTSTATUS
163 NTAPI
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context);
166
167 NTSTATUS
168 NTAPI
169 RxCommonRead(
170 PRX_CONTEXT Context);
171
172 NTSTATUS
173 NTAPI
174 RxCommonSetEa(
175 PRX_CONTEXT Context);
176
177 NTSTATUS
178 NTAPI
179 RxCommonSetInformation(
180 PRX_CONTEXT Context);
181
182 NTSTATUS
183 NTAPI
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context);
186
187 NTSTATUS
188 NTAPI
189 RxCommonSetSecurity(
190 PRX_CONTEXT Context);
191
192 NTSTATUS
193 NTAPI
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context);
196
197 NTSTATUS
198 NTAPI
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context);
201
202 NTSTATUS
203 NTAPI
204 RxCommonWrite(
205 PRX_CONTEXT Context);
206
207 VOID
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext);
210
211 NTSTATUS
212 RxCreateFromNetRoot(
213 PRX_CONTEXT Context,
214 PUNICODE_STRING NetRootName);
215
216 NTSTATUS
217 RxCreateTreeConnect(
218 IN PRX_CONTEXT RxContext);
219
220 BOOLEAN
221 NTAPI
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject,
224 PLARGE_INTEGER FileOffset,
225 ULONG Length, BOOLEAN Wait,
226 ULONG LockKey, BOOLEAN CheckForReadOperation,
227 PIO_STATUS_BLOCK IoStatus,
228 PDEVICE_OBJECT DeviceObject);
229
230 BOOLEAN
231 NTAPI
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject,
234 BOOLEAN Wait,
235 PVOID InputBuffer OPTIONAL,
236 ULONG InputBufferLength,
237 PVOID OutputBuffer OPTIONAL,
238 ULONG OutputBufferLength,
239 ULONG IoControlCode,
240 PIO_STATUS_BLOCK IoStatus,
241 PDEVICE_OBJECT DeviceObject);
242
243 BOOLEAN
244 NTAPI
245 RxFastIoRead(
246 PFILE_OBJECT FileObject,
247 PLARGE_INTEGER FileOffset,
248 ULONG Length,
249 BOOLEAN Wait,
250 ULONG LockKey,
251 PVOID Buffer,
252 PIO_STATUS_BLOCK IoStatus,
253 PDEVICE_OBJECT DeviceObject);
254
255 BOOLEAN
256 NTAPI
257 RxFastIoWrite(
258 PFILE_OBJECT FileObject,
259 PLARGE_INTEGER FileOffset,
260 ULONG Length,
261 BOOLEAN Wait,
262 ULONG LockKey,
263 PVOID Buffer,
264 PIO_STATUS_BLOCK IoStatus,
265 PDEVICE_OBJECT DeviceObject);
266
267 NTSTATUS
268 RxFindOrCreateFcb(
269 PRX_CONTEXT RxContext,
270 PUNICODE_STRING NetRootName);
271
272 NTSTATUS
273 RxFirstCanonicalize(
274 PRX_CONTEXT RxContext,
275 PUNICODE_STRING FileName,
276 PUNICODE_STRING CanonicalName,
277 PNET_ROOT_TYPE NetRootType);
278
279 VOID
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context);
282
283 VOID
284 NTAPI
285 RxFspDispatch(
286 IN PVOID Context);
287
288 VOID
289 NTAPI
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath);
292
293 NTSTATUS
294 NTAPI
295 RxGetStringRegistryParameter(
296 IN HANDLE KeyHandle,
297 IN PCWSTR KeyName,
298 OUT PUNICODE_STRING OutString,
299 IN PUCHAR Buffer,
300 IN ULONG BufferLength,
301 IN BOOLEAN LogFailure);
302
303 VOID
304 NTAPI
305 RxInitializeDebugSupport(
306 VOID);
307
308 VOID
309 NTAPI
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject);
312
313 NTSTATUS
314 NTAPI
315 RxInitializeRegistrationStructures(
316 VOID);
317
318 VOID
319 NTAPI
320 RxInitializeTopLevelIrpPackage(
321 VOID);
322
323 VOID
324 NTAPI
325 RxInitUnwind(
326 PDRIVER_OBJECT DriverObject,
327 USHORT State);
328
329 BOOLEAN
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332
333 NTSTATUS
334 NTAPI
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext);
337
338 NTSTATUS
339 RxLowIoReadShell(
340 PRX_CONTEXT RxContext);
341
342 NTSTATUS
343 NTAPI
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext);
346
347 NTSTATUS
348 RxLowIoWriteShell(
349 IN PRX_CONTEXT RxContext);
350
351 NTSTATUS
352 NTAPI
353 RxLowIoWriteShellCompletion(
354 PRX_CONTEXT RxContext);
355
356 PVOID
357 RxNewMapUserBuffer(
358 PRX_CONTEXT RxContext);
359
360 NTSTATUS
361 RxNotifyChangeDirectory(
362 PRX_CONTEXT RxContext);
363
364 NTSTATUS
365 RxpQueryInfoMiniRdr(
366 PRX_CONTEXT RxContext,
367 FILE_INFORMATION_CLASS FileInfoClass,
368 PVOID Buffer);
369
370 VOID
371 RxPurgeNetFcb(
372 PFCB Fcb,
373 PRX_CONTEXT LocalContext);
374
375 NTSTATUS
376 RxQueryAlternateNameInfo(
377 PRX_CONTEXT RxContext,
378 PFILE_NAME_INFORMATION AltNameInfo);
379
380 NTSTATUS
381 RxQueryBasicInfo(
382 PRX_CONTEXT RxContext,
383 PFILE_BASIC_INFORMATION BasicInfo);
384
385 NTSTATUS
386 RxQueryCompressedInfo(
387 PRX_CONTEXT RxContext,
388 PFILE_COMPRESSION_INFORMATION CompressionInfo);
389
390 NTSTATUS
391 RxQueryDirectory(
392 PRX_CONTEXT RxContext);
393
394 NTSTATUS
395 RxQueryEaInfo(
396 PRX_CONTEXT RxContext,
397 PFILE_EA_INFORMATION EaInfo);
398
399 NTSTATUS
400 RxQueryInternalInfo(
401 PRX_CONTEXT RxContext,
402 PFILE_INTERNAL_INFORMATION InternalInfo);
403
404 NTSTATUS
405 RxQueryNameInfo(
406 PRX_CONTEXT RxContext,
407 PFILE_NAME_INFORMATION NameInfo);
408
409 NTSTATUS
410 RxQueryPipeInfo(
411 PRX_CONTEXT RxContext,
412 PFILE_PIPE_INFORMATION PipeInfo);
413
414 NTSTATUS
415 RxQueryPositionInfo(
416 PRX_CONTEXT RxContext,
417 PFILE_POSITION_INFORMATION PositionInfo);
418
419 NTSTATUS
420 RxQueryStandardInfo(
421 PRX_CONTEXT RxContext,
422 PFILE_STANDARD_INFORMATION StandardInfo);
423
424 VOID
425 NTAPI
426 RxReadRegistryParameters(
427 VOID);
428
429 VOID
430 NTAPI
431 RxReleaseFileForNtCreateSection(
432 PFILE_OBJECT FileObject);
433
434 NTSTATUS
435 NTAPI
436 RxReleaseForCcFlush(
437 PFILE_OBJECT FileObject,
438 PDEVICE_OBJECT DeviceObject);
439
440 PRX_CONTEXT
441 RxRemoveOverflowEntry(
442 PRDBSS_DEVICE_OBJECT DeviceObject,
443 WORK_QUEUE_TYPE Queue);
444
445 NTSTATUS
446 RxSearchForCollapsibleOpen(
447 PRX_CONTEXT RxContext,
448 ACCESS_MASK DesiredAccess,
449 ULONG ShareAccess);
450
451 NTSTATUS
452 RxSetAllocationInfo(
453 PRX_CONTEXT RxContext);
454
455 NTSTATUS
456 RxSetBasicInfo(
457 PRX_CONTEXT RxContext);
458
459 NTSTATUS
460 RxSetDispositionInfo(
461 PRX_CONTEXT RxContext);
462
463 NTSTATUS
464 RxSetEndOfFileInfo(
465 PRX_CONTEXT RxContext);
466
467 NTSTATUS
468 RxSetPipeInfo(
469 PRX_CONTEXT RxContext);
470
471 NTSTATUS
472 RxSetPositionInfo(
473 PRX_CONTEXT RxContext);
474
475 NTSTATUS
476 RxSetRenameInfo(
477 PRX_CONTEXT RxContext);
478
479 NTSTATUS
480 RxSetSimpleInfo(
481 PRX_CONTEXT RxContext);
482
483 VOID
484 RxSetupNetFileObject(
485 PRX_CONTEXT RxContext);
486
487 NTSTATUS
488 RxSystemControl(
489 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
490 IN PIRP Irp);
491
492 VOID
493 RxUninitializeCacheMap(
494 PRX_CONTEXT RxContext,
495 PFILE_OBJECT FileObject,
496 PLARGE_INTEGER TruncateSize);
497
498 VOID
499 RxUnstart(
500 PRX_CONTEXT Context,
501 PRDBSS_DEVICE_OBJECT DeviceObject);
502
503 NTSTATUS
504 RxXXXControlFileCallthru(
505 PRX_CONTEXT Context);
506
507 PVOID
508 NTAPI
509 _RxAllocatePoolWithTag(
510 _In_ POOL_TYPE PoolType,
511 _In_ SIZE_T NumberOfBytes,
512 _In_ ULONG Tag);
513
514 VOID
515 NTAPI
516 _RxFreePool(
517 _In_ PVOID Buffer);
518
519 VOID
520 NTAPI
521 _RxFreePoolWithTag(
522 _In_ PVOID Buffer,
523 _In_ ULONG Tag);
524
525 WCHAR RxStarForTemplate = '*';
526 WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
528 BOOLEAN DisableFlushOnCleanup = FALSE;
529 ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;
530 LIST_ENTRY RxActiveContexts;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList;
532 FAST_MUTEX RxContextPerFileSerializationMutex;
533 RDBSS_DATA RxData;
534 FCB RxDeviceFCB;
535 BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
537 {
538 { RxCommonDispatchProblem },
539 { RxCommonDispatchProblem },
540 { RxCommonDevFCBClose },
541 { RxCommonDispatchProblem },
542 { RxCommonDispatchProblem },
543 { RxCommonDispatchProblem },
544 { RxCommonDispatchProblem },
545 { RxCommonDispatchProblem },
546 { RxCommonDispatchProblem },
547 { RxCommonDispatchProblem },
548 { RxCommonDevFCBQueryVolInfo },
549 { RxCommonDispatchProblem },
550 { RxCommonDispatchProblem },
551 { RxCommonDevFCBFsCtl },
552 { RxCommonDevFCBIoCtl },
553 { RxCommonDevFCBIoCtl },
554 { RxCommonDispatchProblem },
555 { RxCommonDispatchProblem },
556 { RxCommonDevFCBCleanup },
557 { RxCommonDispatchProblem },
558 { RxCommonDispatchProblem },
559 { RxCommonDispatchProblem },
560 { RxCommonUnimplemented },
561 { RxCommonUnimplemented },
562 { RxCommonUnimplemented },
563 { RxCommonUnimplemented },
564 { RxCommonUnimplemented },
565 { RxCommonUnimplemented },
566 };
567 RDBSS_EXPORTS RxExports;
568 FAST_IO_DISPATCH RxFastIoDispatch;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
571 {
572 { RxCommonCreate },
573 { RxCommonUnimplemented },
574 { RxCommonClose },
575 { RxCommonRead },
576 { RxCommonWrite },
577 { RxCommonQueryInformation },
578 { RxCommonSetInformation },
579 { RxCommonQueryEa },
580 { RxCommonSetEa },
581 { RxCommonFlushBuffers },
582 { RxCommonQueryVolumeInformation },
583 { RxCommonSetVolumeInformation },
584 { RxCommonDirectoryControl },
585 { RxCommonFileSystemControl },
586 { RxCommonDeviceControl },
587 { RxCommonDeviceControl },
588 { RxCommonUnimplemented },
589 { RxCommonLockControl },
590 { RxCommonCleanup },
591 { RxCommonUnimplemented },
592 { RxCommonQuerySecurity },
593 { RxCommonSetSecurity },
594 { RxCommonUnimplemented },
595 { RxCommonUnimplemented },
596 { RxCommonUnimplemented },
597 { RxCommonQueryQuotaInformation },
598 { RxCommonSetQuotaInformation },
599 { RxCommonUnimplemented },
600 };
601 ULONG RxFsdEntryCount;
602 LIST_ENTRY RxIrpsList;
603 KSPIN_LOCK RxIrpsListSpinLock;
604 KMUTEX RxScavengerMutex;
605 KMUTEX RxSerializationMutex;
606 UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
607 KSPIN_LOCK TopLevelIrpSpinLock;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList;
609 BOOLEAN RxForceQFIPassThrough = FALSE;
610 BOOLEAN RxNoAsync = FALSE;
611
612 DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
613
614 #if RDBSS_ASSERTS
615 #ifdef ASSERT
616 #undef ASSERT
617 #endif
618
619 #define ASSERT(exp) \
620 if (!(exp)) \
621 { \
622 RxAssert(#exp, __FILE__, __LINE__, NULL); \
623 }
624 #endif
625
626 #if RX_POOL_WRAPPER
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
629 #undef RxFreePool
630
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
635 #endif
636
637 /* FUNCTIONS ****************************************************************/
638
639 /*
640 * @implemented
641 */
642 VOID
643 CheckForLoudOperations(
644 PRX_CONTEXT RxContext)
645 {
646 PAGED_CODE();
647
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
649
650 /* Are loud operations enabled? */
651 if (RxLoudLowIoOpsEnabled)
652 {
653 PFCB Fcb;
654
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 Fcb = (PFCB)RxContext->pFcb;
657 if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
658 L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
659 {
660 SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
661 }
662 }
663 #undef ALLSCR_LENGTH
664 }
665
666 /*
667 * @implemented
668 */
669 VOID
670 __RxInitializeTopLevelIrpContext(
671 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
672 IN PIRP Irp,
673 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
674 IN ULONG Flags)
675 {
676 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
677
678 RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
679 TopLevelContext->Irp = Irp;
680 TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
681 TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
682 TopLevelContext->RxDeviceObject = RxDeviceObject;
683 TopLevelContext->Previous = IoGetTopLevelIrp();
684 TopLevelContext->Thread = PsGetCurrentThread();
685
686 /* We cannot add to list something that'd come from stack */
687 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
688 {
689 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext);
690 }
691 }
692
693 /*
694 * @implemented
695 */
696 VOID
697 __RxWriteReleaseResources(
698 PRX_CONTEXT RxContext,
699 BOOLEAN ResourceOwnerSet,
700 ULONG LineNumber,
701 PCSTR FileName,
702 ULONG SerialNumber)
703 {
704 PFCB Fcb;
705
706 PAGED_CODE();
707
708 ASSERT(RxContext != NULL);
709
710 Fcb = (PFCB)RxContext->pFcb;
711 ASSERT(Fcb != NULL);
712
713 /* If FCB resource was acquired, release it */
714 if (RxContext->FcbResourceAcquired)
715 {
716 /* Taking care of owner */
717 if (ResourceOwnerSet)
718 {
719 RxReleaseFcbForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
720 }
721 else
722 {
723 RxReleaseFcb(RxContext, Fcb);
724 }
725
726 RxContext->FcbResourceAcquired = FALSE;
727 }
728
729 /* If FCB paging resource was acquired, release it */
730 if (RxContext->FcbPagingIoResourceAcquired)
731 {
732 /* Taking care of owner */
733 if (ResourceOwnerSet)
734 {
735 RxReleasePagingIoResourceForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
736 }
737 else
738 {
739 RxReleasePagingIoResource(RxContext, Fcb);
740 }
741
742 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
743 }
744 }
745
746 /*
747 * @implemented
748 */
749 VOID
750 RxAddToTopLevelIrpAllocatedContextsList(
751 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
752 {
753 KIRQL OldIrql;
754
755 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
756
757 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
758 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
759
760 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
761 InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
762 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
763 }
764
765 /*
766 * @implemented
767 */
768 VOID
769 NTAPI
770 RxAddToWorkque(
771 IN PRX_CONTEXT RxContext,
772 IN PIRP Irp)
773 {
774 ULONG Queued;
775 KIRQL OldIrql;
776 WORK_QUEUE_TYPE Queue;
777 PIO_STACK_LOCATION Stack;
778
779 Stack = RxContext->CurrentIrpSp;
780 RxContext->PostRequest = FALSE;
781
782 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
784 Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
785 {
786 Queue = DelayedWorkQueue;
787 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
788 }
789 else
790 {
791 Queue = CriticalWorkQueue;
792 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
793 }
794
795 /* Check for overflow */
796 if (Stack->FileObject != NULL)
797 {
798 KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
799
800 Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
801 /* In case of an overflow, add the new queued call to the overflow list */
802 if (Queued > 1)
803 {
804 InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
805 InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
806 ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
807
808 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
809 return;
810 }
811
812 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
813 }
814
815 ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
816 ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
817 }
818
819 /*
820 * @implemented
821 */
822 VOID
823 RxAdjustFileTimesAndSize(
824 PRX_CONTEXT Context)
825 {
826 PFCB Fcb;
827 PFOBX Fobx;
828 NTSTATUS Status;
829 PFILE_OBJECT FileObject;
830 LARGE_INTEGER CurrentTime;
831 FILE_BASIC_INFORMATION FileBasicInfo;
832 FILE_END_OF_FILE_INFORMATION FileEOFInfo;
833 BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
834
835 PAGED_CODE();
836
837 FileObject = Context->CurrentIrpSp->FileObject;
838 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839 if (FileObject->PrivateCacheMap == NULL)
840 {
841 return;
842 }
843
844 /* Get now */
845 KeQuerySystemTime(&CurrentTime);
846
847 Fobx = (PFOBX)Context->pFobx;
848 /* Was the file modified? */
849 FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
850 /* We'll set last write if it was modified and user didn't update yet */
851 SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
852 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853 SetLastAccess = SetLastWrite ||
854 (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
855 !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
856 /* We'll set last change if it was modified and user didn't update yet */
857 SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
858
859 /* Nothing to update? Job done */
860 if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
861 {
862 return;
863 }
864
865 Fcb = (PFCB)Context->pFcb;
866 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
867 NeedUpdate = FALSE;
868 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
869
870 /* Update lastwrite time if required */
871 if (SetLastWrite)
872 {
873 NeedUpdate = TRUE;
874 Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
875 FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
876 }
877
878 /* Update lastaccess time if required */
879 if (SetLastAccess)
880 {
881 NeedUpdate = TRUE;
882 Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
883 FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
884 }
885
886 /* Update lastchange time if required */
887 if (SetLastChange)
888 {
889 NeedUpdate = TRUE;
890 Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
891 FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
892 }
893
894 /* If one of the date was modified, issue a call to mini-rdr */
895 if (NeedUpdate)
896 {
897 Context->Info.FileInformationClass = FileBasicInformation;
898 Context->Info.Buffer = &FileBasicInfo;
899 Context->Info.Length = sizeof(FileBasicInfo);
900
901 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
902 (void)Status;
903 }
904
905 /* If the file was modified, update its EOF */
906 if (FileModified)
907 {
908 FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
909
910 Context->Info.FileInformationClass = FileEndOfFileInformation;
911 Context->Info.Buffer = &FileEOFInfo;
912 Context->Info.Length = sizeof(FileEOFInfo);
913
914 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
915 (void)Status;
916 }
917 }
918
919 /*
920 * @implemented
921 */
922 NTSTATUS
923 RxAllocateCanonicalNameBuffer(
924 PRX_CONTEXT RxContext,
925 PUNICODE_STRING CanonicalName,
926 USHORT CanonicalLength)
927 {
928 PAGED_CODE();
929
930 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
931
932 /* Context must be free of any already allocated name */
933 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
934
935 /* Validate string length */
936 if (CanonicalLength > USHRT_MAX - 1)
937 {
938 CanonicalName->Buffer = NULL;
939 return STATUS_OBJECT_PATH_INVALID;
940 }
941
942 CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
943 if (CanonicalName->Buffer == NULL)
944 {
945 return STATUS_INSUFFICIENT_RESOURCES;
946 }
947
948 CanonicalName->Length = 0;
949 CanonicalName->MaximumLength = CanonicalLength;
950
951 /* Set the two places - they must always be identical */
952 RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
953 RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
954
955 return STATUS_SUCCESS;
956 }
957
958 /*
959 * @implemented
960 */
961 VOID
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
963 PFOBX Fobx)
964 {
965 KIRQL OldIrql;
966 PLIST_ENTRY Entry;
967 PRX_CONTEXT Context;
968 LIST_ENTRY ContextsToCancel;
969
970 /* Init a list for the contexts to cancel */
971 InitializeListHead(&ContextsToCancel);
972
973 /* Lock our list lock */
974 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
975
976 /* Now, browse all the active contexts, to find the associated ones */
977 Entry = RxActiveContexts.Flink;
978 while (Entry != &RxActiveContexts)
979 {
980 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
981 Entry = Entry->Flink;
982
983 /* Not the IRP we're looking for, ignore */
984 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
985 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
986 {
987 continue;
988 }
989
990 /* Not the FOBX we're looking for, ignore */
991 if ((PFOBX)Context->pFobx != Fobx)
992 {
993 continue;
994 }
995
996 /* No cancel routine (can't be cancel, then), ignore */
997 if (Context->MRxCancelRoutine == NULL)
998 {
999 continue;
1000 }
1001
1002 /* Mark our context as cancelled */
1003 SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1004
1005 /* Move it to our list */
1006 RemoveEntryList(&Context->ContextListEntry);
1007 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1008
1009 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1010 }
1011
1012 /* Done with the contexts */
1013 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1014
1015 /* Now, handle all our "extracted" contexts */
1016 while (!IsListEmpty(&ContextsToCancel))
1017 {
1018 Entry = RemoveHeadList(&ContextsToCancel);
1019 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1020
1021 /* If they had an associated IRP (should be always true) */
1022 if (Context->CurrentIrp != NULL)
1023 {
1024 /* Then, call cancel routine */
1025 ASSERT(Context->MRxCancelRoutine != NULL);
1026 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1027 Context->MRxCancelRoutine(Context);
1028 }
1029
1030 /* And delete the context */
1031 RxDereferenceAndDeleteRxContext(Context);
1032 }
1033 }
1034
1035 /*
1036 * @implemented
1037 */
1038 NTSTATUS
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040 PV_NET_ROOT VNetRoot,
1041 BOOLEAN ForceFilesClosed)
1042 {
1043 KIRQL OldIrql;
1044 NTSTATUS Status;
1045 PLIST_ENTRY Entry;
1046 PRX_CONTEXT Context;
1047 LIST_ENTRY ContextsToCancel;
1048
1049 /* Init a list for the contexts to cancel */
1050 InitializeListHead(&ContextsToCancel);
1051
1052 /* Lock our list lock */
1053 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1054
1055 /* Now, browse all the active contexts, to find the associated ones */
1056 Entry = RxActiveContexts.Flink;
1057 while (Entry != &RxActiveContexts)
1058 {
1059 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1060 Entry = Entry->Flink;
1061
1062 /* Not the IRP we're looking for, ignore */
1063 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
1064 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
1065 {
1066 continue;
1067 }
1068
1069 /* Not the VNetRoot we're looking for, ignore */
1070 if (Context->pFcb == NULL ||
1071 (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
1072 {
1073 continue;
1074 }
1075
1076 /* No cancel routine (can't be cancel, then), ignore */
1077 if (Context->MRxCancelRoutine == NULL)
1078 {
1079 continue;
1080 }
1081
1082 /* At that point, we found a matching context
1083 * If we're not asked to force close, then fail - it's still open
1084 */
1085 if (!ForceFilesClosed)
1086 {
1087 Status = STATUS_FILES_OPEN;
1088 break;
1089 }
1090
1091 /* Mark our context as cancelled */
1092 SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1093
1094 /* Move it to our list */
1095 RemoveEntryList(&Context->ContextListEntry);
1096 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1097
1098 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1099 }
1100
1101 /* Done with the contexts */
1102 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1103
1104 if (Status != STATUS_SUCCESS)
1105 {
1106 return Status;
1107 }
1108
1109 /* Now, handle all our "extracted" contexts */
1110 while (!IsListEmpty(&ContextsToCancel))
1111 {
1112 Entry = RemoveHeadList(&ContextsToCancel);
1113 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1114
1115 /* If they had an associated IRP (should be always true) */
1116 if (Context->CurrentIrp != NULL)
1117 {
1118 /* Then, call cancel routine */
1119 ASSERT(Context->MRxCancelRoutine != NULL);
1120 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1121 Context->MRxCancelRoutine(Context);
1122 }
1123
1124 /* And delete the context */
1125 RxDereferenceAndDeleteRxContext(Context);
1126 }
1127
1128 return Status;
1129 }
1130
1131 VOID
1132 NTAPI
1133 RxCancelRoutine(
1134 PDEVICE_OBJECT DeviceObject,
1135 PIRP Irp)
1136 {
1137 UNIMPLEMENTED;
1138 }
1139
1140 /*
1141 * @implemented
1142 */
1143 NTSTATUS
1144 RxCanonicalizeFileNameByServerSpecs(
1145 PRX_CONTEXT RxContext,
1146 PUNICODE_STRING NetRootName)
1147 {
1148 USHORT NextChar, CurChar;
1149 USHORT MaxChars;
1150
1151 PAGED_CODE();
1152
1153 /* Validate file name is not empty */
1154 MaxChars = NetRootName->Length / sizeof(WCHAR);
1155 if (MaxChars == 0)
1156 {
1157 return STATUS_MORE_PROCESSING_REQUIRED;
1158 }
1159
1160 /* Validate name is correct */
1161 for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
1162 {
1163 USHORT i;
1164
1165 for (i = NextChar + 1; i < MaxChars; ++i)
1166 {
1167 if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
1168 {
1169 break;
1170 }
1171 }
1172
1173 CurChar = i - 1;
1174 if (CurChar == NextChar)
1175 {
1176 if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
1177 {
1178 continue;
1179 }
1180
1181 if (CurChar != 0)
1182 {
1183 if (CurChar >= MaxChars - 1)
1184 {
1185 continue;
1186 }
1187
1188 if (NetRootName->Buffer[CurChar + 1] != ':')
1189 {
1190 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1191 }
1192 }
1193 else
1194 {
1195 if (NetRootName->Buffer[1] != ':')
1196 {
1197 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1198 }
1199 }
1200 }
1201 else
1202 {
1203 if ((CurChar - NextChar) == 1)
1204 {
1205 if (NetRootName->Buffer[NextChar + 2] != '.')
1206 {
1207 continue;
1208 }
1209
1210 if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
1211 {
1212 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1213 }
1214 }
1215 else
1216 {
1217 if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
1218 || NetRootName->Buffer[NextChar + 1] != '.')
1219 {
1220 continue;
1221 }
1222
1223 if (NetRootName->Buffer[NextChar + 2] == '.')
1224 {
1225 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1226 }
1227 }
1228 }
1229 }
1230
1231 return STATUS_MORE_PROCESSING_REQUIRED;
1232 }
1233
1234 NTSTATUS
1235 RxCanonicalizeNameAndObtainNetRoot(
1236 PRX_CONTEXT RxContext,
1237 PUNICODE_STRING FileName,
1238 PUNICODE_STRING NetRootName)
1239 {
1240 NTSTATUS Status;
1241 NET_ROOT_TYPE NetRootType;
1242 UNICODE_STRING CanonicalName;
1243
1244 PAGED_CODE();
1245
1246 NetRootType = NET_ROOT_WILD;
1247
1248 RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1249 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1250
1251 /* if not relative opening, just handle the passed name */
1252 if (RxContext->CurrentIrpSp->FileObject->RelatedFileObject == NULL)
1253 {
1254 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1255 if (!NT_SUCCESS(Status))
1256 {
1257 return Status;
1258 }
1259 }
1260 else
1261 {
1262 PFCB Fcb;
1263
1264 /* Make sure we have a valid FCB and a FOBX */
1265 Fcb = RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext;
1266 if (Fcb == NULL ||
1267 RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext2 == NULL)
1268 {
1269 return STATUS_INVALID_PARAMETER;
1270 }
1271
1272 if (!NodeTypeIsFcb(Fcb))
1273 {
1274 return STATUS_INVALID_PARAMETER;
1275 }
1276
1277 UNIMPLEMENTED;
1278 }
1279
1280 /* Get/Create the associated VNetRoot for opening */
1281 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1282 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1283 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
1284 {
1285 ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1286
1287 RxFreeCanonicalNameBuffer(RxContext);
1288 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1289 if (NT_SUCCESS(Status))
1290 {
1291 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1292 }
1293 }
1294
1295 /* Filename cannot contain wildcards */
1296 if (FsRtlDoesNameContainWildCards(NetRootName))
1297 {
1298 Status = STATUS_OBJECT_NAME_INVALID;
1299 }
1300
1301 /* Make sure file name is correct */
1302 if (NT_SUCCESS(Status))
1303 {
1304 Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1305 }
1306
1307 /* Give the mini-redirector a chance to prepare the name */
1308 if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
1309 {
1310 if (RxContext->Create.pNetRoot != NULL)
1311 {
1312 NTSTATUS IgnoredStatus;
1313
1314 MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1315 MRxPreparseName, (RxContext, NetRootName));
1316 (void)IgnoredStatus;
1317 }
1318 }
1319
1320 return Status;
1321 }
1322
1323 VOID
1324 NTAPI
1325 RxCheckFcbStructuresForAlignment(
1326 VOID)
1327 {
1328 UNIMPLEMENTED;
1329 }
1330
1331 NTSTATUS
1332 RxCheckShareAccess(
1333 _In_ ACCESS_MASK DesiredAccess,
1334 _In_ ULONG DesiredShareAccess,
1335 _Inout_ PFILE_OBJECT FileObject,
1336 _Inout_ PSHARE_ACCESS ShareAccess,
1337 _In_ BOOLEAN Update,
1338 _In_ PSZ where,
1339 _In_ PSZ wherelogtag)
1340 {
1341 PAGED_CODE();
1342
1343 RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1344 RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1345
1346 return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
1347 }
1348
1349 /*
1350 * @implemented
1351 */
1352 NTSTATUS
1353 RxCheckShareAccessPerSrvOpens(
1354 IN PFCB Fcb,
1355 IN ACCESS_MASK DesiredAccess,
1356 IN ULONG DesiredShareAccess)
1357 {
1358 BOOLEAN ReadAccess;
1359 BOOLEAN WriteAccess;
1360 BOOLEAN DeleteAccess;
1361 PSHARE_ACCESS ShareAccess;
1362
1363 PAGED_CODE();
1364
1365 ShareAccess = &Fcb->ShareAccessPerSrvOpens;
1366
1367 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1368 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1369
1370 /* Check if any access wanted */
1371 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
1372 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
1373 DeleteAccess = (DesiredAccess & DELETE) != 0;
1374
1375 if (ReadAccess || WriteAccess || DeleteAccess)
1376 {
1377 BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1378 BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1379 BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1380
1381 /* Check whether there's a violation */
1382 if ((ReadAccess &&
1383 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1384 (WriteAccess &&
1385 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1386 (DeleteAccess &&
1387 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1388 ((ShareAccess->Readers != 0) && !SharedRead) ||
1389 ((ShareAccess->Writers != 0) && !SharedWrite) ||
1390 ((ShareAccess->Deleters != 0) && !SharedDelete))
1391 {
1392 return STATUS_SHARING_VIOLATION;
1393 }
1394 }
1395
1396 return STATUS_SUCCESS;
1397 }
1398
1399 VOID
1400 RxCleanupPipeQueues(
1401 PRX_CONTEXT Context)
1402 {
1403 UNIMPLEMENTED;
1404 }
1405
1406 /*
1407 * @implemented
1408 */
1409 NTSTATUS
1410 RxCloseAssociatedSrvOpen(
1411 IN PFOBX Fobx,
1412 IN PRX_CONTEXT RxContext OPTIONAL)
1413 {
1414 PFCB Fcb;
1415 NTSTATUS Status;
1416 PSRV_OPEN SrvOpen;
1417 BOOLEAN CloseSrvOpen;
1418 PRX_CONTEXT LocalContext;
1419
1420 PAGED_CODE();
1421
1422 /* Assume SRV_OPEN is already closed */
1423 CloseSrvOpen = FALSE;
1424 /* If we have a FOBX, we'll have to close it */
1425 if (Fobx != NULL)
1426 {
1427 /* If the FOBX isn't closed yet */
1428 if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1429 {
1430 SrvOpen = Fobx->SrvOpen;
1431 Fcb = (PFCB)SrvOpen->pFcb;
1432 /* Check whether we've to close SRV_OPEN first */
1433 if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1434 {
1435 CloseSrvOpen = TRUE;
1436 }
1437 else
1438 {
1439 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1440
1441 /* Not much to do */
1442 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1443
1444 if (SrvOpen->OpenCount > 0)
1445 {
1446 --SrvOpen->OpenCount;
1447 }
1448 }
1449 }
1450
1451 /* No need to close SRV_OPEN, so close FOBX */
1452 if (!CloseSrvOpen)
1453 {
1454 RxMarkFobxOnClose(Fobx);
1455
1456 return STATUS_SUCCESS;
1457 }
1458 }
1459 else
1460 {
1461 /* No FOBX? No RX_CONTEXT, ok, job done! */
1462 if (RxContext == NULL)
1463 {
1464 return STATUS_SUCCESS;
1465 }
1466
1467 /* Get the FCB from RX_CONTEXT */
1468 Fcb = (PFCB)RxContext->pFcb;
1469 SrvOpen = NULL;
1470 }
1471
1472 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1473 if (RxContext == NULL)
1474 {
1475 ASSERT(Fobx != NULL);
1476
1477 LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
1478 if (LocalContext == NULL)
1479 {
1480 return STATUS_INSUFFICIENT_RESOURCES;
1481 }
1482
1483 LocalContext->MajorFunction = 2;
1484 LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1485 LocalContext->pFobx = (PMRX_FOBX)Fobx;
1486 LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1487 }
1488 else
1489 {
1490 LocalContext = RxContext;
1491 }
1492
1493 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1494
1495 /* Now, close the FOBX */
1496 if (Fobx != NULL)
1497 {
1498 RxMarkFobxOnClose(Fobx);
1499 }
1500 else
1501 {
1502 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1503 }
1504
1505 /* If not a "standard" file, SRV_OPEN can be null */
1506 if (SrvOpen == NULL)
1507 {
1508 ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
1509 RxDereferenceNetFcb(Fcb);
1510
1511 if (LocalContext != RxContext)
1512 {
1513 RxDereferenceAndDeleteRxContext(LocalContext);
1514 }
1515
1516 return STATUS_SUCCESS;
1517 }
1518
1519 /* If SRV_OPEN isn't in a good condition, nothing to close */
1520 if (SrvOpen->Condition != Condition_Good)
1521 {
1522 if (LocalContext != RxContext)
1523 {
1524 RxDereferenceAndDeleteRxContext(LocalContext);
1525 }
1526
1527 return STATUS_SUCCESS;
1528 }
1529
1530 /* Decrease open count */
1531 if (SrvOpen->OpenCount > 0)
1532 {
1533 --SrvOpen->OpenCount;
1534 }
1535
1536 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1537 if (SrvOpen->OpenCount == 1)
1538 {
1539 if (!IsListEmpty(&SrvOpen->FobxList))
1540 {
1541 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1542 {
1543 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1544 }
1545 }
1546 }
1547
1548 /* Nothing left, purge FCB */
1549 if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1550 {
1551 RxPurgeNetFcb(Fcb, LocalContext);
1552 }
1553
1554 /* Already closed? Job done! */
1555 SrvOpen = Fobx->SrvOpen;
1556 if (SrvOpen == NULL ||
1557 (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1558 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1559 {
1560 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1561 if (LocalContext != RxContext)
1562 {
1563 RxDereferenceAndDeleteRxContext(LocalContext);
1564 }
1565
1566 return STATUS_SUCCESS;
1567 }
1568
1569 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1570
1571 /* Inform mini-rdr about closing */
1572 MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1573 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1574 Status, RxContext, Fobx, Fcb, SrvOpen);
1575
1576 /* And mark as such */
1577 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1578 SrvOpen->Key = (PVOID)-1;
1579
1580 /* If we were delayed, we're not! */
1581 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1582 {
1583 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1584 }
1585
1586 /* Clear access */
1587 RxRemoveShareAccessPerSrvOpens(SrvOpen);
1588 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
1589
1590 /* Dereference */
1591 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1592
1593 /* Mark the FOBX closed as well */
1594 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1595
1596 if (LocalContext != RxContext)
1597 {
1598 RxDereferenceAndDeleteRxContext(LocalContext);
1599 }
1600
1601 return Status;
1602 }
1603
1604 /*
1605 * @implemented
1606 */
1607 NTSTATUS
1608 RxCollapseOrCreateSrvOpen(
1609 PRX_CONTEXT RxContext)
1610 {
1611 PFCB Fcb;
1612 NTSTATUS Status;
1613 ULONG Disposition;
1614 PSRV_OPEN SrvOpen;
1615 USHORT ShareAccess;
1616 PIO_STACK_LOCATION Stack;
1617 ACCESS_MASK DesiredAccess;
1618 RX_BLOCK_CONDITION FcbCondition;
1619
1620 PAGED_CODE();
1621
1622 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1623
1624 Fcb = (PFCB)RxContext->pFcb;
1625 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1626 ++Fcb->UncleanCount;
1627
1628 Stack = RxContext->CurrentIrpSp;
1629 DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1630 ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1631
1632 Disposition = RxContext->Create.NtCreateParameters.Disposition;
1633
1634 /* Try to find a reusable SRV_OPEN */
1635 Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
1636 if (Status == STATUS_NOT_FOUND)
1637 {
1638 /* If none found, create one */
1639 SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb);
1640 if (SrvOpen == NULL)
1641 {
1642 Status = STATUS_INSUFFICIENT_RESOURCES;
1643 }
1644 else
1645 {
1646 SrvOpen->DesiredAccess = DesiredAccess;
1647 SrvOpen->ShareAccess = ShareAccess;
1648 Status = STATUS_SUCCESS;
1649 }
1650
1651 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1652
1653 if (Status != STATUS_SUCCESS)
1654 {
1655 FcbCondition = Condition_Bad;
1656 }
1657 else
1658 {
1659 RxInitiateSrvOpenKeyAssociation(SrvOpen);
1660
1661 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1662 RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1663 /* Inform the mini-rdr we're handling a create */
1664 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCreate, (RxContext));
1665 ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1666
1667 DPRINT("MRxCreate returned: %x\n", Status);
1668 if (Status == STATUS_SUCCESS)
1669 {
1670 /* In case of overwrite, reset file size */
1671 if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
1672 {
1673 RxAcquirePagingIoResource(RxContext, Fcb);
1674 Fcb->Header.AllocationSize.QuadPart = 0LL;
1675 Fcb->Header.FileSize.QuadPart = 0LL;
1676 Fcb->Header.ValidDataLength.QuadPart = 0LL;
1677 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1678 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1679 RxReleasePagingIoResource(RxContext, Fcb);
1680 }
1681 else
1682 {
1683 /* Otherwise, adjust sizes */
1684 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1685 if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1686 {
1687 RxAdjustAllocationSizeforCC(Fcb);
1688 }
1689 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1690 }
1691 }
1692
1693 /* Set the IoStatus with information returned by mini-rdr */
1694 RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1695
1696 SrvOpen->OpenStatus = Status;
1697 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1698 RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
1699
1700 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1701
1702 RxCompleteSrvOpenKeyAssociation(SrvOpen);
1703
1704 if (Status == STATUS_SUCCESS)
1705 {
1706 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1707 {
1708 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
1709 }
1710 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1711 FcbCondition = Condition_Good;
1712 }
1713 else
1714 {
1715 FcbCondition = Condition_Bad;
1716 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1717 RxContext->pRelevantSrvOpen = NULL;
1718
1719 if (RxContext->pFobx != NULL)
1720 {
1721 RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
1722 RxContext->pFobx = NULL;
1723 }
1724 }
1725 }
1726
1727 /* Set FCB state - good or bad - depending on whether create succeed */
1728 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb, Fcb->Condition);
1729 RxTransitionNetFcb(Fcb, FcbCondition);
1730 }
1731 else if (Status == STATUS_SUCCESS)
1732 {
1733 BOOLEAN IsGood, ExtraOpen;
1734
1735 /* A reusable SRV_OPEN was found */
1736 RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
1737 ExtraOpen = FALSE;
1738
1739 SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1740
1741 IsGood = (SrvOpen->Condition == Condition_Good);
1742 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1743 if (!StableCondition(SrvOpen->Condition))
1744 {
1745 RxReferenceSrvOpen(SrvOpen);
1746 ++SrvOpen->OpenCount;
1747 ExtraOpen = TRUE;
1748
1749 RxReleaseFcb(RxContext, Fcb);
1750 RxContext->Create.FcbAcquired = FALSE;
1751
1752 RxWaitForStableSrvOpen(SrvOpen, RxContext);
1753
1754 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, Fcb)))
1755 {
1756 RxContext->Create.FcbAcquired = TRUE;
1757 }
1758
1759 IsGood = (SrvOpen->Condition == Condition_Good);
1760 }
1761
1762 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1763 if (IsGood)
1764 {
1765 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1766
1767 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1768 }
1769 else
1770 {
1771 Status = SrvOpen->OpenStatus;
1772 }
1773
1774 if (ExtraOpen)
1775 {
1776 --SrvOpen->OpenCount;
1777 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1778 }
1779 }
1780
1781 --Fcb->UncleanCount;
1782
1783 DPRINT("Status: %x\n", Status);
1784 return Status;
1785 }
1786
1787 /*
1788 * @implemented
1789 */
1790 NTSTATUS
1791 NTAPI
1792 RxCommonCleanup(
1793 PRX_CONTEXT Context)
1794 {
1795 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1796 PFCB Fcb;
1797 PFOBX Fobx;
1798 ULONG OpenCount;
1799 NTSTATUS Status;
1800 PNET_ROOT NetRoot;
1801 PFILE_OBJECT FileObject;
1802 LARGE_INTEGER TruncateSize;
1803 PLARGE_INTEGER TruncateSizePtr;
1804 BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1805
1806 PAGED_CODE();
1807
1808 Fcb = (PFCB)Context->pFcb;
1809 Fobx = (PFOBX)Context->pFobx;
1810 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1811
1812 /* File system closing, it's OK */
1813 if (Fobx == NULL)
1814 {
1815 if (Fcb->UncleanCount > 0)
1816 {
1817 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1818 }
1819
1820 return STATUS_SUCCESS;
1821 }
1822
1823 /* Check we have a correct FCB type */
1824 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
1825 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
1826 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1827 NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
1828 {
1829 DPRINT1("Invalid Fcb type for %p\n", Fcb);
1830 RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1831 }
1832
1833 FileObject = Context->CurrentIrpSp->FileObject;
1834 ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
1835
1836 RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1837
1838 Status = RxAcquireExclusiveFcb(Context, Fcb);
1839 if (!NT_SUCCESS(Status))
1840 {
1841 return Status;
1842 }
1843
1844 FcbAcquired = TRUE;
1845
1846 Fobx->AssociatedFileObject = NULL;
1847
1848 /* In case SRV_OPEN used is part of FCB */
1849 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED))
1850 {
1851 ASSERT(Fcb->UncleanCount != 0);
1852 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1853
1854 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1855 {
1856 --Fcb->UncachedUncleanCount;
1857 }
1858
1859 /* Inform mini-rdr */
1860 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1861
1862 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1863 --Fobx->SrvOpen->UncleanFobxCount;
1864
1865 RxUninitializeCacheMap(Context, FileObject, NULL);
1866
1867 RxReleaseFcb(Context, Fcb);
1868
1869 return STATUS_SUCCESS;
1870 }
1871
1872 /* Report the fact that file could be set as delete on close */
1873 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1874 {
1875 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
1876 }
1877
1878 /* Cancel any pending notification */
1879 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
1880
1881 /* Backup open count before we start playing with it */
1882 OpenCount = Fcb->ShareAccess.OpenCount;
1883
1884 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1885 FcbTableAcquired = FALSE;
1886 LeftForDelete = FALSE;
1887 OneLeft = (Fcb->UncleanCount == 1);
1888
1889 _SEH2_TRY
1890 {
1891 /* Unclean count and delete on close? Verify whether we're the one */
1892 if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
1893 {
1894 if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
1895 {
1896 FcbTableAcquired = TRUE;
1897 }
1898 else
1899 {
1900 RxReleaseFcb(Context, Fcb);
1901
1902 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
1903
1904 Status = RxAcquireExclusiveFcb(Context, Fcb);
1905 if (Status != STATUS_SUCCESS)
1906 {
1907 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1908 return Status;
1909 }
1910
1911 FcbTableAcquired = TRUE;
1912 }
1913
1914 /* That means we'll perform the delete on close! */
1915 if (Fcb->UncleanCount == 1)
1916 {
1917 LeftForDelete = TRUE;
1918 }
1919 else
1920 {
1921 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1922 FcbTableAcquired = FALSE;
1923 }
1924 }
1925
1926 IsFile = FALSE;
1927 TruncateSizePtr = NULL;
1928 /* Handle cleanup for pipes and printers */
1929 if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
1930 {
1931 RxCleanupPipeQueues(Context);
1932 }
1933 /* Handle cleanup for files */
1934 else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
1935 {
1936 Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
1937 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
1938 {
1939 /* First, unlock */
1940 FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
1941
1942 /* If there are still locks to release, proceed */
1943 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
1944 {
1945 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
1946 Context->LowIoContext.ParamsFor.Locks.Flags = 0;
1947 Status = RxLowIoLockControlShell(Context);
1948 }
1949
1950 /* Fix times and size */
1951 RxAdjustFileTimesAndSize(Context);
1952
1953 /* If we're the only one left... */
1954 if (OneLeft)
1955 {
1956 /* And if we're supposed to delete on close */
1957 if (LeftForDelete)
1958 {
1959 /* Update the sizes */
1960 RxAcquirePagingIoResource(Context, Fcb);
1961 Fcb->Header.FileSize.QuadPart = 0;
1962 Fcb->Header.ValidDataLength.QuadPart = 0;
1963 RxReleasePagingIoResource(Context, Fcb);
1964 }
1965 /* Otherwise, call the mini-rdr to adjust sizes */
1966 else
1967 {
1968 /* File got grown up, fill with zeroes */
1969 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
1970 (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
1971 {
1972 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
1973 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1974 }
1975
1976 /* File was truncated, let mini-rdr proceed */
1977 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
1978 {
1979 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
1980 ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
1981
1982 /* Keep track of file change for Cc uninit */
1983 TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
1984 TruncateSizePtr = &TruncateSize;
1985 }
1986 }
1987 }
1988
1989 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1990 if (NeedPurge)
1991 {
1992 if (!OneLeft)
1993 {
1994 NeedPurge = FALSE;
1995 }
1996 }
1997 /* Otherwise, try to see whether we can purge */
1998 else
1999 {
2000 NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
2001 }
2002
2003 IsFile = TRUE;
2004 }
2005 }
2006
2007 /* We have to still be there! */
2008 ASSERT(Fcb->UncleanCount != 0);
2009 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
2010
2011 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2012 {
2013 --Fcb->UncachedUncleanCount;
2014 }
2015
2016 /* Inform mini-rdr about ongoing cleanup */
2017 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
2018
2019 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
2020 --Fobx->SrvOpen->UncleanFobxCount;
2021
2022 /* Flush cache */
2023 if (DisableFlushOnCleanup)
2024 {
2025 /* Only if we're the last standing */
2026 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
2027 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
2028 {
2029 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
2030 RxFlushFcbInSystemCache(Fcb, TRUE);
2031 }
2032 }
2033 else
2034 {
2035 /* Always */
2036 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2037 {
2038 DPRINT("Flushing %p on cleanup\n", Context);
2039 RxFlushFcbInSystemCache(Fcb, TRUE);
2040 }
2041 }
2042
2043 /* If only remaining uncached & unclean, then flush and purge */
2044 if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2045 {
2046 if (Fcb->UncachedUncleanCount != 0)
2047 {
2048 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
2049 Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2050 {
2051 DPRINT("Flushing FCB in system cache for %p\n", Context);
2052 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
2053 }
2054 }
2055 }
2056
2057 /* If purge required, and not about to delete, flush */
2058 if (!LeftForDelete && NeedPurge)
2059 {
2060 DPRINT("Flushing FCB in system cache for %p\n", Context);
2061 RxFlushFcbInSystemCache(Fcb, TRUE);
2062 }
2063
2064 /* If it was a file, drop cache */
2065 if (IsFile)
2066 {
2067 DPRINT("Uninit cache map for file\n");
2068 RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
2069 }
2070
2071 /* If that's the one left for deletion, or if it needs purge, flush */
2072 if (LeftForDelete || NeedPurge)
2073 {
2074 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
2075 /* If that's for deletion, also remove from FCB table */
2076 if (LeftForDelete)
2077 {
2078 RxRemoveNameNetFcb(Fcb);
2079 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2080 FcbTableAcquired = FALSE;
2081 }
2082 }
2083
2084 /* Remove any share access */
2085 if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
2086 {
2087 RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
2088 }
2089
2090 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2091 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
2092 RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
2093 {
2094 NTSTATUS InternalStatus;
2095 PRX_CONTEXT InternalContext;
2096
2097 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2098 InternalStatus = STATUS_UNSUCCESSFUL;
2099 InternalContext = RxCreateRxContext(Context->CurrentIrp,
2100 Fcb->RxDeviceObject,
2101 RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
2102 if (InternalContext != NULL)
2103 {
2104 FILE_END_OF_FILE_INFORMATION FileEOF;
2105
2106 InternalStatus = STATUS_SUCCESS;
2107
2108 /* Initialize the context for file information set */
2109 InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
2110 InternalContext->pFobx = (PMRX_FOBX)Fobx;
2111 InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
2112
2113 /* Get EOF from the FCB */
2114 FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
2115 InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
2116 InternalContext->Info.Buffer = &FileEOF;
2117 InternalContext->Info.Length = sizeof(FileEOF);
2118
2119 /* Call the mini-rdr */
2120 MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
2121
2122 /* We're done */
2123 RxDereferenceAndDeleteRxContext(InternalContext);
2124 }
2125
2126 /* We tried, so, clean the FOBX flag */
2127 ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
2128 /* If it failed, then, disable collapsing on the FCB */
2129 if (!NT_SUCCESS(InternalStatus))
2130 {
2131 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2132 }
2133 }
2134
2135 /* We're clean! */
2136 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
2137
2138 FcbAcquired = FALSE;
2139 RxReleaseFcb(Context, Fcb);
2140 }
2141 _SEH2_FINALLY
2142 {
2143 if (FcbAcquired)
2144 {
2145 RxReleaseFcb(Context, Fcb);
2146 }
2147
2148 if (FcbTableAcquired)
2149 {
2150 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2151 }
2152 }
2153 _SEH2_END;
2154
2155 return Status;
2156 #undef BugCheckFileId
2157 }
2158
2159 NTSTATUS
2160 NTAPI
2161 RxCommonClose(
2162 PRX_CONTEXT Context)
2163 {
2164 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2165 PFCB Fcb;
2166 PFOBX Fobx;
2167 NTSTATUS Status;
2168 PFILE_OBJECT FileObject;
2169 BOOLEAN DereferenceFobx, AcquiredFcb;
2170
2171 PAGED_CODE();
2172
2173 Fcb = (PFCB)Context->pFcb;
2174 Fobx = (PFOBX)Context->pFobx;
2175 FileObject = Context->CurrentIrpSp->FileObject;
2176 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
2177
2178 Status = RxAcquireExclusiveFcb(Context, Fcb);
2179 if (!NT_SUCCESS(Status))
2180 {
2181 return Status;
2182 }
2183
2184 AcquiredFcb = TRUE;
2185 _SEH2_TRY
2186 {
2187 BOOLEAN Freed;
2188
2189 /* Check our FCB type is expected */
2190 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2191 (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
2192 (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
2193 {
2194 RxBugCheck(NodeType(Fcb), 0, 0);
2195 }
2196
2197 RxReferenceNetFcb(Fcb);
2198
2199 DereferenceFobx = FALSE;
2200 /* If we're not closing FS */
2201 if (Fobx != NULL)
2202 {
2203 PSRV_OPEN SrvOpen;
2204 PSRV_CALL SrvCall;
2205
2206 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
2207 SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
2208 /* Handle delayed close */
2209 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2210 {
2211 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
2212 {
2213 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
2214 {
2215 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
2216
2217 if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
2218 {
2219 if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
2220 {
2221 InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
2222 }
2223 else
2224 {
2225 DereferenceFobx = TRUE;
2226 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
2227 }
2228 }
2229 }
2230 }
2231 }
2232
2233 /* If we reach maximum of delayed close/or if there are no delayed close */
2234 if (!DereferenceFobx)
2235 {
2236 PNET_ROOT NetRoot;
2237
2238 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2239 if (NetRoot->Type != NET_ROOT_PRINT)
2240 {
2241 /* Delete if asked */
2242 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
2243 {
2244 RxScavengeRelatedFobxs(Fcb);
2245 RxSynchronizeWithScavenger(Context);
2246
2247 RxReleaseFcb(Context, Fcb);
2248
2249 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2250 RxOrphanThisFcb(Fcb);
2251 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2252
2253 Status = RxAcquireExclusiveFcb(Context, Fcb);
2254 ASSERT(NT_SUCCESS(Status));
2255 }
2256 }
2257 }
2258
2259 RxMarkFobxOnClose(Fobx);
2260 }
2261
2262 if (DereferenceFobx)
2263 {
2264 ASSERT(Fobx != NULL);
2265 RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
2266 }
2267 else
2268 {
2269 RxCloseAssociatedSrvOpen(Fobx, Context);
2270 if (Fobx != NULL)
2271 {
2272 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
2273 }
2274 }
2275
2276 Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
2277 AcquiredFcb = !Freed;
2278
2279 FileObject->FsContext = (PVOID)-1;
2280
2281 if (Freed)
2282 {
2283 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2284 }
2285 else
2286 {
2287 RxReleaseFcb(Context, Fcb);
2288 AcquiredFcb = FALSE;
2289 }
2290 }
2291 _SEH2_FINALLY
2292 {
2293 if (_SEH2_AbnormalTermination())
2294 {
2295 if (AcquiredFcb)
2296 {
2297 RxReleaseFcb(Context, Fcb);
2298 }
2299 }
2300 else
2301 {
2302 ASSERT(!AcquiredFcb);
2303 }
2304 }
2305 _SEH2_END;
2306
2307 DPRINT("Status: %x\n", Status);
2308 return Status;
2309 #undef BugCheckFileId
2310 }
2311
2312 /*
2313 * @implemented
2314 */
2315 NTSTATUS
2316 NTAPI
2317 RxCommonCreate(
2318 PRX_CONTEXT Context)
2319 {
2320 PIRP Irp;
2321 NTSTATUS Status;
2322 PFILE_OBJECT FileObject;
2323 PIO_STACK_LOCATION Stack;
2324
2325 PAGED_CODE();
2326
2327 DPRINT("RxCommonCreate(%p)\n", Context);
2328
2329 Irp = Context->CurrentIrp;
2330 Stack = Context->CurrentIrpSp;
2331 FileObject = Stack->FileObject;
2332
2333 /* Check whether that's a device opening */
2334 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2335 {
2336 FileObject->FsContext = &RxDeviceFCB;
2337 FileObject->FsContext2 = NULL;
2338
2339 ++RxDeviceFCB.NodeReferenceCount;
2340 ++RxDeviceFCB.OpenCount;
2341
2342 Irp->IoStatus.Information = FILE_OPENED;
2343 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2344
2345 Status = STATUS_SUCCESS;
2346 }
2347 else
2348 {
2349 PFCB RelatedFcb = NULL;
2350
2351 /* Make sure caller is consistent */
2352 if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
2353 (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
2354 {
2355 DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2356 return STATUS_INVALID_PARAMETER;
2357 }
2358
2359 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2360 Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2361 Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2362 DPRINT("FileName: %wZ\n", &FileObject->FileName);
2363
2364 if (FileObject->RelatedFileObject != NULL)
2365 {
2366 RelatedFcb = FileObject->RelatedFileObject->FsContext;
2367 DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2368 }
2369
2370 /* Going to rename? */
2371 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
2372 {
2373 DPRINT("TargetDir!\n");
2374 }
2375
2376 /* Copy create parameters to the context */
2377 RxCopyCreateParameters(Context);
2378
2379 /* If the caller wants to establish a connection, go ahead */
2380 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2381 {
2382 Status = RxCreateTreeConnect(Context);
2383 }
2384 else
2385 {
2386 /* Validate file name */
2387 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2388 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2389 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2390 {
2391 FileObject->FileName.Length -= sizeof(WCHAR);
2392 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2393 FileObject->FileName.Length);
2394
2395 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2396 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2397 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2398 {
2399 return STATUS_OBJECT_NAME_INVALID;
2400 }
2401 }
2402
2403 /* Attempt to open the file */
2404 do
2405 {
2406 UNICODE_STRING NetRootName;
2407
2408 /* Strip last \ if required */
2409 if (FileObject->FileName.Length != 0 &&
2410 FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2411 {
2412 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2413 {
2414 return STATUS_OBJECT_NAME_INVALID;
2415 }
2416
2417 FileObject->FileName.Length -= sizeof(WCHAR);
2418 Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
2419 }
2420
2421 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
2422 {
2423 FileObject->Flags |= FO_WRITE_THROUGH;
2424 }
2425
2426 /* Get the associated net root to opening */
2427 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2428 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2429 {
2430 break;
2431 }
2432
2433 /* And attempt to open */
2434 Status = RxCreateFromNetRoot(Context, &NetRootName);
2435 if (Status == STATUS_SHARING_VIOLATION)
2436 {
2437 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2438
2439 /* If that happens for file creation, fail for real */
2440 if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
2441 {
2442 Status = STATUS_OBJECT_NAME_COLLISION;
2443 }
2444 else
2445 {
2446 /* Otherwise, if possible, attempt to scavenger current FOBX
2447 * to check whether a dormant FOBX is the reason for sharing violation
2448 */
2449 if (Context->Create.TryForScavengingOnSharingViolation &&
2450 !Context->Create.ScavengingAlreadyTried)
2451 {
2452 /* Only doable with a VNetRoot */
2453 if (Context->Create.pVNetRoot != NULL)
2454 {
2455 PV_NET_ROOT VNetRoot;
2456 NT_CREATE_PARAMETERS SavedParameters;
2457
2458 /* Save create parameters */
2459 RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
2460
2461 /* Reference the VNetRoot for the scavenging time */
2462 VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
2463 RxReferenceVNetRoot(VNetRoot);
2464
2465 /* Prepare the RX_CONTEXT for reuse */
2466 RxpPrepareCreateContextForReuse(Context);
2467 RxReinitializeContext(Context);
2468
2469 /* Copy what we saved */
2470 RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
2471
2472 /* And recopy what can be */
2473 RxCopyCreateParameters(Context);
2474
2475 /* And start purging, then scavenging FOBX */
2476 RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
2477 DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
2478 RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
2479 NULL, TRUE);
2480
2481 /* Ask for a second round */
2482 Status = STATUS_MORE_PROCESSING_REQUIRED;
2483
2484 /* Keep track we already scavenged */
2485 Context->Create.ScavengingAlreadyTried = TRUE;
2486
2487 /* Reference our SRV_CALL for CBS handling */
2488 RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
2489 RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
2490
2491 /* Drop our extra reference */
2492 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2493 }
2494 }
2495 }
2496 }
2497 else if (Status == STATUS_REPARSE)
2498 {
2499 Context->CurrentIrp->IoStatus.Information = 0;
2500 }
2501 else
2502 {
2503 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2504 }
2505 }
2506 while (Status == STATUS_MORE_PROCESSING_REQUIRED);
2507 }
2508
2509 if (Status == STATUS_RETRY)
2510 {
2511 RxpPrepareCreateContextForReuse(Context);
2512 }
2513 ASSERT(Status != STATUS_PENDING);
2514 }
2515
2516 DPRINT("Status: %lx\n", Status);
2517 return Status;
2518 }
2519
2520 /*
2521 * @implemented
2522 */
2523 NTSTATUS
2524 NTAPI
2525 RxCommonDevFCBCleanup(
2526 PRX_CONTEXT Context)
2527 {
2528 PMRX_FCB Fcb;
2529 NTSTATUS Status;
2530
2531 PAGED_CODE();
2532
2533 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2534
2535 Fcb = Context->pFcb;
2536 Status = STATUS_SUCCESS;
2537 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2538
2539 /* Our FOBX if set, has to be a VNetRoot */
2540 if (Context->pFobx != NULL)
2541 {
2542 RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2543 if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2544 {
2545 Status = STATUS_INVALID_DEVICE_REQUEST;
2546 }
2547 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2548 }
2549 else
2550 {
2551 --Fcb->UncleanCount;
2552 }
2553
2554 return Status;
2555 }
2556
2557 /*
2558 * @implemented
2559 */
2560 NTSTATUS
2561 NTAPI
2562 RxCommonDevFCBClose(
2563 PRX_CONTEXT Context)
2564 {
2565 PMRX_FCB Fcb;
2566 NTSTATUS Status;
2567 PMRX_V_NET_ROOT NetRoot;
2568
2569 PAGED_CODE();
2570
2571 DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2572
2573 Fcb = Context->pFcb;
2574 NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2575 Status = STATUS_SUCCESS;
2576 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2577
2578 /* Our FOBX if set, has to be a VNetRoot */
2579 if (NetRoot != NULL)
2580 {
2581 RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2582 if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2583 {
2584 --NetRoot->NumberOfOpens;
2585 RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2586 }
2587 else
2588 {
2589 Status = STATUS_NOT_IMPLEMENTED;
2590 }
2591 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2592 }
2593 else
2594 {
2595 --Fcb->OpenCount;
2596 }
2597
2598 return Status;
2599 }
2600
2601 NTSTATUS
2602 NTAPI
2603 RxCommonDevFCBFsCtl(
2604 PRX_CONTEXT Context)
2605 {
2606 UNIMPLEMENTED;
2607 return STATUS_NOT_IMPLEMENTED;
2608 }
2609
2610 /*
2611 * @implemented
2612 */
2613 NTSTATUS
2614 NTAPI
2615 RxCommonDevFCBIoCtl(
2616 PRX_CONTEXT Context)
2617 {
2618 NTSTATUS Status;
2619
2620 PAGED_CODE();
2621
2622 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2623
2624 if (Context->pFobx != NULL)
2625 {
2626 return STATUS_INVALID_HANDLE;
2627 }
2628
2629 /* Is that a prefix claim from MUP? */
2630 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2631 {
2632 return RxPrefixClaim(Context);
2633 }
2634
2635 /* Otherwise, pass through the mini-rdr */
2636 Status = RxXXXControlFileCallthru(Context);
2637 if (Status != STATUS_PENDING)
2638 {
2639 if (Context->PostRequest)
2640 {
2641 Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2642 Status = RxFsdPostRequest(Context);
2643 }
2644 }
2645
2646 DPRINT("Status: %lx\n", Status);
2647 return Status;
2648 }
2649
2650 NTSTATUS
2651 NTAPI
2652 RxCommonDevFCBQueryVolInfo(
2653 PRX_CONTEXT Context)
2654 {
2655 UNIMPLEMENTED;
2656 return STATUS_NOT_IMPLEMENTED;
2657 }
2658
2659 /*
2660 * @implemented
2661 */
2662 NTSTATUS
2663 NTAPI
2664 RxCommonDeviceControl(
2665 PRX_CONTEXT Context)
2666 {
2667 NTSTATUS Status;
2668
2669 PAGED_CODE();
2670
2671 /* Prefix claim is only allowed for device, not files */
2672 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2673 {
2674 return STATUS_INVALID_DEVICE_REQUEST;
2675 }
2676
2677 /* Submit to mini-rdr */
2678 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
2679 Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
2680 if (Status == STATUS_PENDING)
2681 {
2682 RxDereferenceAndDeleteRxContext_Real(Context);
2683 }
2684
2685 return Status;
2686 }
2687
2688 /*
2689 * @implemented
2690 */
2691 NTSTATUS
2692 NTAPI
2693 RxCommonDirectoryControl(
2694 PRX_CONTEXT Context)
2695 {
2696 PFCB Fcb;
2697 PFOBX Fobx;
2698 NTSTATUS Status;
2699 PIO_STACK_LOCATION Stack;
2700
2701 PAGED_CODE();
2702
2703 Fcb = (PFCB)Context->pFcb;
2704 Fobx = (PFOBX)Context->pFobx;
2705 Stack = Context->CurrentIrpSp;
2706 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2707
2708 /* Call the appropriate helper */
2709 if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2710 {
2711 Status = RxQueryDirectory(Context);
2712 }
2713 else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2714 {
2715 Status = RxNotifyChangeDirectory(Context);
2716 if (Status == STATUS_PENDING)
2717 {
2718 RxDereferenceAndDeleteRxContext_Real(Context);
2719 }
2720 }
2721 else
2722 {
2723 Status = STATUS_INVALID_DEVICE_REQUEST;
2724 }
2725
2726 return Status;
2727 }
2728
2729 NTSTATUS
2730 NTAPI
2731 RxCommonDispatchProblem(
2732 PRX_CONTEXT Context)
2733 {
2734 UNIMPLEMENTED;
2735 return STATUS_NOT_IMPLEMENTED;
2736 }
2737
2738 NTSTATUS
2739 NTAPI
2740 RxCommonFileSystemControl(
2741 PRX_CONTEXT Context)
2742 {
2743 PIRP Irp;
2744 ULONG ControlCode;
2745 PIO_STACK_LOCATION Stack;
2746
2747 PAGED_CODE();
2748
2749 Irp = Context->CurrentIrp;
2750 Stack = Context->CurrentIrpSp;
2751 ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
2752
2753 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
2754
2755 UNIMPLEMENTED;
2756 return STATUS_NOT_IMPLEMENTED;
2757 }
2758
2759 NTSTATUS
2760 NTAPI
2761 RxCommonFlushBuffers(
2762 PRX_CONTEXT Context)
2763 {
2764 UNIMPLEMENTED;
2765 return STATUS_NOT_IMPLEMENTED;
2766 }
2767
2768 NTSTATUS
2769 NTAPI
2770 RxCommonLockControl(
2771 PRX_CONTEXT Context)
2772 {
2773 UNIMPLEMENTED;
2774 return STATUS_NOT_IMPLEMENTED;
2775 }
2776
2777 NTSTATUS
2778 NTAPI
2779 RxCommonQueryEa(
2780 PRX_CONTEXT Context)
2781 {
2782 UNIMPLEMENTED;
2783 return STATUS_NOT_IMPLEMENTED;
2784 }
2785
2786 /*
2787 * @implemented
2788 */
2789 NTSTATUS
2790 NTAPI
2791 RxCommonQueryInformation(
2792 PRX_CONTEXT Context)
2793 {
2794 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2795 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2796 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2797
2798 PFCB Fcb;
2799 PIRP Irp;
2800 PFOBX Fobx;
2801 BOOLEAN Locked;
2802 NTSTATUS Status;
2803 PIO_STACK_LOCATION Stack;
2804 FILE_INFORMATION_CLASS FileInfoClass;
2805
2806 PAGED_CODE();
2807
2808 Fcb = (PFCB)Context->pFcb;
2809 Fobx = (PFOBX)Context->pFobx;
2810 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2811
2812 Irp = Context->CurrentIrp;
2813 Stack = Context->CurrentIrpSp;
2814 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2815 Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2816
2817 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2818 FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2819
2820 Locked = FALSE;
2821 _SEH2_TRY
2822 {
2823 PVOID Buffer;
2824
2825 /* Get a writable buffer */
2826 Buffer = RxMapSystemBuffer(Context);
2827 if (Buffer == NULL)
2828 {
2829 Status = STATUS_INSUFFICIENT_RESOURCES;
2830 _SEH2_LEAVE;
2831 }
2832 /* Zero it */
2833 RtlZeroMemory(Buffer, Context->Info.Length);
2834
2835 /* Validate file type */
2836 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
2837 {
2838 if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2839 {
2840 Status = STATUS_INVALID_PARAMETER;
2841 _SEH2_LEAVE;
2842 }
2843 else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
2844 {
2845 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
2846 {
2847 Status = STATUS_NOT_IMPLEMENTED;
2848 }
2849 else
2850 {
2851 Status = STATUS_INVALID_PARAMETER;
2852 }
2853
2854 _SEH2_LEAVE;
2855 }
2856 }
2857
2858 /* Acquire the right lock */
2859 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
2860 FileInfoClass != FileNameInformation)
2861 {
2862 if (FileInfoClass == FileCompressionInformation)
2863 {
2864 Status = RxAcquireExclusiveFcb(Context, Fcb);
2865 }
2866 else
2867 {
2868 Status = RxAcquireSharedFcb(Context, Fcb);
2869 }
2870
2871 if (Status == STATUS_LOCK_NOT_GRANTED)
2872 {
2873 Status = STATUS_PENDING;
2874 _SEH2_LEAVE;
2875 }
2876 else if (!NT_SUCCESS(Status))
2877 {
2878 _SEH2_LEAVE;
2879 }
2880
2881 Locked = TRUE;
2882 }
2883
2884 /* Dispatch to the right helper */
2885 switch (FileInfoClass)
2886 {
2887 case FileBasicInformation:
2888 Status = RxQueryBasicInfo(Context, Buffer);
2889 break;
2890
2891 case FileStandardInformation:
2892 Status = RxQueryStandardInfo(Context, Buffer);
2893 break;
2894
2895 case FileInternalInformation:
2896 Status = RxQueryInternalInfo(Context, Buffer);
2897 break;
2898
2899 case FileEaInformation:
2900 Status = RxQueryEaInfo(Context, Buffer);
2901 break;
2902
2903 case FileNameInformation:
2904 Status = RxQueryNameInfo(Context, Buffer);
2905 break;
2906
2907 case FileAllInformation:
2908 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
2909 if (!NT_SUCCESS(Status))
2910 {
2911 break;
2912 }
2913
2914 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
2915 if (!NT_SUCCESS(Status))
2916 {
2917 break;
2918 }
2919
2920 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2921 sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
2922 if (!NT_SUCCESS(Status))
2923 {
2924 break;
2925 }
2926
2927 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2928 sizeof(FILE_STANDARD_INFORMATION) +
2929 sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
2930 if (!NT_SUCCESS(Status))
2931 {
2932 break;
2933 }
2934
2935 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2936 sizeof(FILE_STANDARD_INFORMATION) +
2937 sizeof(FILE_INTERNAL_INFORMATION) +
2938 sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
2939 if (!NT_SUCCESS(Status))
2940 {
2941 break;
2942 }
2943
2944 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2945 sizeof(FILE_STANDARD_INFORMATION) +
2946 sizeof(FILE_INTERNAL_INFORMATION) +
2947 sizeof(FILE_EA_INFORMATION) +
2948 sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
2949 break;
2950
2951 case FileAlternateNameInformation:
2952 Status = RxQueryAlternateNameInfo(Context, Buffer);
2953 break;
2954
2955 case FilePipeInformation:
2956 case FilePipeLocalInformation:
2957 case FilePipeRemoteInformation:
2958 Status = RxQueryPipeInfo(Context, Buffer);
2959 break;
2960
2961 case FileCompressionInformation:
2962 Status = RxQueryCompressedInfo(Context, Buffer);
2963 break;
2964
2965 default:
2966 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
2967 Status = Context->IoStatusBlock.Status;
2968 break;
2969 }
2970
2971 if (Context->Info.Length < 0)
2972 {
2973 Status = STATUS_BUFFER_OVERFLOW;
2974 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2975 }
2976
2977 Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
2978 }
2979 _SEH2_FINALLY
2980 {
2981 if (Locked)
2982 {
2983 RxReleaseFcb(Context, Fcb);
2984 }
2985 }
2986 _SEH2_END;
2987
2988 DPRINT("Status: %x\n", Status);
2989 return Status;
2990
2991 #undef SET_SIZE_AND_QUERY
2992 }
2993
2994 NTSTATUS
2995 NTAPI
2996 RxCommonQueryQuotaInformation(
2997 PRX_CONTEXT Context)
2998 {
2999 UNIMPLEMENTED;
3000 return STATUS_NOT_IMPLEMENTED;
3001 }
3002
3003 NTSTATUS
3004 NTAPI
3005 RxCommonQuerySecurity(
3006 PRX_CONTEXT Context)
3007 {
3008 UNIMPLEMENTED;
3009 return STATUS_NOT_IMPLEMENTED;
3010 }
3011
3012 /*
3013 * @implemented
3014 */
3015 NTSTATUS
3016 NTAPI
3017 RxCommonQueryVolumeInformation(
3018 PRX_CONTEXT Context)
3019 {
3020 PIRP Irp;
3021 PFCB Fcb;
3022 PFOBX Fobx;
3023 NTSTATUS Status;
3024 PIO_STACK_LOCATION Stack;
3025
3026 PAGED_CODE();
3027
3028 Fcb = (PFCB)Context->pFcb;
3029 Fobx = (PFOBX)Context->pFobx;
3030
3031 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3032
3033 Irp = Context->CurrentIrp;
3034 Stack = Context->CurrentIrpSp;
3035 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
3036 Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
3037
3038 Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
3039 Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
3040 Context->Info.Length = Stack->Parameters.QueryVolume.Length;
3041
3042 /* Forward to mini-rdr */
3043 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
3044
3045 /* Post request if mini-rdr asked to */
3046 if (Context->PostRequest)
3047 {
3048 Status = RxFsdPostRequest(Context);
3049 }
3050 else
3051 {
3052 Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
3053 }
3054
3055 DPRINT("Status: %x\n", Status);
3056 return Status;
3057 }
3058
3059 NTSTATUS
3060 NTAPI
3061 RxCommonRead(
3062 PRX_CONTEXT RxContext)
3063 {
3064 PFCB Fcb;
3065 PIRP Irp;
3066 PFOBX Fobx;
3067 NTSTATUS Status;
3068 PNET_ROOT NetRoot;
3069 PVOID SystemBuffer;
3070 PFILE_OBJECT FileObject;
3071 LARGE_INTEGER ByteOffset;
3072 PIO_STACK_LOCATION Stack;
3073 PLOWIO_CONTEXT LowIoContext;
3074 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3075 ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3076 BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
3077
3078 PAGED_CODE();
3079
3080 Fcb = (PFCB)RxContext->pFcb;
3081 Fobx = (PFOBX)RxContext->pFobx;
3082 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3083
3084 /* Get some parameters */
3085 Irp = RxContext->CurrentIrp;
3086 Stack = RxContext->CurrentIrpSp;
3087 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3088 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3089 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3090 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3091 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3092 ReadLength = Stack->Parameters.Read.Length;
3093 ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
3094 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
3095 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3096
3097 RxItsTheSameContext();
3098
3099 Irp->IoStatus.Information = 0;
3100
3101 /* Should the read be loud - so far, it's just ignored on ReactOS:
3102 * s/DPRINT/DPRINT1/g will make it loud
3103 */
3104 LowIoContext = &RxContext->LowIoContext;
3105 CheckForLoudOperations(RxContext);
3106 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3107 {
3108 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3109 ByteOffset, ReadLength,
3110 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3111 }
3112
3113 RxDeviceObject = RxContext->RxDeviceObject;
3114 /* Update stats */
3115 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3116 {
3117 InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
3118
3119 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
3120 {
3121 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
3122 }
3123 Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
3124
3125 if (PagingIo)
3126 {
3127 ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
3128 }
3129 else if (NoCache)
3130 {
3131 ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
3132 }
3133 else
3134 {
3135 ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
3136 }
3137 }
3138
3139 /* A pagefile cannot be a pipe */
3140 IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
3141 if (IsPipe && PagingIo)
3142 {
3143 return STATUS_INVALID_DEVICE_REQUEST;
3144 }
3145
3146 /* Null-length read is no-op */
3147 if (ReadLength == 0)
3148 {
3149 return STATUS_SUCCESS;
3150 }
3151
3152 /* Validate FCB type */
3153 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
3154 {
3155 return STATUS_INVALID_DEVICE_REQUEST;
3156 }
3157
3158 /* Init the lowio context for possible forward */
3159 RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
3160
3161 PostRequest = FALSE;
3162 ReadCachingDisabled = FALSE;
3163 OwnerSet = FALSE;
3164 ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3165 FileObject = Stack->FileObject;
3166 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3167 _SEH2_TRY
3168 {
3169 LONGLONG FileSize;
3170
3171 /* If no caching, make sure current Cc data have been flushed */
3172 if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
3173 {
3174 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
3175 if (Status == STATUS_LOCK_NOT_GRANTED)
3176 {
3177 PostRequest = TRUE;
3178 _SEH2_LEAVE;
3179 }
3180 else if (Status != STATUS_SUCCESS)
3181 {
3182 _SEH2_LEAVE;
3183 }
3184
3185 ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
3186 CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
3187 RxReleasePagingIoResource(RxContext, Fcb);
3188
3189 if (!NT_SUCCESS(Irp->IoStatus.Status))
3190 {
3191 Status = Irp->IoStatus.Status;
3192 _SEH2_LEAVE;
3193 }
3194
3195 RxAcquirePagingIoResource(RxContext, Fcb);
3196 RxReleasePagingIoResource(RxContext, Fcb);
3197 }
3198
3199 /* Acquire the appropriate lock */
3200 if (PagingIo && !ReadCachingEnabled)
3201 {
3202 ASSERT(!IsPipe);
3203
3204 if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
3205 {
3206 PostRequest = TRUE;
3207 _SEH2_LEAVE;
3208 }
3209
3210 if (!CanWait)
3211 {
3212 LowIoContext->Resource = Fcb->Header.PagingIoResource;
3213 }
3214 }
3215 else
3216 {
3217 if (!ReadCachingEnabled)
3218 {
3219 if (!CanWait && NoCache)
3220 {
3221 Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
3222 if (Status == STATUS_LOCK_NOT_GRANTED)
3223 {
3224 DPRINT1("RdAsyLNG %x\n", RxContext);
3225 PostRequest = TRUE;
3226 _SEH2_LEAVE;
3227 }
3228 if (Status != STATUS_SUCCESS)
3229 {
3230 DPRINT1("RdAsyOthr %x\n", RxContext);
3231 _SEH2_LEAVE;
3232 }
3233
3234 if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3235 {
3236 LowIoContext->Resource = Fcb->Header.Resource;
3237 }
3238 else
3239 {
3240 PostRequest = TRUE;
3241 _SEH2_LEAVE;
3242 }
3243 }
3244 else
3245 {
3246 Status = RxAcquireSharedFcb(RxContext, Fcb);
3247 if (Status == STATUS_LOCK_NOT_GRANTED)
3248 {
3249 PostRequest = TRUE;
3250 _SEH2_LEAVE;
3251 }
3252 else if (Status != STATUS_SUCCESS)
3253 {
3254 _SEH2_LEAVE;
3255 }
3256 }
3257 }
3258 }
3259
3260 RxItsTheSameContext();
3261
3262 ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3263 if (IsPipe)
3264 {
3265 UNIMPLEMENTED;
3266 }
3267
3268 RxGetFileSizeWithLock(Fcb, &FileSize);
3269
3270 /* Make sure FLOCK doesn't conflict */
3271 if (!PagingIo)
3272 {
3273 if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
3274 {
3275 Status = STATUS_FILE_LOCK_CONFLICT;
3276 _SEH2_LEAVE;
3277 }
3278 }
3279
3280 /* Validate byteoffset vs length */
3281 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
3282 {
3283 if (ByteOffset.QuadPart >= FileSize)
3284 {
3285 Status = STATUS_END_OF_FILE;
3286 _SEH2_LEAVE;
3287 }
3288
3289 if (ReadLength > FileSize - ByteOffset.QuadPart)
3290 {
3291 ReadLength = FileSize - ByteOffset.QuadPart;
3292 }
3293 }
3294
3295 /* Read with Cc! */
3296 if (!PagingIo && !NoCache && ReadCachingEnabled &&
3297 !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
3298 {
3299 /* File was not cached yet, do it */
3300 if (FileObject->PrivateCacheMap == NULL)
3301 {
3302 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
3303 {
3304 Status = STATUS_FILE_CLOSED;
3305 _SEH2_LEAVE;
3306 }
3307
3308 RxAdjustAllocationSizeforCC(Fcb);
3309
3310 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
3311 FALSE, &RxData.CacheManagerCallbacks, Fcb);
3312
3313 if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
3314 {
3315 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3316 }
3317 else
3318 {
3319 CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
3320 SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3321 }
3322
3323 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3324 }
3325
3326 /* This should never happen - fix your RDR */
3327 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3328 {
3329 ASSERT(FALSE);
3330 ASSERT(CanWait);
3331
3332 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3333 Status = Irp->IoStatus.Status;
3334 ASSERT(NT_SUCCESS(Status));
3335 }
3336 else
3337 {
3338 /* Map buffer */
3339 SystemBuffer = RxNewMapUserBuffer(RxContext);
3340 if (SystemBuffer == NULL)
3341 {
3342 Status = STATUS_INSUFFICIENT_RESOURCES;
3343 _SEH2_LEAVE;
3344 }
3345
3346 SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3347
3348 RxItsTheSameContext();
3349
3350 /* Perform the read */
3351 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3352 {
3353 if (!ReadCachingEnabled)
3354 {
3355 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3356 }
3357
3358 RxItsTheSameContext();
3359
3360 PostRequest = TRUE;
3361 _SEH2_LEAVE;
3362 }
3363
3364 if (!ReadCachingEnabled)
3365 {
3366 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3367 }
3368
3369 Status = Irp->IoStatus.Status;
3370 ASSERT(NT_SUCCESS(Status));
3371 }
3372 }
3373 else
3374 {
3375 /* Validate the reading */
3376 if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3377 ByteOffset.QuadPart >= 4096)
3378 {
3379 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3380 ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3381 }
3382
3383 /* If it's consistent, forward to mini-rdr */
3384 if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3385 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3386 {
3387 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3388 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3389
3390 RxItsTheSameContext();
3391
3392 if (InFsp && ReadCachingDisabled)
3393 {
3394 ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3395 (PVOID)((ULONG_PTR)RxContext | 3));
3396 OwnerSet = TRUE;
3397 }
3398
3399 Status = RxLowIoReadShell(RxContext);
3400
3401 RxItsTheSameContext();
3402 }
3403 else
3404 {
3405 if (ByteOffset.QuadPart > FileSize)
3406 {
3407 ReadLength = 0;
3408 Irp->IoStatus.Information = ReadLength;
3409 _SEH2_LEAVE;
3410 }
3411
3412 if (ByteOffset.QuadPart + ReadLength > FileSize)
3413 {
3414 ReadLength = FileSize - ByteOffset.QuadPart;
3415 }
3416
3417 SystemBuffer = RxNewMapUserBuffer(RxContext);
3418 RtlZeroMemory(SystemBuffer, ReadLength);
3419 Irp->IoStatus.Information = ReadLength;
3420 }
3421 }
3422 }
3423 _SEH2_FINALLY
3424 {
3425 RxItsTheSameContext();
3426
3427 /* Post if required */
3428 if (PostRequest)
3429 {
3430 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3431 Status = RxFsdPostRequest(RxContext);
3432 }
3433 else
3434 {
3435 /* Update FO in case of sync IO */
3436 if (!IsPipe && !PagingIo)
3437 {
3438 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
3439 {
3440 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
3441 }
3442 }
3443 }
3444
3445 /* Set FastIo if read was a success */
3446 if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
3447 {
3448 if (!IsPipe && !PagingIo)
3449 {
3450 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
3451 }
3452 }
3453
3454 /* In case we're done (not expected any further processing */
3455 if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
3456 {
3457 /* Release everything that can be */
3458 if (ReadCachingDisabled)
3459 {
3460 if (PagingIo)
3461 {
3462 if (OwnerSet)
3463 {
3464 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3465 }
3466 else
3467 {
3468 RxReleasePagingIoResource(RxContext, Fcb);
3469 }
3470 }
3471 else
3472 {
3473 if (OwnerSet)
3474 {
3475 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3476 }
3477 else
3478 {
3479 RxReleaseFcb(RxContext, Fcb);
3480 }
3481 }
3482 }
3483
3484 /* Dereference/Delete context */
3485 if (PostRequest)
3486 {
3487 RxDereferenceAndDeleteRxContext(RxContext);
3488 }
3489 else
3490 {
3491 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
3492 {
3493 RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
3494 }
3495 }
3496
3497 /* We cannot return more than asked */
3498 if (Status == STATUS_SUCCESS)
3499 {
3500 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
3501 }
3502 }
3503 else
3504 {
3505 ASSERT(!Sync);
3506
3507 RxDereferenceAndDeleteRxContext(RxContext);
3508 }
3509 }
3510 _SEH2_END;
3511
3512 return Status;
3513 }
3514
3515 NTSTATUS
3516 NTAPI
3517 RxCommonSetEa(
3518 PRX_CONTEXT Context)
3519 {
3520 UNIMPLEMENTED;
3521 return STATUS_NOT_IMPLEMENTED;
3522 }
3523
3524 /*
3525 * @implemented
3526 */
3527 NTSTATUS
3528 NTAPI
3529 RxCommonSetInformation(
3530 PRX_CONTEXT Context)
3531 {
3532 PIRP Irp;
3533 PFCB Fcb;
3534 PFOBX Fobx;
3535 NTSTATUS Status;
3536 PNET_ROOT NetRoot;
3537 PIO_STACK_LOCATION Stack;
3538 FILE_INFORMATION_CLASS Class;
3539 BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
3540
3541 PAGED_CODE();
3542
3543 Fcb = (PFCB)Context->pFcb;
3544 Fobx = (PFOBX)Context->pFobx;
3545 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3546
3547 Irp = Context->CurrentIrp;
3548 Stack = Context->CurrentIrpSp;
3549 Class = Stack->Parameters.SetFile.FileInformationClass;
3550 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3551 Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
3552 Class, Stack->Parameters.SetFile.ReplaceIfExists);
3553
3554 Status = STATUS_SUCCESS;
3555 CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
3556 FcbTableAcquired = FALSE;
3557 FcbAcquired = FALSE;
3558 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3559
3560 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3561
3562 _SEH2_TRY
3563 {
3564 /* Valide the node type first */
3565 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
3566 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
3567 {
3568 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
3569 {
3570 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3571 {
3572 Status = STATUS_SUCCESS;
3573 }
3574 }
3575 else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
3576 {
3577 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
3578 {
3579 _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
3580 }
3581 else
3582 {
3583 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
3584 _SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER);
3585 }
3586 }
3587 }
3588
3589 /* We don't autorize advance operation */
3590 if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
3591 {
3592 DPRINT1("Not allowed\n");
3593
3594 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3595 }
3596
3597 /* For these to classes, we'll have to deal with the FCB table (removal)
3598 * We thus need the exclusive FCB table lock
3599 */
3600 if (Class == FileDispositionInformation || Class == FileRenameInformation)
3601 {
3602 RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
3603 RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
3604
3605 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
3606 {
3607 Context->PostRequest = TRUE;
3608 _SEH2_TRY_RETURN(Status = STATUS_PENDING);
3609 }
3610
3611 FcbTableAcquired = TRUE;
3612 }
3613
3614 /* Finally, if not paging file, we need exclusive FCB lock */
3615 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3616 {
3617 Status = RxAcquireExclusiveFcb(Context, Fcb);
3618 if (Status == STATUS_LOCK_NOT_GRANTED)
3619 {
3620 Context->PostRequest = TRUE;
3621 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3622 }
3623 else if (Status != STATUS_SUCCESS)
3624 {
3625 _SEH2_LEAVE;
3626 }
3627
3628 FcbAcquired = TRUE;
3629 }
3630
3631 Status = STATUS_SUCCESS;
3632
3633 /* And now, perform the job! */
3634 switch (Class)
3635 {
3636 case FileBasicInformation:
3637 Status = RxSetBasicInfo(Context);
3638 break;
3639
3640 case FileDispositionInformation:
3641 {
3642 PFILE_DISPOSITION_INFORMATION FDI;
3643
3644 /* Check whether user wants deletion */
3645 FDI = Irp->AssociatedIrp.SystemBuffer;
3646 if (FDI->DeleteFile)
3647 {
3648 /* If so, check whether it's doable */
3649 if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
3650 {
3651 Status = STATUS_CANNOT_DELETE;
3652 }
3653
3654 /* And if doable, already remove from FCB table */
3655 if (Status == STATUS_SUCCESS)
3656 {
3657 ASSERT(FcbAcquired && FcbTableAcquired);
3658 RxRemoveNameNetFcb(Fcb);
3659
3660 RxReleaseFcbTableLock(&NetRoot->FcbTable);
3661 FcbTableAcquired = FALSE;
3662 }
3663 }
3664
3665 /* If it succeed, perform the operation */
3666 if (Status == STATUS_SUCCESS)
3667 {
3668 Status = RxSetDispositionInfo(Context);
3669 }
3670
3671 break;
3672 }
3673
3674 case FilePositionInformation:
3675 Status = RxSetPositionInfo(Context);
3676 break;
3677
3678 case FileAllocationInformation:
3679 Status = RxSetAllocationInfo(Context);
3680 break;
3681
3682 case FileEndOfFileInformation:
3683 Status = RxSetEndOfFileInfo(Context);
3684 break;
3685
3686 case FilePipeInformation:
3687 case FilePipeLocalInformation:
3688 case FilePipeRemoteInformation:
3689 Status = RxSetPipeInfo(Context);
3690 break;
3691
3692 case FileRenameInformation:
3693 case FileLinkInformation:
3694 case FileMoveClusterInformation:
3695 /* If we can wait, try to perform the operation right now */
3696 if (CanWait)
3697 {
3698 /* Of course, collapsing is not doable anymore, file is
3699 * in an inbetween state
3700 */
3701 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
3702
3703 /* Set the information */
3704 Status = RxSetRenameInfo(Context);
3705 /* If it succeed, drop the current entry from FCB table */
3706 if (Status == STATUS_SUCCESS && Class == FileRenameInformation)
3707 {
3708 ASSERT(FcbAcquired && FcbTableAcquired);
3709 RxRemoveNameNetFcb(Fcb);
3710 }
3711 _SEH2_TRY_RETURN(Status);
3712 }
3713 /* Can't wait? Post for async retry */
3714 else
3715 {
3716 Status = RxFsdPostRequest(Context);
3717 _SEH2_TRY_RETURN(Status);
3718 }
3719 break;
3720
3721 case FileValidDataLengthInformation:
3722 if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL))
3723 {
3724 Status = STATUS_USER_MAPPED_FILE;
3725 }
3726 break;
3727
3728 case FileShortNameInformation:
3729 Status = RxSetSimpleInfo(Context);
3730 break;
3731
3732 default:
3733 DPRINT1("Insupported class: %x\n", Class);
3734 Status = STATUS_INVALID_PARAMETER;
3735
3736 break;
3737 }
3738
3739 try_exit: NOTHING;
3740 /* If mini-rdr was OK and wants a re-post on this, do it */
3741 if (Status == STATUS_SUCCESS)
3742 {
3743 if (Context->PostRequest)
3744 {
3745 Status = RxFsdPostRequest(Context);
3746 }
3747 }
3748 }
3749 _SEH2_FINALLY
3750 {
3751 /* Release any acquired lock */
3752 if (FcbAcquired)
3753 {
3754 RxReleaseFcb(Context, Fcb);
3755 }
3756
3757 if (FcbTableAcquired)
3758 {
3759 RxReleaseFcbTableLock(&NetRoot->FcbTable);
3760 }
3761 }
3762 _SEH2_END;
3763
3764 #undef _SEH2_TRY_RETURN
3765
3766 return Status;
3767 }
3768
3769 NTSTATUS
3770 NTAPI
3771 RxCommonSetQuotaInformation(
3772 PRX_CONTEXT Context)
3773 {
3774 UNIMPLEMENTED;
3775 return STATUS_NOT_IMPLEMENTED;
3776 }
3777
3778 NTSTATUS
3779 NTAPI
3780 RxCommonSetSecurity(
3781 PRX_CONTEXT Context)
3782 {
3783 UNIMPLEMENTED;
3784 return STATUS_NOT_IMPLEMENTED;
3785 }
3786
3787 NTSTATUS
3788 NTAPI
3789 RxCommonSetVolumeInformation(
3790 PRX_CONTEXT Context)
3791 {
3792 UNIMPLEMENTED;
3793 return STATUS_NOT_IMPLEMENTED;
3794 }
3795
3796 NTSTATUS
3797 NTAPI
3798 RxCommonUnimplemented(
3799 PRX_CONTEXT Context)
3800 {
3801 UNIMPLEMENTED;
3802 return STATUS_NOT_IMPLEMENTED;
3803 }
3804
3805 NTSTATUS
3806 NTAPI
3807 RxCommonWrite(
3808 PRX_CONTEXT RxContext)
3809 {
3810 PIRP Irp;
3811 PFCB Fcb;
3812 PFOBX Fobx;
3813 NTSTATUS Status;
3814 PNET_ROOT NetRoot;
3815 PSRV_OPEN SrvOpen;
3816 PFILE_OBJECT FileObject;
3817 PIO_STACK_LOCATION Stack;
3818 LARGE_INTEGER ByteOffset;
3819 NODE_TYPE_CODE NodeTypeCode;
3820 PLOWIO_CONTEXT LowIoContext;
3821 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3822 ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3823 LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
3824 BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
3825
3826 PAGED_CODE();
3827
3828 Fcb = (PFCB)RxContext->pFcb;
3829 NodeTypeCode = NodeType(Fcb);
3830 /* Validate FCB type */
3831 if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
3832 NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
3833 {
3834 return STATUS_INVALID_DEVICE_REQUEST;
3835 }
3836
3837 /* We'll write to file, keep track of it */
3838 Fcb->IsFileWritten = TRUE;
3839
3840 Stack = RxContext->CurrentIrpSp;
3841 /* Set write through if asked */
3842 if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
3843 {
3844 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
3845 }
3846
3847 Fobx = (PFOBX)RxContext->pFobx;
3848 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3849
3850 /* Get some parameters */
3851 Irp = RxContext->CurrentIrp;
3852 NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
3853 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3854 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3855 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3856 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3857 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3858 WriteLength = Stack->Parameters.Write.Length;
3859 ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
3860 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
3861 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3862
3863 RxItsTheSameContext();
3864
3865 RxContext->FcbResourceAcquired = FALSE;
3866 RxContext->FcbPagingIoResourceAcquired = FALSE;
3867
3868 LowIoContext = &RxContext->LowIoContext;
3869 CheckForLoudOperations(RxContext);
3870 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3871 {
3872 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3873 ByteOffset, WriteLength,
3874 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3875 }
3876
3877 RxDeviceObject = RxContext->RxDeviceObject;
3878 /* Update stats */
3879 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3880 {
3881 InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
3882
3883 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
3884 {
3885 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
3886 }
3887 Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
3888