[DELAYIMP] Fix 2 Clang-Cl warnings about __pfnDliNotifyHook2Default and __pfnDliFailu...
[reactos.git] / 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 RxCaptureFcb;
647
648 PAGED_CODE();
649
650 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
651
652 /* Are loud operations enabled? */
653 if (RxLoudLowIoOpsEnabled)
654 {
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 if (RtlCompareMemory(Add2Ptr(capFcb->PrivateAlreadyPrefixedName.Buffer,
657 (capFcb->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 RxCaptureFcb;
705
706 PAGED_CODE();
707
708 ASSERT(RxContext != NULL);
709 ASSERT(capFcb != NULL);
710
711 /* If FCB resource was acquired, release it */
712 if (RxContext->FcbResourceAcquired)
713 {
714 /* Taking care of owner */
715 if (ResourceOwnerSet)
716 {
717 RxReleaseFcbForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId);
718 }
719 else
720 {
721 RxReleaseFcb(RxContext, capFcb);
722 }
723
724 RxContext->FcbResourceAcquired = FALSE;
725 }
726
727 /* If FCB paging resource was acquired, release it */
728 if (RxContext->FcbPagingIoResourceAcquired)
729 {
730 /* Taking care of owner */
731 if (ResourceOwnerSet)
732 {
733 RxReleasePagingIoResourceForThread(RxContext, capFcb, RxContext->LowIoContext.ResourceThreadId);
734 }
735 else
736 {
737 RxReleasePagingIoResource(RxContext, capFcb);
738 }
739
740 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
741 }
742 }
743
744 /*
745 * @implemented
746 */
747 VOID
748 RxAddToTopLevelIrpAllocatedContextsList(
749 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
750 {
751 KIRQL OldIrql;
752
753 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
754
755 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
756 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
757
758 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
759 InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
760 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
761 }
762
763 /*
764 * @implemented
765 */
766 VOID
767 NTAPI
768 RxAddToWorkque(
769 IN PRX_CONTEXT RxContext,
770 IN PIRP Irp)
771 {
772 ULONG Queued;
773 KIRQL OldIrql;
774 WORK_QUEUE_TYPE Queue;
775
776 RxCaptureParamBlock;
777
778 RxContext->PostRequest = FALSE;
779
780 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
781 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
782 capPARAMS->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
783 {
784 Queue = DelayedWorkQueue;
785 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
786 }
787 else
788 {
789 Queue = CriticalWorkQueue;
790 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
791 }
792
793 /* Check for overflow */
794 if (capPARAMS->FileObject != NULL)
795 {
796 KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
797
798 Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
799 /* In case of an overflow, add the new queued call to the overflow list */
800 if (Queued > 1)
801 {
802 InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
803 InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
804 ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
805
806 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
807 return;
808 }
809
810 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
811 }
812
813 ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
814 ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
815 }
816
817 /*
818 * @implemented
819 */
820 VOID
821 RxAdjustFileTimesAndSize(
822 PRX_CONTEXT RxContext)
823 {
824 NTSTATUS Status;
825 LARGE_INTEGER CurrentTime;
826 FILE_BASIC_INFORMATION FileBasicInfo;
827 FILE_END_OF_FILE_INFORMATION FileEOFInfo;
828 BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
829
830 RxCaptureFcb;
831 RxCaptureFobx;
832 RxCaptureParamBlock;
833 RxCaptureFileObject;
834
835 PAGED_CODE();
836
837 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
838 if (capFileObject->PrivateCacheMap == NULL)
839 {
840 return;
841 }
842
843 /* Get now */
844 KeQuerySystemTime(&CurrentTime);
845
846 /* Was the file modified? */
847 FileModified = BooleanFlagOn(capFileObject->Flags, FO_FILE_MODIFIED);
848 /* We'll set last write if it was modified and user didn't update yet */
849 SetLastWrite = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
850 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
851 SetLastAccess = SetLastWrite ||
852 (BooleanFlagOn(capFileObject->Flags, FO_FILE_FAST_IO_READ) &&
853 !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
854 /* We'll set last change if it was modified and user didn't update yet */
855 SetLastChange = FileModified && !BooleanFlagOn(capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
856
857 /* Nothing to update? Job done */
858 if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
859 {
860 return;
861 }
862
863 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
864 NeedUpdate = FALSE;
865 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
866
867 /* Update lastwrite time if required */
868 if (SetLastWrite)
869 {
870 NeedUpdate = TRUE;
871 capFcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
872 FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
873 }
874
875 /* Update lastaccess time if required */
876 if (SetLastAccess)
877 {
878 NeedUpdate = TRUE;
879 capFcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
880 FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
881 }
882
883 /* Update lastchange time if required */
884 if (SetLastChange)
885 {
886 NeedUpdate = TRUE;
887 capFcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
888 FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
889 }
890
891 /* If one of the date was modified, issue a call to mini-rdr */
892 if (NeedUpdate)
893 {
894 RxContext->Info.FileInformationClass = FileBasicInformation;
895 RxContext->Info.Buffer = &FileBasicInfo;
896 RxContext->Info.Length = sizeof(FileBasicInfo);
897
898 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
899 (void)Status;
900 }
901
902 /* If the file was modified, update its EOF */
903 if (FileModified)
904 {
905 FileEOFInfo.EndOfFile.QuadPart = capFcb->Header.FileSize.QuadPart;
906
907 RxContext->Info.FileInformationClass = FileEndOfFileInformation;
908 RxContext->Info.Buffer = &FileEOFInfo;
909 RxContext->Info.Length = sizeof(FileEOFInfo);
910
911 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxSetFileInfoAtCleanup, (RxContext));
912 (void)Status;
913 }
914 }
915
916 /*
917 * @implemented
918 */
919 NTSTATUS
920 RxAllocateCanonicalNameBuffer(
921 PRX_CONTEXT RxContext,
922 PUNICODE_STRING CanonicalName,
923 USHORT CanonicalLength)
924 {
925 PAGED_CODE();
926
927 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
928
929 /* Context must be free of any already allocated name */
930 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
931
932 /* Validate string length */
933 if (CanonicalLength > USHRT_MAX - 1)
934 {
935 CanonicalName->Buffer = NULL;
936 return STATUS_OBJECT_PATH_INVALID;
937 }
938
939 CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
940 if (CanonicalName->Buffer == NULL)
941 {
942 return STATUS_INSUFFICIENT_RESOURCES;
943 }
944
945 CanonicalName->Length = 0;
946 CanonicalName->MaximumLength = CanonicalLength;
947
948 /* Set the two places - they must always be identical */
949 RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
950 RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
951
952 return STATUS_SUCCESS;
953 }
954
955 /*
956 * @implemented
957 */
958 VOID
959 RxCancelNotifyChangeDirectoryRequestsForFobx(
960 PFOBX Fobx)
961 {
962 KIRQL OldIrql;
963 PLIST_ENTRY Entry;
964 PRX_CONTEXT Context;
965 LIST_ENTRY ContextsToCancel;
966
967 /* Init a list for the contexts to cancel */
968 InitializeListHead(&ContextsToCancel);
969
970 /* Lock our list lock */
971 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
972
973 /* Now, browse all the active contexts, to find the associated ones */
974 Entry = RxActiveContexts.Flink;
975 while (Entry != &RxActiveContexts)
976 {
977 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
978 Entry = Entry->Flink;
979
980 /* Not the IRP we're looking for, ignore */
981 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
982 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
983 {
984 continue;
985 }
986
987 /* Not the FOBX we're looking for, ignore */
988 if ((PFOBX)Context->pFobx != Fobx)
989 {
990 continue;
991 }
992
993 /* No cancel routine (can't be cancel, then), ignore */
994 if (Context->MRxCancelRoutine == NULL)
995 {
996 continue;
997 }
998
999 /* Mark our context as cancelled */
1000 SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1001
1002 /* Move it to our list */
1003 RemoveEntryList(&Context->ContextListEntry);
1004 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1005
1006 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1007 }
1008
1009 /* Done with the contexts */
1010 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1011
1012 /* Now, handle all our "extracted" contexts */
1013 while (!IsListEmpty(&ContextsToCancel))
1014 {
1015 Entry = RemoveHeadList(&ContextsToCancel);
1016 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1017
1018 /* If they had an associated IRP (should be always true) */
1019 if (Context->CurrentIrp != NULL)
1020 {
1021 /* Then, call cancel routine */
1022 ASSERT(Context->MRxCancelRoutine != NULL);
1023 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1024 Context->MRxCancelRoutine(Context);
1025 }
1026
1027 /* And delete the context */
1028 RxDereferenceAndDeleteRxContext(Context);
1029 }
1030 }
1031
1032 /*
1033 * @implemented
1034 */
1035 NTSTATUS
1036 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1037 PV_NET_ROOT VNetRoot,
1038 BOOLEAN ForceFilesClosed)
1039 {
1040 KIRQL OldIrql;
1041 NTSTATUS Status;
1042 PLIST_ENTRY Entry;
1043 PRX_CONTEXT Context;
1044 LIST_ENTRY ContextsToCancel;
1045
1046 /* Init a list for the contexts to cancel */
1047 InitializeListHead(&ContextsToCancel);
1048
1049 /* Lock our list lock */
1050 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1051
1052 /* Assume success */
1053 Status = STATUS_SUCCESS;
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 RxCaptureParamBlock;
1245 RxCaptureFileObject;
1246
1247 PAGED_CODE();
1248
1249 NetRootType = NET_ROOT_WILD;
1250
1251 RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1252 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1253
1254 /* if not relative opening, just handle the passed name */
1255 if (capFileObject->RelatedFileObject == NULL)
1256 {
1257 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1258 if (!NT_SUCCESS(Status))
1259 {
1260 return Status;
1261 }
1262 }
1263 else
1264 {
1265 PFCB Fcb;
1266
1267 /* Make sure we have a valid FCB and a FOBX */
1268 Fcb = capFileObject->RelatedFileObject->FsContext;
1269 if (Fcb == NULL || capFileObject->RelatedFileObject->FsContext2 == NULL)
1270 {
1271 return STATUS_INVALID_PARAMETER;
1272 }
1273
1274 if (!NodeTypeIsFcb(Fcb))
1275 {
1276 return STATUS_INVALID_PARAMETER;
1277 }
1278
1279 UNIMPLEMENTED;
1280 }
1281
1282 /* Get/Create the associated VNetRoot for opening */
1283 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1284 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1285 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
1286 {
1287 ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1288
1289 RxFreeCanonicalNameBuffer(RxContext);
1290 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1291 if (NT_SUCCESS(Status))
1292 {
1293 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1294 }
1295 }
1296
1297 /* Filename cannot contain wildcards */
1298 if (FsRtlDoesNameContainWildCards(NetRootName))
1299 {
1300 Status = STATUS_OBJECT_NAME_INVALID;
1301 }
1302
1303 /* Make sure file name is correct */
1304 if (NT_SUCCESS(Status))
1305 {
1306 Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1307 }
1308
1309 /* Give the mini-redirector a chance to prepare the name */
1310 if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
1311 {
1312 if (RxContext->Create.pNetRoot != NULL)
1313 {
1314 NTSTATUS IgnoredStatus;
1315
1316 MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1317 MRxPreparseName, (RxContext, NetRootName));
1318 (void)IgnoredStatus;
1319 }
1320 }
1321
1322 return Status;
1323 }
1324
1325 /*
1326 * @implemented
1327 */
1328 VOID
1329 NTAPI
1330 RxCheckFcbStructuresForAlignment(
1331 VOID)
1332 {
1333 PAGED_CODE();
1334 }
1335
1336 #if DBG
1337 NTSTATUS
1338 RxCheckShareAccess(
1339 _In_ ACCESS_MASK DesiredAccess,
1340 _In_ ULONG DesiredShareAccess,
1341 _Inout_ PFILE_OBJECT FileObject,
1342 _Inout_ PSHARE_ACCESS ShareAccess,
1343 _In_ BOOLEAN Update,
1344 _In_ PSZ where,
1345 _In_ PSZ wherelogtag)
1346 {
1347 PAGED_CODE();
1348
1349 RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1350 RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1351
1352 return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
1353 }
1354 #endif
1355
1356 /*
1357 * @implemented
1358 */
1359 NTSTATUS
1360 RxCheckShareAccessPerSrvOpens(
1361 IN PFCB Fcb,
1362 IN ACCESS_MASK DesiredAccess,
1363 IN ULONG DesiredShareAccess)
1364 {
1365 BOOLEAN ReadAccess;
1366 BOOLEAN WriteAccess;
1367 BOOLEAN DeleteAccess;
1368 PSHARE_ACCESS ShareAccess;
1369
1370 PAGED_CODE();
1371
1372 ShareAccess = &Fcb->ShareAccessPerSrvOpens;
1373
1374 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1375 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1376
1377 /* Check if any access wanted */
1378 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
1379 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
1380 DeleteAccess = (DesiredAccess & DELETE) != 0;
1381
1382 if (ReadAccess || WriteAccess || DeleteAccess)
1383 {
1384 BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1385 BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1386 BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1387
1388 /* Check whether there's a violation */
1389 if ((ReadAccess &&
1390 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1391 (WriteAccess &&
1392 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1393 (DeleteAccess &&
1394 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1395 ((ShareAccess->Readers != 0) && !SharedRead) ||
1396 ((ShareAccess->Writers != 0) && !SharedWrite) ||
1397 ((ShareAccess->Deleters != 0) && !SharedDelete))
1398 {
1399 return STATUS_SHARING_VIOLATION;
1400 }
1401 }
1402
1403 return STATUS_SUCCESS;
1404 }
1405
1406 VOID
1407 RxCleanupPipeQueues(
1408 PRX_CONTEXT Context)
1409 {
1410 UNIMPLEMENTED;
1411 }
1412
1413 /*
1414 * @implemented
1415 */
1416 NTSTATUS
1417 RxCloseAssociatedSrvOpen(
1418 IN PFOBX Fobx,
1419 IN PRX_CONTEXT RxContext OPTIONAL)
1420 {
1421 PFCB Fcb;
1422 NTSTATUS Status;
1423 PSRV_OPEN SrvOpen;
1424 BOOLEAN CloseSrvOpen;
1425 PRX_CONTEXT LocalContext;
1426
1427 PAGED_CODE();
1428
1429 /* Assume SRV_OPEN is already closed */
1430 CloseSrvOpen = FALSE;
1431 /* If we have a FOBX, we'll have to close it */
1432 if (Fobx != NULL)
1433 {
1434 /* If the FOBX isn't closed yet */
1435 if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1436 {
1437 SrvOpen = Fobx->SrvOpen;
1438 Fcb = (PFCB)SrvOpen->pFcb;
1439 /* Check whether we've to close SRV_OPEN first */
1440 if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1441 {
1442 CloseSrvOpen = TRUE;
1443 }
1444 else
1445 {
1446 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1447
1448 /* Not much to do */
1449 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1450
1451 if (SrvOpen->OpenCount > 0)
1452 {
1453 --SrvOpen->OpenCount;
1454 }
1455 }
1456 }
1457
1458 /* No need to close SRV_OPEN, so close FOBX */
1459 if (!CloseSrvOpen)
1460 {
1461 RxMarkFobxOnClose(Fobx);
1462
1463 return STATUS_SUCCESS;
1464 }
1465 }
1466 else
1467 {
1468 /* No FOBX? No RX_CONTEXT, ok, job done! */
1469 if (RxContext == NULL)
1470 {
1471 return STATUS_SUCCESS;
1472 }
1473
1474 /* Get the FCB from RX_CONTEXT */
1475 Fcb = (PFCB)RxContext->pFcb;
1476 SrvOpen = NULL;
1477 }
1478
1479 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1480 if (RxContext == NULL)
1481 {
1482 ASSERT(Fobx != NULL);
1483
1484 LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
1485 if (LocalContext == NULL)
1486 {
1487 return STATUS_INSUFFICIENT_RESOURCES;
1488 }
1489
1490 LocalContext->MajorFunction = 2;
1491 LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1492 LocalContext->pFobx = (PMRX_FOBX)Fobx;
1493 LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1494 }
1495 else
1496 {
1497 LocalContext = RxContext;
1498 }
1499
1500 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1501
1502 /* Now, close the FOBX */
1503 if (Fobx != NULL)
1504 {
1505 RxMarkFobxOnClose(Fobx);
1506 }
1507 else
1508 {
1509 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1510 }
1511
1512 /* If not a "standard" file, SRV_OPEN can be null */
1513 if (SrvOpen == NULL)
1514 {
1515 ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
1516 RxDereferenceNetFcb(Fcb);
1517
1518 if (LocalContext != RxContext)
1519 {
1520 RxDereferenceAndDeleteRxContext(LocalContext);
1521 }
1522
1523 return STATUS_SUCCESS;
1524 }
1525
1526 /* If SRV_OPEN isn't in a good condition, nothing to close */
1527 if (SrvOpen->Condition != Condition_Good)
1528 {
1529 if (LocalContext != RxContext)
1530 {
1531 RxDereferenceAndDeleteRxContext(LocalContext);
1532 }
1533
1534 return STATUS_SUCCESS;
1535 }
1536
1537 /* Decrease open count */
1538 if (SrvOpen->OpenCount > 0)
1539 {
1540 --SrvOpen->OpenCount;
1541 }
1542
1543 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1544 if (SrvOpen->OpenCount == 1)
1545 {
1546 if (!IsListEmpty(&SrvOpen->FobxList))
1547 {
1548 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1549 {
1550 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1551 }
1552 }
1553 }
1554
1555 /* Nothing left, purge FCB */
1556 if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1557 {
1558 RxPurgeNetFcb(Fcb, LocalContext);
1559 }
1560
1561 /* Already closed? Job done! */
1562 SrvOpen = Fobx->SrvOpen;
1563 if (SrvOpen == NULL ||
1564 (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1565 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1566 {
1567 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1568 if (LocalContext != RxContext)
1569 {
1570 RxDereferenceAndDeleteRxContext(LocalContext);
1571 }
1572
1573 return STATUS_SUCCESS;
1574 }
1575
1576 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1577
1578 /* Inform mini-rdr about closing */
1579 MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1580 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1581 Status, RxContext, Fobx, Fcb, SrvOpen);
1582
1583 /* And mark as such */
1584 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1585 SrvOpen->Key = (PVOID)-1;
1586
1587 /* If we were delayed, we're not! */
1588 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1589 {
1590 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1591 }
1592
1593 /* Clear access */
1594 RxRemoveShareAccessPerSrvOpens(SrvOpen);
1595 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
1596
1597 /* Dereference */
1598 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1599
1600 /* Mark the FOBX closed as well */
1601 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1602
1603 if (LocalContext != RxContext)
1604 {
1605 RxDereferenceAndDeleteRxContext(LocalContext);
1606 }
1607
1608 return Status;
1609 }
1610
1611 /*
1612 * @implemented
1613 */
1614 NTSTATUS
1615 RxCollapseOrCreateSrvOpen(
1616 PRX_CONTEXT RxContext)
1617 {
1618 NTSTATUS Status;
1619 ULONG Disposition;
1620 PSRV_OPEN SrvOpen;
1621 USHORT ShareAccess;
1622 ACCESS_MASK DesiredAccess;
1623 RX_BLOCK_CONDITION FcbCondition;
1624
1625 RxCaptureFcb;
1626 RxCaptureParamBlock;
1627
1628 PAGED_CODE();
1629
1630 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1631
1632 ASSERT(RxIsFcbAcquiredExclusive(capFcb));
1633 ++capFcb->UncleanCount;
1634
1635 DesiredAccess = capPARAMS->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1636 ShareAccess = capPARAMS->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1637
1638 Disposition = RxContext->Create.NtCreateParameters.Disposition;
1639
1640 /* Try to find a reusable SRV_OPEN */
1641 Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
1642 if (Status == STATUS_NOT_FOUND)
1643 {
1644 /* If none found, create one */
1645 SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, capFcb);
1646 if (SrvOpen == NULL)
1647 {
1648 Status = STATUS_INSUFFICIENT_RESOURCES;
1649 }
1650 else
1651 {
1652 SrvOpen->DesiredAccess = DesiredAccess;
1653 SrvOpen->ShareAccess = ShareAccess;
1654 Status = STATUS_SUCCESS;
1655 }
1656
1657 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1658
1659 if (Status != STATUS_SUCCESS)
1660 {
1661 FcbCondition = Condition_Bad;
1662 }
1663 else
1664 {
1665 RxInitiateSrvOpenKeyAssociation(SrvOpen);
1666
1667 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1668 RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1669 /* Inform the mini-rdr we're handling a create */
1670 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCreate, (RxContext));
1671 ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1672
1673 DPRINT("MRxCreate returned: %x\n", Status);
1674 if (Status == STATUS_SUCCESS)
1675 {
1676 /* In case of overwrite, reset file size */
1677 if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
1678 {
1679 RxAcquirePagingIoResource(RxContext, capFcb);
1680 capFcb->Header.AllocationSize.QuadPart = 0LL;
1681 capFcb->Header.FileSize.QuadPart = 0LL;
1682 capFcb->Header.ValidDataLength.QuadPart = 0LL;
1683 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
1684 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
1685 RxReleasePagingIoResource(RxContext, capFcb);
1686 }
1687 else
1688 {
1689 /* Otherwise, adjust sizes */
1690 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &capFcb->NonPaged->SectionObjectPointers;
1691 if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1692 {
1693 RxAdjustAllocationSizeforCC(capFcb);
1694 }
1695 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize);
1696 }
1697 }
1698
1699 /* Set the IoStatus with information returned by mini-rdr */
1700 RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1701
1702 SrvOpen->OpenStatus = Status;
1703 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1704 RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
1705
1706 ASSERT(RxIsFcbAcquiredExclusive(capFcb));
1707
1708 RxCompleteSrvOpenKeyAssociation(SrvOpen);
1709
1710 if (Status == STATUS_SUCCESS)
1711 {
1712 if (BooleanFlagOn(capPARAMS->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1713 {
1714 ClearFlag(capFcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
1715 }
1716 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1717 FcbCondition = Condition_Good;
1718 }
1719 else
1720 {
1721 FcbCondition = Condition_Bad;
1722 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1723 RxContext->pRelevantSrvOpen = NULL;
1724
1725 if (RxContext->pFobx != NULL)
1726 {
1727 RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
1728 RxContext->pFobx = NULL;
1729 }
1730 }
1731 }
1732
1733 /* Set FCB state - good or bad - depending on whether create succeed */
1734 DPRINT("Transitioning FCB %p to condition %lx\n", capFcb, capFcb->Condition);
1735 RxTransitionNetFcb(capFcb, FcbCondition);
1736 }
1737 else if (Status == STATUS_SUCCESS)
1738 {
1739 BOOLEAN IsGood, ExtraOpen;
1740
1741 /* A reusable SRV_OPEN was found */
1742 RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
1743 ExtraOpen = FALSE;
1744
1745 SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1746
1747 IsGood = (SrvOpen->Condition == Condition_Good);
1748 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1749 if (!StableCondition(SrvOpen->Condition))
1750 {
1751 RxReferenceSrvOpen(SrvOpen);
1752 ++SrvOpen->OpenCount;
1753 ExtraOpen = TRUE;
1754
1755 RxReleaseFcb(RxContext, capFcb);
1756 RxContext->Create.FcbAcquired = FALSE;
1757
1758 RxWaitForStableSrvOpen(SrvOpen, RxContext);
1759
1760 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, capFcb)))
1761 {
1762 RxContext->Create.FcbAcquired = TRUE;
1763 }
1764
1765 IsGood = (SrvOpen->Condition == Condition_Good);
1766 }
1767
1768 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1769 if (IsGood)
1770 {
1771 MINIRDR_CALL(Status, RxContext, capFcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1772
1773 ASSERT(RxIsFcbAcquiredExclusive(capFcb));
1774 }
1775 else
1776 {
1777 Status = SrvOpen->OpenStatus;
1778 }
1779
1780 if (ExtraOpen)
1781 {
1782 --SrvOpen->OpenCount;
1783 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1784 }
1785 }
1786
1787 --capFcb->UncleanCount;
1788
1789 DPRINT("Status: %x\n", Status);
1790 return Status;
1791 }
1792
1793 /*
1794 * @implemented
1795 */
1796 NTSTATUS
1797 NTAPI
1798 RxCommonCleanup(
1799 PRX_CONTEXT Context)
1800 {
1801 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1802 PFCB Fcb;
1803 PFOBX Fobx;
1804 ULONG OpenCount;
1805 NTSTATUS Status;
1806 PNET_ROOT NetRoot;
1807 PFILE_OBJECT FileObject;
1808 LARGE_INTEGER TruncateSize;
1809 PLARGE_INTEGER TruncateSizePtr;
1810 BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1811
1812 PAGED_CODE();
1813
1814 Fcb = (PFCB)Context->pFcb;
1815 Fobx = (PFOBX)Context->pFobx;
1816 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1817
1818 /* File system closing, it's OK */
1819 if (Fobx == NULL)
1820 {
1821 if (Fcb->UncleanCount > 0)
1822 {
1823 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1824 }
1825
1826 return STATUS_SUCCESS;
1827 }
1828
1829 /* Check we have a correct FCB type */
1830 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
1831 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
1832 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1833 NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
1834 {
1835 DPRINT1("Invalid Fcb type for %p\n", Fcb);
1836 RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1837 }
1838
1839 FileObject = Context->CurrentIrpSp->FileObject;
1840 ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
1841
1842 RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1843
1844 Status = RxAcquireExclusiveFcb(Context, Fcb);
1845 if (!NT_SUCCESS(Status))
1846 {
1847 return Status;
1848 }
1849
1850 FcbAcquired = TRUE;
1851
1852 Fobx->AssociatedFileObject = NULL;
1853
1854 /* In case it was already orphaned */
1855 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
1856 {
1857 ASSERT(Fcb->UncleanCount != 0);
1858 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1859
1860 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1861 {
1862 --Fcb->UncachedUncleanCount;
1863 }
1864
1865 /* Inform mini-rdr */
1866 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1867
1868 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1869 --Fobx->SrvOpen->UncleanFobxCount;
1870
1871 RxUninitializeCacheMap(Context, FileObject, NULL);
1872
1873 RxReleaseFcb(Context, Fcb);
1874
1875 return STATUS_SUCCESS;
1876 }
1877
1878 /* Report the fact that file could be set as delete on close */
1879 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1880 {
1881 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
1882 }
1883
1884 /* Cancel any pending notification */
1885 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
1886
1887 /* Backup open count before we start playing with it */
1888 OpenCount = Fcb->ShareAccess.OpenCount;
1889
1890 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1891 FcbTableAcquired = FALSE;
1892 LeftForDelete = FALSE;
1893 OneLeft = (Fcb->UncleanCount == 1);
1894
1895 _SEH2_TRY
1896 {
1897 /* Unclean count and delete on close? Verify whether we're the one */
1898 if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
1899 {
1900 if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
1901 {
1902 FcbTableAcquired = TRUE;
1903 }
1904 else
1905 {
1906 RxReleaseFcb(Context, Fcb);
1907
1908 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
1909
1910 Status = RxAcquireExclusiveFcb(Context, Fcb);
1911 if (Status != STATUS_SUCCESS)
1912 {
1913 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1914 return Status;
1915 }
1916
1917 FcbTableAcquired = TRUE;
1918 }
1919
1920 /* That means we'll perform the delete on close! */
1921 if (Fcb->UncleanCount == 1)
1922 {
1923 LeftForDelete = TRUE;
1924 }
1925 else
1926 {
1927 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1928 FcbTableAcquired = FALSE;
1929 }
1930 }
1931
1932 IsFile = FALSE;
1933 TruncateSizePtr = NULL;
1934 /* Handle cleanup for pipes and printers */
1935 if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
1936 {
1937 RxCleanupPipeQueues(Context);
1938 }
1939 /* Handle cleanup for files */
1940 else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
1941 {
1942 Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
1943 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
1944 {
1945 /* First, unlock */
1946 FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
1947
1948 /* If there are still locks to release, proceed */
1949 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
1950 {
1951 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
1952 Context->LowIoContext.ParamsFor.Locks.Flags = 0;
1953 Status = RxLowIoLockControlShell(Context);
1954 }
1955
1956 /* Fix times and size */
1957 RxAdjustFileTimesAndSize(Context);
1958
1959 /* If we're the only one left... */
1960 if (OneLeft)
1961 {
1962 /* And if we're supposed to delete on close */
1963 if (LeftForDelete)
1964 {
1965 /* Update the sizes */
1966 RxAcquirePagingIoResource(Context, Fcb);
1967 Fcb->Header.FileSize.QuadPart = 0;
1968 Fcb->Header.ValidDataLength.QuadPart = 0;
1969 RxReleasePagingIoResource(Context, Fcb);
1970 }
1971 /* Otherwise, call the mini-rdr to adjust sizes */
1972 else
1973 {
1974 /* File got grown up, fill with zeroes */
1975 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
1976 (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
1977 {
1978 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
1979 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1980 }
1981
1982 /* File was truncated, let mini-rdr proceed */
1983 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
1984 {
1985 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
1986 ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
1987
1988 /* Keep track of file change for Cc uninit */
1989 TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
1990 TruncateSizePtr = &TruncateSize;
1991 }
1992 }
1993 }
1994
1995 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1996 if (NeedPurge)
1997 {
1998 if (!OneLeft)
1999 {
2000 NeedPurge = FALSE;
2001 }
2002 }
2003 /* Otherwise, try to see whether we can purge */
2004 else
2005 {
2006 NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
2007 }
2008
2009 IsFile = TRUE;
2010 }
2011 }
2012
2013 /* We have to still be there! */
2014 ASSERT(Fcb->UncleanCount != 0);
2015 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
2016
2017 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2018 {
2019 --Fcb->UncachedUncleanCount;
2020 }
2021
2022 /* Inform mini-rdr about ongoing cleanup */
2023 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
2024
2025 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
2026 --Fobx->SrvOpen->UncleanFobxCount;
2027
2028 /* Flush cache */
2029 if (DisableFlushOnCleanup)
2030 {
2031 /* Only if we're the last standing */
2032 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
2033 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
2034 {
2035 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
2036 RxFlushFcbInSystemCache(Fcb, TRUE);
2037 }
2038 }
2039 else
2040 {
2041 /* Always */
2042 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2043 {
2044 DPRINT("Flushing %p on cleanup\n", Context);
2045 RxFlushFcbInSystemCache(Fcb, TRUE);
2046 }
2047 }
2048
2049 /* If only remaining uncached & unclean, then flush and purge */
2050 if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2051 {
2052 if (Fcb->UncachedUncleanCount != 0)
2053 {
2054 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
2055 Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2056 {
2057 DPRINT("Flushing FCB in system cache for %p\n", Context);
2058 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
2059 }
2060 }
2061 }
2062
2063 /* If purge required, and not about to delete, flush */
2064 if (!LeftForDelete && NeedPurge)
2065 {
2066 DPRINT("Flushing FCB in system cache for %p\n", Context);
2067 RxFlushFcbInSystemCache(Fcb, TRUE);
2068 }
2069
2070 /* If it was a file, drop cache */
2071 if (IsFile)
2072 {
2073 DPRINT("Uninit cache map for file\n");
2074 RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
2075 }
2076
2077 /* If that's the one left for deletion, or if it needs purge, flush */
2078 if (LeftForDelete || NeedPurge)
2079 {
2080 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
2081 /* If that's for deletion, also remove from FCB table */
2082 if (LeftForDelete)
2083 {
2084 RxRemoveNameNetFcb(Fcb);
2085 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2086 FcbTableAcquired = FALSE;
2087 }
2088 }
2089
2090 /* Remove any share access */
2091 if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
2092 {
2093 RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
2094 }
2095
2096 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2097 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
2098 RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
2099 {
2100 NTSTATUS InternalStatus;
2101 PRX_CONTEXT InternalContext;
2102
2103 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2104 InternalStatus = STATUS_UNSUCCESSFUL;
2105 InternalContext = RxCreateRxContext(Context->CurrentIrp,
2106 Fcb->RxDeviceObject,
2107 RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
2108 if (InternalContext != NULL)
2109 {
2110 FILE_END_OF_FILE_INFORMATION FileEOF;
2111
2112 InternalStatus = STATUS_SUCCESS;
2113
2114 /* Initialize the context for file information set */
2115 InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
2116 InternalContext->pFobx = (PMRX_FOBX)Fobx;
2117 InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
2118
2119 /* Get EOF from the FCB */
2120 FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
2121 InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
2122 InternalContext->Info.Buffer = &FileEOF;
2123 InternalContext->Info.Length = sizeof(FileEOF);
2124
2125 /* Call the mini-rdr */
2126 MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
2127
2128 /* We're done */
2129 RxDereferenceAndDeleteRxContext(InternalContext);
2130 }
2131
2132 /* We tried, so, clean the FOBX flag */
2133 ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
2134 /* If it failed, then, disable collapsing on the FCB */
2135 if (!NT_SUCCESS(InternalStatus))
2136 {
2137 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2138 }
2139 }
2140
2141 /* We're clean! */
2142 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
2143
2144 FcbAcquired = FALSE;
2145 RxReleaseFcb(Context, Fcb);
2146 }
2147 _SEH2_FINALLY
2148 {
2149 if (FcbAcquired)
2150 {
2151 RxReleaseFcb(Context, Fcb);
2152 }
2153
2154 if (FcbTableAcquired)
2155 {
2156 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2157 }
2158 }
2159 _SEH2_END;
2160
2161 return Status;
2162 #undef BugCheckFileId
2163 }
2164
2165 NTSTATUS
2166 NTAPI
2167 RxCommonClose(
2168 PRX_CONTEXT Context)
2169 {
2170 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2171 PFCB Fcb;
2172 PFOBX Fobx;
2173 NTSTATUS Status;
2174 PFILE_OBJECT FileObject;
2175 BOOLEAN DereferenceFobx, AcquiredFcb;
2176
2177 PAGED_CODE();
2178
2179 Fcb = (PFCB)Context->pFcb;
2180 Fobx = (PFOBX)Context->pFobx;
2181 FileObject = Context->CurrentIrpSp->FileObject;
2182 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
2183
2184 Status = RxAcquireExclusiveFcb(Context, Fcb);
2185 if (!NT_SUCCESS(Status))
2186 {
2187 return Status;
2188 }
2189
2190 AcquiredFcb = TRUE;
2191 _SEH2_TRY
2192 {
2193 BOOLEAN Freed;
2194
2195 /* Check our FCB type is expected */
2196 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2197 (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
2198 (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
2199 {
2200 RxBugCheck(NodeType(Fcb), 0, 0);
2201 }
2202
2203 RxReferenceNetFcb(Fcb);
2204
2205 DereferenceFobx = FALSE;
2206 /* If we're not closing FS */
2207 if (Fobx != NULL)
2208 {
2209 PSRV_OPEN SrvOpen;
2210 PSRV_CALL SrvCall;
2211
2212 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
2213 SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
2214 /* Handle delayed close */
2215 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2216 {
2217 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
2218 {
2219 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
2220 {
2221 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
2222
2223 if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
2224 {
2225 if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
2226 {
2227 InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
2228 }
2229 else
2230 {
2231 DereferenceFobx = TRUE;
2232 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
2233 }
2234 }
2235 }
2236 }
2237 }
2238
2239 /* If we reach maximum of delayed close/or if there are no delayed close */
2240 if (!DereferenceFobx)
2241 {
2242 PNET_ROOT NetRoot;
2243
2244 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2245 if (NetRoot->Type != NET_ROOT_PRINT)
2246 {
2247 /* Delete if asked */
2248 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
2249 {
2250 RxScavengeRelatedFobxs(Fcb);
2251 RxSynchronizeWithScavenger(Context);
2252
2253 RxReleaseFcb(Context, Fcb);
2254
2255 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2256 RxOrphanThisFcb(Fcb);
2257 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2258
2259 Status = RxAcquireExclusiveFcb(Context, Fcb);
2260 ASSERT(NT_SUCCESS(Status));
2261 }
2262 }
2263 }
2264
2265 RxMarkFobxOnClose(Fobx);
2266 }
2267
2268 if (DereferenceFobx)
2269 {
2270 ASSERT(Fobx != NULL);
2271 RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
2272 }
2273 else
2274 {
2275 RxCloseAssociatedSrvOpen(Fobx, Context);
2276 if (Fobx != NULL)
2277 {
2278 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
2279 }
2280 }
2281
2282 Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
2283 AcquiredFcb = !Freed;
2284
2285 FileObject->FsContext = (PVOID)-1;
2286
2287 if (Freed)
2288 {
2289 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2290 }
2291 else
2292 {
2293 RxReleaseFcb(Context, Fcb);
2294 AcquiredFcb = FALSE;
2295 }
2296 }
2297 _SEH2_FINALLY
2298 {
2299 if (_SEH2_AbnormalTermination())
2300 {
2301 if (AcquiredFcb)
2302 {
2303 RxReleaseFcb(Context, Fcb);
2304 }
2305 }
2306 else
2307 {
2308 ASSERT(!AcquiredFcb);
2309 }
2310 }
2311 _SEH2_END;
2312
2313 DPRINT("Status: %x\n", Status);
2314 return Status;
2315 #undef BugCheckFileId
2316 }
2317
2318 /*
2319 * @implemented
2320 */
2321 NTSTATUS
2322 NTAPI
2323 RxCommonCreate(
2324 PRX_CONTEXT Context)
2325 {
2326 PIRP Irp;
2327 NTSTATUS Status;
2328 PFILE_OBJECT FileObject;
2329 PIO_STACK_LOCATION Stack;
2330
2331 PAGED_CODE();
2332
2333 DPRINT("RxCommonCreate(%p)\n", Context);
2334
2335 Irp = Context->CurrentIrp;
2336 Stack = Context->CurrentIrpSp;
2337 FileObject = Stack->FileObject;
2338
2339 /* Check whether that's a device opening */
2340 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2341 {
2342 FileObject->FsContext = &RxDeviceFCB;
2343 FileObject->FsContext2 = NULL;
2344
2345 ++RxDeviceFCB.NodeReferenceCount;
2346 ++RxDeviceFCB.OpenCount;
2347
2348 Irp->IoStatus.Information = FILE_OPENED;
2349 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2350
2351 Status = STATUS_SUCCESS;
2352 }
2353 else
2354 {
2355 PFCB RelatedFcb = NULL;
2356
2357 /* Make sure caller is consistent */
2358 if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
2359 (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
2360 {
2361 DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2362 return STATUS_INVALID_PARAMETER;
2363 }
2364
2365 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2366 Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2367 Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2368 DPRINT("FileName: %wZ\n", &FileObject->FileName);
2369
2370 if (FileObject->RelatedFileObject != NULL)
2371 {
2372 RelatedFcb = FileObject->RelatedFileObject->FsContext;
2373 DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2374 }
2375
2376 /* Going to rename? */
2377 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
2378 {
2379 DPRINT("TargetDir!\n");
2380 }
2381
2382 /* Copy create parameters to the context */
2383 RxCopyCreateParameters(Context);
2384
2385 /* If the caller wants to establish a connection, go ahead */
2386 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2387 {
2388 Status = RxCreateTreeConnect(Context);
2389 }
2390 else
2391 {
2392 /* Validate file name */
2393 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2394 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2395 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2396 {
2397 FileObject->FileName.Length -= sizeof(WCHAR);
2398 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2399 FileObject->FileName.Length);
2400
2401 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2402 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2403 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2404 {
2405 return STATUS_OBJECT_NAME_INVALID;
2406 }
2407 }
2408
2409 /* Attempt to open the file */
2410 do
2411 {
2412 UNICODE_STRING NetRootName;
2413
2414 /* Strip last \ if required */
2415 if (FileObject->FileName.Length != 0 &&
2416 FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2417 {
2418 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2419 {
2420 return STATUS_OBJECT_NAME_INVALID;
2421 }
2422
2423 FileObject->FileName.Length -= sizeof(WCHAR);
2424 Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
2425 }
2426
2427 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
2428 {
2429 FileObject->Flags |= FO_WRITE_THROUGH;
2430 }
2431
2432 /* Get the associated net root to opening */
2433 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2434 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2435 {
2436 break;
2437 }
2438
2439 /* And attempt to open */
2440 Status = RxCreateFromNetRoot(Context, &NetRootName);
2441 if (Status == STATUS_SHARING_VIOLATION)
2442 {
2443 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2444
2445 /* If that happens for file creation, fail for real */
2446 if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
2447 {
2448 Status = STATUS_OBJECT_NAME_COLLISION;
2449 }
2450 else
2451 {
2452 /* Otherwise, if possible, attempt to scavenger current FOBX
2453 * to check whether a dormant FOBX is the reason for sharing violation
2454 */
2455 if (Context->Create.TryForScavengingOnSharingViolation &&
2456 !Context->Create.ScavengingAlreadyTried)
2457 {
2458 /* Only doable with a VNetRoot */
2459 if (Context->Create.pVNetRoot != NULL)
2460 {
2461 PV_NET_ROOT VNetRoot;
2462 NT_CREATE_PARAMETERS SavedParameters;
2463
2464 /* Save create parameters */
2465 RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
2466
2467 /* Reference the VNetRoot for the scavenging time */
2468 VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
2469 RxReferenceVNetRoot(VNetRoot);
2470
2471 /* Prepare the RX_CONTEXT for reuse */
2472 RxpPrepareCreateContextForReuse(Context);
2473 RxReinitializeContext(Context);
2474
2475 /* Copy what we saved */
2476 RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
2477
2478 /* And recopy what can be */
2479 RxCopyCreateParameters(Context);
2480
2481 /* And start purging, then scavenging FOBX */
2482 RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
2483 DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
2484 RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
2485 NULL, TRUE);
2486
2487 /* Ask for a second round */
2488 Status = STATUS_MORE_PROCESSING_REQUIRED;
2489
2490 /* Keep track we already scavenged */
2491 Context->Create.ScavengingAlreadyTried = TRUE;
2492
2493 /* Reference our SRV_CALL for CBS handling */
2494 RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
2495 RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
2496
2497 /* Drop our extra reference */
2498 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2499 }
2500 }
2501 }
2502 }
2503 else if (Status == STATUS_REPARSE)
2504 {
2505 Context->CurrentIrp->IoStatus.Information = 0;
2506 }
2507 else
2508 {
2509 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2510 }
2511 }
2512 while (Status == STATUS_MORE_PROCESSING_REQUIRED);
2513 }
2514
2515 if (Status == STATUS_RETRY)
2516 {
2517 RxpPrepareCreateContextForReuse(Context);
2518 }
2519 ASSERT(Status != STATUS_PENDING);
2520 }
2521
2522 DPRINT("Status: %lx\n", Status);
2523 return Status;
2524 }
2525
2526 /*
2527 * @implemented
2528 */
2529 NTSTATUS
2530 NTAPI
2531 RxCommonDevFCBCleanup(
2532 PRX_CONTEXT Context)
2533 {
2534 PMRX_FCB Fcb;
2535 NTSTATUS Status;
2536
2537 PAGED_CODE();
2538
2539 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2540
2541 Fcb = Context->pFcb;
2542 Status = STATUS_SUCCESS;
2543 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2544
2545 /* Our FOBX if set, has to be a VNetRoot */
2546 if (Context->pFobx != NULL)
2547 {
2548 RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2549 if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2550 {
2551 Status = STATUS_INVALID_DEVICE_REQUEST;
2552 }
2553 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2554 }
2555 else
2556 {
2557 --Fcb->UncleanCount;
2558 }
2559
2560 return Status;
2561 }
2562
2563 /*
2564 * @implemented
2565 */
2566 NTSTATUS
2567 NTAPI
2568 RxCommonDevFCBClose(
2569 PRX_CONTEXT Context)
2570 {
2571 PMRX_FCB Fcb;
2572 NTSTATUS Status;
2573 PMRX_V_NET_ROOT NetRoot;
2574
2575 PAGED_CODE();
2576
2577 DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2578
2579 Fcb = Context->pFcb;
2580 NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2581 Status = STATUS_SUCCESS;
2582 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2583
2584 /* Our FOBX if set, has to be a VNetRoot */
2585 if (NetRoot != NULL)
2586 {
2587 RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2588 if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2589 {
2590 --NetRoot->NumberOfOpens;
2591 RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2592 }
2593 else
2594 {
2595 Status = STATUS_NOT_IMPLEMENTED;
2596 }
2597 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2598 }
2599 else
2600 {
2601 --Fcb->OpenCount;
2602 }
2603
2604 return Status;
2605 }
2606
2607 NTSTATUS
2608 NTAPI
2609 RxCommonDevFCBFsCtl(
2610 PRX_CONTEXT Context)
2611 {
2612 UNIMPLEMENTED;
2613 return STATUS_NOT_IMPLEMENTED;
2614 }
2615
2616 /*
2617 * @implemented
2618 */
2619 NTSTATUS
2620 NTAPI
2621 RxCommonDevFCBIoCtl(
2622 PRX_CONTEXT Context)
2623 {
2624 NTSTATUS Status;
2625
2626 PAGED_CODE();
2627
2628 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2629
2630 if (Context->pFobx != NULL)
2631 {
2632 return STATUS_INVALID_HANDLE;
2633 }
2634
2635 /* Is that a prefix claim from MUP? */
2636 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2637 {
2638 return RxPrefixClaim(Context);
2639 }
2640
2641 /* Otherwise, pass through the mini-rdr */
2642 Status = RxXXXControlFileCallthru(Context);
2643 if (Status != STATUS_PENDING)
2644 {
2645 if (Context->PostRequest)
2646 {
2647 Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2648 Status = RxFsdPostRequest(Context);
2649 }
2650 }
2651
2652 DPRINT("Status: %lx\n", Status);
2653 return Status;
2654 }
2655
2656 NTSTATUS
2657 NTAPI
2658 RxCommonDevFCBQueryVolInfo(
2659 PRX_CONTEXT Context)
2660 {
2661 UNIMPLEMENTED;
2662 return STATUS_NOT_IMPLEMENTED;
2663 }
2664
2665 /*
2666 * @implemented
2667 */
2668 NTSTATUS
2669 NTAPI
2670 RxCommonDeviceControl(
2671 PRX_CONTEXT Context)
2672 {
2673 NTSTATUS Status;
2674
2675 PAGED_CODE();
2676
2677 /* Prefix claim is only allowed for device, not files */
2678 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2679 {
2680 return STATUS_INVALID_DEVICE_REQUEST;
2681 }
2682
2683 /* Submit to mini-rdr */
2684 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
2685 Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
2686 if (Status == STATUS_PENDING)
2687 {
2688 RxDereferenceAndDeleteRxContext_Real(Context);
2689 }
2690
2691 return Status;
2692 }
2693
2694 /*
2695 * @implemented
2696 */
2697 NTSTATUS
2698 NTAPI
2699 RxCommonDirectoryControl(
2700 PRX_CONTEXT Context)
2701 {
2702 PFCB Fcb;
2703 PFOBX Fobx;
2704 NTSTATUS Status;
2705 PIO_STACK_LOCATION Stack;
2706
2707 PAGED_CODE();
2708
2709 Fcb = (PFCB)Context->pFcb;
2710 Fobx = (PFOBX)Context->pFobx;
2711 Stack = Context->CurrentIrpSp;
2712 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2713
2714 /* Call the appropriate helper */
2715 if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2716 {
2717 Status = RxQueryDirectory(Context);
2718 }
2719 else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2720 {
2721 Status = RxNotifyChangeDirectory(Context);
2722 if (Status == STATUS_PENDING)
2723 {
2724 RxDereferenceAndDeleteRxContext_Real(Context);
2725 }
2726 }
2727 else
2728 {
2729 Status = STATUS_INVALID_DEVICE_REQUEST;
2730 }
2731
2732 return Status;
2733 }
2734
2735 NTSTATUS
2736 NTAPI
2737 RxCommonDispatchProblem(
2738 PRX_CONTEXT Context)
2739 {
2740 UNIMPLEMENTED;
2741 return STATUS_NOT_IMPLEMENTED;
2742 }
2743
2744 NTSTATUS
2745 NTAPI
2746 RxCommonFileSystemControl(
2747 PRX_CONTEXT Context)
2748 {
2749 PIRP Irp;
2750 ULONG ControlCode;
2751 PIO_STACK_LOCATION Stack;
2752
2753 PAGED_CODE();
2754
2755 Irp = Context->CurrentIrp;
2756 Stack = Context->CurrentIrpSp;
2757 ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
2758
2759 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
2760
2761 UNIMPLEMENTED;
2762 return STATUS_NOT_IMPLEMENTED;
2763 }
2764
2765 NTSTATUS
2766 NTAPI
2767 RxCommonFlushBuffers(
2768 PRX_CONTEXT Context)
2769 {
2770 UNIMPLEMENTED;
2771 return STATUS_NOT_IMPLEMENTED;
2772 }
2773
2774 NTSTATUS
2775 NTAPI
2776 RxCommonLockControl(
2777 PRX_CONTEXT Context)
2778 {
2779 UNIMPLEMENTED;
2780 return STATUS_NOT_IMPLEMENTED;
2781 }
2782
2783 NTSTATUS
2784 NTAPI
2785 RxCommonQueryEa(
2786 PRX_CONTEXT Context)
2787 {
2788 UNIMPLEMENTED;
2789 return STATUS_NOT_IMPLEMENTED;
2790 }
2791
2792 /*
2793 * @implemented
2794 */
2795 NTSTATUS
2796 NTAPI
2797 RxCommonQueryInformation(
2798 PRX_CONTEXT Context)
2799 {
2800 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2801 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2802 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2803
2804 PFCB Fcb;
2805 PIRP Irp;
2806 PFOBX Fobx;
2807 BOOLEAN Locked;
2808 NTSTATUS Status;
2809 PIO_STACK_LOCATION Stack;
2810 FILE_INFORMATION_CLASS FileInfoClass;
2811
2812 PAGED_CODE();
2813
2814 Fcb = (PFCB)Context->pFcb;
2815 Fobx = (PFOBX)Context->pFobx;
2816 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2817
2818 Irp = Context->CurrentIrp;
2819 Stack = Context->CurrentIrpSp;
2820 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2821 Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2822
2823 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2824 FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2825
2826 Locked = FALSE;
2827 _SEH2_TRY
2828 {
2829 PVOID Buffer;
2830
2831 /* Get a writable buffer */
2832 Buffer = RxMapSystemBuffer(Context);
2833 if (Buffer == NULL)
2834 {
2835 Status = STATUS_INSUFFICIENT_RESOURCES;
2836 _SEH2_LEAVE;
2837 }
2838 /* Zero it */
2839 RtlZeroMemory(Buffer, Context->Info.Length);
2840
2841 /* Validate file type */
2842 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
2843 {
2844 if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2845 {
2846 Status = STATUS_INVALID_PARAMETER;
2847 _SEH2_LEAVE;
2848 }
2849 else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
2850 {
2851 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
2852 {
2853 Status = STATUS_NOT_IMPLEMENTED;
2854 }
2855 else
2856 {
2857 Status = STATUS_INVALID_PARAMETER;
2858 }
2859
2860 _SEH2_LEAVE;
2861 }
2862 }
2863
2864 /* Acquire the right lock */
2865 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
2866 FileInfoClass != FileNameInformation)
2867 {
2868 if (FileInfoClass == FileCompressionInformation)
2869 {
2870 Status = RxAcquireExclusiveFcb(Context, Fcb);
2871 }
2872 else
2873 {
2874 Status = RxAcquireSharedFcb(Context, Fcb);
2875 }
2876
2877 if (Status == STATUS_LOCK_NOT_GRANTED)
2878 {
2879 Status = STATUS_PENDING;
2880 _SEH2_LEAVE;
2881 }
2882 else if (!NT_SUCCESS(Status))
2883 {
2884 _SEH2_LEAVE;
2885 }
2886
2887 Locked = TRUE;
2888 }
2889
2890 /* Dispatch to the right helper */
2891 switch (FileInfoClass)
2892 {
2893 case FileBasicInformation:
2894 Status = RxQueryBasicInfo(Context, Buffer);
2895 break;
2896
2897 case FileStandardInformation:
2898 Status = RxQueryStandardInfo(Context, Buffer);
2899 break;
2900
2901 case FileInternalInformation:
2902 Status = RxQueryInternalInfo(Context, Buffer);
2903 break;
2904
2905 case FileEaInformation:
2906 Status = RxQueryEaInfo(Context, Buffer);
2907 break;
2908
2909 case FileNameInformation:
2910 Status = RxQueryNameInfo(Context, Buffer);
2911 break;
2912
2913 case FileAllInformation:
2914 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
2915 if (!NT_SUCCESS(Status))
2916 {
2917 break;
2918 }
2919
2920 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
2921 if (!NT_SUCCESS(Status))
2922 {
2923 break;
2924 }
2925
2926 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2927 sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
2928 if (!NT_SUCCESS(Status))
2929 {
2930 break;
2931 }
2932
2933 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2934 sizeof(FILE_STANDARD_INFORMATION) +
2935 sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
2936 if (!NT_SUCCESS(Status))
2937 {
2938 break;
2939 }
2940
2941 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2942 sizeof(FILE_STANDARD_INFORMATION) +
2943 sizeof(FILE_INTERNAL_INFORMATION) +
2944 sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
2945 if (!NT_SUCCESS(Status))
2946 {
2947 break;
2948 }
2949
2950 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2951 sizeof(FILE_STANDARD_INFORMATION) +
2952 sizeof(FILE_INTERNAL_INFORMATION) +
2953 sizeof(FILE_EA_INFORMATION) +
2954 sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
2955 break;
2956
2957 case FileAlternateNameInformation:
2958 Status = RxQueryAlternateNameInfo(Context, Buffer);
2959 break;
2960
2961 case FilePipeInformation:
2962 case FilePipeLocalInformation:
2963 case FilePipeRemoteInformation:
2964 Status = RxQueryPipeInfo(Context, Buffer);
2965 break;
2966
2967 case FileCompressionInformation:
2968 Status = RxQueryCompressedInfo(Context, Buffer);
2969 break;
2970
2971 default:
2972 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
2973 Status = Context->IoStatusBlock.Status;
2974 break;
2975 }
2976
2977 if (Context->Info.Length < 0)
2978 {
2979 Status = STATUS_BUFFER_OVERFLOW;
2980 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2981 }
2982
2983 Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
2984 }
2985 _SEH2_FINALLY
2986 {
2987 if (Locked)
2988 {
2989 RxReleaseFcb(Context, Fcb);
2990 }
2991 }
2992 _SEH2_END;
2993
2994 DPRINT("Status: %x\n", Status);
2995 return Status;
2996
2997 #undef SET_SIZE_AND_QUERY
2998 }
2999
3000 NTSTATUS
3001 NTAPI
3002 RxCommonQueryQuotaInformation(
3003 PRX_CONTEXT Context)
3004 {
3005 UNIMPLEMENTED;
3006 return STATUS_NOT_IMPLEMENTED;
3007 }
3008
3009 NTSTATUS
3010 NTAPI
3011 RxCommonQuerySecurity(
3012 PRX_CONTEXT Context)
3013 {
3014 UNIMPLEMENTED;
3015 return STATUS_NOT_IMPLEMENTED;
3016 }
3017
3018 /*
3019 * @implemented
3020 */
3021 NTSTATUS
3022 NTAPI
3023 RxCommonQueryVolumeInformation(
3024 PRX_CONTEXT Context)
3025 {
3026 PIRP Irp;
3027 PFCB Fcb;
3028 PFOBX Fobx;
3029 NTSTATUS Status;
3030 PIO_STACK_LOCATION Stack;
3031
3032 PAGED_CODE();
3033
3034 Fcb = (PFCB)Context->pFcb;
3035 Fobx = (PFOBX)Context->pFobx;
3036
3037 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3038
3039 Irp = Context->CurrentIrp;
3040 Stack = Context->CurrentIrpSp;
3041 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
3042 Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
3043
3044 Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
3045 Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
3046 Context->Info.Length = Stack->Parameters.QueryVolume.Length;
3047
3048 /* Forward to mini-rdr */
3049 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
3050
3051 /* Post request if mini-rdr asked to */
3052 if (Context->PostRequest)
3053 {
3054 Status = RxFsdPostRequest(Context);
3055 }
3056 else
3057 {
3058 Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
3059 }
3060
3061 DPRINT("Status: %x\n", Status);
3062 return Status;
3063 }
3064
3065 NTSTATUS
3066 NTAPI
3067 RxCommonRead(
3068 PRX_CONTEXT RxContext)
3069 {
3070 PFCB Fcb;
3071 PIRP Irp;
3072 PFOBX Fobx;
3073 NTSTATUS Status;
3074 PNET_ROOT NetRoot;
3075 PVOID SystemBuffer;
3076 PFILE_OBJECT FileObject;
3077 LARGE_INTEGER ByteOffset;
3078 PIO_STACK_LOCATION Stack;
3079 PLOWIO_CONTEXT LowIoContext;
3080 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3081 ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3082 BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
3083
3084 PAGED_CODE();
3085
3086 Fcb = (PFCB)RxContext->pFcb;
3087 Fobx = (PFOBX)RxContext->pFobx;
3088 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3089
3090 /* Get some parameters */
3091 Irp = RxContext->CurrentIrp;
3092 Stack = RxContext->CurrentIrpSp;
3093 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3094 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3095 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3096 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3097 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3098 ReadLength = Stack->Parameters.Read.Length;
3099 ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
3100 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
3101 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3102
3103 RxItsTheSameContext();
3104
3105 Irp->IoStatus.Information = 0;
3106
3107 /* Should the read be loud - so far, it's just ignored on ReactOS:
3108 * s/DPRINT/DPRINT1/g will make it loud
3109 */
3110 LowIoContext = &RxContext->LowIoContext;
3111 CheckForLoudOperations(RxContext);
3112 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3113 {
3114 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3115 ByteOffset, ReadLength,
3116 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3117 }
3118
3119 RxDeviceObject = RxContext->RxDeviceObject;
3120 /* Update stats */
3121 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3122 {
3123 InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
3124
3125 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
3126 {
3127 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
3128 }
3129 Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
3130
3131 if (PagingIo)
3132 {
3133 ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
3134 }
3135 else if (NoCache)
3136 {
3137 ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
3138 }
3139 else
3140 {
3141 ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
3142 }
3143 }
3144
3145 /* A pagefile cannot be a pipe */
3146 IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
3147 if (IsPipe && PagingIo)
3148 {
3149 return STATUS_INVALID_DEVICE_REQUEST;
3150 }
3151
3152 /* Null-length read is no-op */
3153 if (ReadLength == 0)
3154 {
3155 return STATUS_SUCCESS;
3156 }
3157
3158 /* Validate FCB type */
3159 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
3160 {
3161 return STATUS_INVALID_DEVICE_REQUEST;
3162 }
3163
3164 /* Init the lowio context for possible forward */
3165 RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
3166
3167 PostRequest = FALSE;
3168 ReadCachingDisabled = FALSE;
3169 OwnerSet = FALSE;
3170 ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3171 FileObject = Stack->FileObject;
3172 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3173 _SEH2_TRY
3174 {
3175 LONGLONG FileSize;
3176
3177 /* If no caching, make sure current Cc data have been flushed */
3178 if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
3179 {
3180 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
3181 if (Status == STATUS_LOCK_NOT_GRANTED)
3182 {
3183 PostRequest = TRUE;
3184 _SEH2_LEAVE;
3185 }
3186 else if (Status != STATUS_SUCCESS)
3187 {
3188 _SEH2_LEAVE;
3189 }
3190
3191 ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
3192 CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
3193 RxReleasePagingIoResource(RxContext, Fcb);
3194
3195 if (!NT_SUCCESS(Irp->IoStatus.Status))
3196 {
3197 Status = Irp->IoStatus.Status;
3198 _SEH2_LEAVE;
3199 }
3200
3201 RxAcquirePagingIoResource(RxContext, Fcb);
3202 RxReleasePagingIoResource(RxContext, Fcb);
3203 }
3204
3205 /* Acquire the appropriate lock */
3206 if (PagingIo && !ReadCachingEnabled)
3207 {
3208 ASSERT(!IsPipe);
3209
3210 if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
3211 {
3212 PostRequest = TRUE;
3213 _SEH2_LEAVE;
3214 }
3215
3216 if (!CanWait)
3217 {
3218 LowIoContext->Resource = Fcb->Header.PagingIoResource;
3219 }
3220 }
3221 else
3222 {
3223 if (!ReadCachingEnabled)
3224 {
3225 if (!CanWait && NoCache)
3226 {
3227 Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
3228 if (Status == STATUS_LOCK_NOT_GRANTED)
3229 {
3230 DPRINT1("RdAsyLNG %x\n", RxContext);
3231 PostRequest = TRUE;
3232 _SEH2_LEAVE;
3233 }
3234 if (Status != STATUS_SUCCESS)
3235 {
3236 DPRINT1("RdAsyOthr %x\n", RxContext);
3237 _SEH2_LEAVE;
3238 }
3239
3240 if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3241 {
3242 LowIoContext->Resource = Fcb->Header.Resource;
3243 }
3244 else
3245 {
3246 PostRequest = TRUE;
3247 _SEH2_LEAVE;
3248 }
3249 }
3250 else
3251 {
3252 Status = RxAcquireSharedFcb(RxContext, Fcb);
3253 if (Status == STATUS_LOCK_NOT_GRANTED)
3254 {
3255 PostRequest = TRUE;
3256 _SEH2_LEAVE;
3257 }
3258 else if (Status != STATUS_SUCCESS)
3259 {
3260 _SEH2_LEAVE;
3261 }
3262 }
3263 }
3264 }
3265
3266 RxItsTheSameContext();
3267
3268 ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3269 if (IsPipe)
3270 {
3271 UNIMPLEMENTED;
3272 }
3273
3274 RxGetFileSizeWithLock(Fcb, &FileSize);
3275
3276 /* Make sure FLOCK doesn't conflict */
3277 if (!PagingIo)
3278 {
3279 if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
3280 {
3281 Status = STATUS_FILE_LOCK_CONFLICT;
3282 _SEH2_LEAVE;
3283 }
3284 }
3285
3286 /* Validate byteoffset vs length */
3287 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
3288 {
3289 if (ByteOffset.QuadPart >= FileSize)
3290 {
3291 Status = STATUS_END_OF_FILE;
3292 _SEH2_LEAVE;
3293 }
3294
3295 if (ReadLength > FileSize - ByteOffset.QuadPart)
3296 {
3297 ReadLength = FileSize - ByteOffset.QuadPart;
3298 }
3299 }
3300
3301 /* Read with Cc! */
3302 if (!PagingIo && !NoCache && ReadCachingEnabled &&
3303 !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
3304 {
3305 /* File was not cached yet, do it */
3306 if (FileObject->PrivateCacheMap == NULL)
3307 {
3308 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
3309 {
3310 Status = STATUS_FILE_CLOSED;
3311 _SEH2_LEAVE;
3312 }
3313
3314 RxAdjustAllocationSizeforCC(Fcb);
3315
3316 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
3317 FALSE, &RxData.CacheManagerCallbacks, Fcb);
3318
3319 if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
3320 {
3321 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3322 }
3323 else
3324 {
3325 CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
3326 SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3327 }
3328
3329 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3330 }
3331
3332 /* This should never happen - fix your RDR */
3333 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3334 {
3335 ASSERT(FALSE);
3336 ASSERT(CanWait);
3337
3338 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3339 Status = Irp->IoStatus.Status;
3340 ASSERT(NT_SUCCESS(Status));
3341 }
3342 else
3343 {
3344 /* Map buffer */
3345 SystemBuffer = RxNewMapUserBuffer(RxContext);
3346 if (SystemBuffer == NULL)
3347 {
3348 Status = STATUS_INSUFFICIENT_RESOURCES;
3349 _SEH2_LEAVE;
3350 }
3351
3352 SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3353
3354 RxItsTheSameContext();
3355
3356 /* Perform the read */
3357 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3358 {
3359 if (!ReadCachingEnabled)
3360 {
3361 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3362 }
3363
3364 RxItsTheSameContext();
3365
3366 PostRequest = TRUE;
3367 _SEH2_LEAVE;
3368 }
3369
3370 if (!ReadCachingEnabled)
3371 {
3372 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3373 }
3374
3375 Status = Irp->IoStatus.Status;
3376 ASSERT(NT_SUCCESS(Status));
3377 }
3378 }
3379 else
3380 {
3381 /* Validate the reading */
3382 if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3383 ByteOffset.QuadPart >= 4096)
3384 {
3385 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3386 ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3387 }
3388
3389 /* If it's consistent, forward to mini-rdr */
3390 if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3391 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3392 {
3393 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3394 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3395
3396 RxItsTheSameContext();
3397
3398 if (InFsp && ReadCachingDisabled)
3399 {
3400 ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3401 (PVOID)((ULONG_PTR)RxContext | 3));
3402 OwnerSet = TRUE;
3403 }
3404
3405 Status = RxLowIoReadShell(RxContext);
3406
3407 RxItsTheSameContext();
3408 }
3409 else
3410 {
3411 if (ByteOffset.QuadPart > FileSize)
3412 {
3413 ReadLength = 0;
3414 Irp->IoStatus.Information = ReadLength;
3415 _SEH2_LEAVE;
3416 }
3417
3418 if (ByteOffset.QuadPart + ReadLength > FileSize)
3419 {
3420 ReadLength = FileSize - ByteOffset.QuadPart;
3421 }
3422
3423 SystemBuffer = RxNewMapUserBuffer(RxContext);
3424 RtlZeroMemory(SystemBuffer, ReadLength);
3425 Irp->IoStatus.Information = ReadLength;
3426 }
3427 }
3428 }
3429 _SEH2_FINALLY
3430 {
3431 RxItsTheSameContext();
3432
3433 /* Post if required */
3434 if (PostRequest)
3435 {
3436 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3437 Status = RxFsdPostRequest(RxContext);
3438 }
3439 else