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