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