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