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