[RDBSS] Fix broken cast when comparing DFS magic values
[reactos.git] / sdk / lib / drivers / rdbsslib / rdbss.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rdbsslib/rdbss.c
23 * PURPOSE: RDBSS library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <limits.h>
32 #include <dfs.h>
33 #include <copysup.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
39
40 typedef
41 NTSTATUS
42 (NTAPI *PRX_FSD_DISPATCH) (
43 PRX_CONTEXT Context);
44
45 typedef struct _RX_FSD_DISPATCH_VECTOR
46 {
47 PRX_FSD_DISPATCH CommonRoutine;
48 } RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
49
50 VOID
51 NTAPI
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject);
54
55 NTSTATUS
56 NTAPI
57 RxAcquireForCcFlush(
58 PFILE_OBJECT FileObject,
59 PDEVICE_OBJECT DeviceObject);
60
61 VOID
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64
65 VOID
66 RxAssert(
67 PVOID Assert,
68 PVOID File,
69 ULONG Line,
70 PVOID Message);
71
72 NTSTATUS
73 NTAPI
74 RxCommonCleanup(
75 PRX_CONTEXT Context);
76
77 NTSTATUS
78 NTAPI
79 RxCommonClose(
80 PRX_CONTEXT Context);
81
82 NTSTATUS
83 NTAPI
84 RxCommonCreate(
85 PRX_CONTEXT Context);
86
87 NTSTATUS
88 NTAPI
89 RxCommonDevFCBCleanup(
90 PRX_CONTEXT Context);
91
92 NTSTATUS
93 NTAPI
94 RxCommonDevFCBClose(
95 PRX_CONTEXT Context);
96
97 NTSTATUS
98 NTAPI
99 RxCommonDevFCBFsCtl(
100 PRX_CONTEXT Context);
101
102 NTSTATUS
103 NTAPI
104 RxCommonDevFCBIoCtl(
105 PRX_CONTEXT Context);
106
107 NTSTATUS
108 NTAPI
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context);
111
112 NTSTATUS
113 NTAPI
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context);
116
117 NTSTATUS
118 NTAPI
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context);
121
122 NTSTATUS
123 NTAPI
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context);
126
127 NTSTATUS
128 NTAPI
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context);
131
132 NTSTATUS
133 NTAPI
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context);
136
137 NTSTATUS
138 NTAPI
139 RxCommonLockControl(
140 PRX_CONTEXT Context);
141
142 NTSTATUS
143 NTAPI
144 RxCommonQueryEa(
145 PRX_CONTEXT Context);
146
147 NTSTATUS
148 NTAPI
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context);
151
152 NTSTATUS
153 NTAPI
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context);
156
157 NTSTATUS
158 NTAPI
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context);
161
162 NTSTATUS
163 NTAPI
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context);
166
167 NTSTATUS
168 NTAPI
169 RxCommonRead(
170 PRX_CONTEXT Context);
171
172 NTSTATUS
173 NTAPI
174 RxCommonSetEa(
175 PRX_CONTEXT Context);
176
177 NTSTATUS
178 NTAPI
179 RxCommonSetInformation(
180 PRX_CONTEXT Context);
181
182 NTSTATUS
183 NTAPI
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context);
186
187 NTSTATUS
188 NTAPI
189 RxCommonSetSecurity(
190 PRX_CONTEXT Context);
191
192 NTSTATUS
193 NTAPI
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context);
196
197 NTSTATUS
198 NTAPI
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context);
201
202 NTSTATUS
203 NTAPI
204 RxCommonWrite(
205 PRX_CONTEXT Context);
206
207 VOID
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext);
210
211 NTSTATUS
212 RxCreateFromNetRoot(
213 PRX_CONTEXT Context,
214 PUNICODE_STRING NetRootName);
215
216 NTSTATUS
217 RxCreateTreeConnect(
218 IN PRX_CONTEXT RxContext);
219
220 BOOLEAN
221 NTAPI
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject,
224 PLARGE_INTEGER FileOffset,
225 ULONG Length, BOOLEAN Wait,
226 ULONG LockKey, BOOLEAN CheckForReadOperation,
227 PIO_STATUS_BLOCK IoStatus,
228 PDEVICE_OBJECT DeviceObject);
229
230 BOOLEAN
231 NTAPI
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject,
234 BOOLEAN Wait,
235 PVOID InputBuffer OPTIONAL,
236 ULONG InputBufferLength,
237 PVOID OutputBuffer OPTIONAL,
238 ULONG OutputBufferLength,
239 ULONG IoControlCode,
240 PIO_STATUS_BLOCK IoStatus,
241 PDEVICE_OBJECT DeviceObject);
242
243 BOOLEAN
244 NTAPI
245 RxFastIoRead(
246 PFILE_OBJECT FileObject,
247 PLARGE_INTEGER FileOffset,
248 ULONG Length,
249 BOOLEAN Wait,
250 ULONG LockKey,
251 PVOID Buffer,
252 PIO_STATUS_BLOCK IoStatus,
253 PDEVICE_OBJECT DeviceObject);
254
255 BOOLEAN
256 NTAPI
257 RxFastIoWrite(
258 PFILE_OBJECT FileObject,
259 PLARGE_INTEGER FileOffset,
260 ULONG Length,
261 BOOLEAN Wait,
262 ULONG LockKey,
263 PVOID Buffer,
264 PIO_STATUS_BLOCK IoStatus,
265 PDEVICE_OBJECT DeviceObject);
266
267 NTSTATUS
268 RxFindOrCreateFcb(
269 PRX_CONTEXT RxContext,
270 PUNICODE_STRING NetRootName);
271
272 NTSTATUS
273 RxFirstCanonicalize(
274 PRX_CONTEXT RxContext,
275 PUNICODE_STRING FileName,
276 PUNICODE_STRING CanonicalName,
277 PNET_ROOT_TYPE NetRootType);
278
279 VOID
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context);
282
283 VOID
284 NTAPI
285 RxFspDispatch(
286 IN PVOID Context);
287
288 VOID
289 NTAPI
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath);
292
293 NTSTATUS
294 NTAPI
295 RxGetStringRegistryParameter(
296 IN HANDLE KeyHandle,
297 IN PCWSTR KeyName,
298 OUT PUNICODE_STRING OutString,
299 IN PUCHAR Buffer,
300 IN ULONG BufferLength,
301 IN BOOLEAN LogFailure);
302
303 VOID
304 NTAPI
305 RxInitializeDebugSupport(
306 VOID);
307
308 VOID
309 NTAPI
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject);
312
313 NTSTATUS
314 NTAPI
315 RxInitializeRegistrationStructures(
316 VOID);
317
318 VOID
319 NTAPI
320 RxInitializeTopLevelIrpPackage(
321 VOID);
322
323 VOID
324 NTAPI
325 RxInitUnwind(
326 PDRIVER_OBJECT DriverObject,
327 USHORT State);
328
329 BOOLEAN
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332
333 NTSTATUS
334 NTAPI
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext);
337
338 NTSTATUS
339 RxLowIoReadShell(
340 PRX_CONTEXT RxContext);
341
342 NTSTATUS
343 NTAPI
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext);
346
347 NTSTATUS
348 RxLowIoWriteShell(
349 IN PRX_CONTEXT RxContext);
350
351 NTSTATUS
352 NTAPI
353 RxLowIoWriteShellCompletion(
354 PRX_CONTEXT RxContext);
355
356 PVOID
357 RxNewMapUserBuffer(
358 PRX_CONTEXT RxContext);
359
360 NTSTATUS
361 RxNotifyChangeDirectory(
362 PRX_CONTEXT RxContext);
363
364 NTSTATUS
365 RxpQueryInfoMiniRdr(
366 PRX_CONTEXT RxContext,
367 FILE_INFORMATION_CLASS FileInfoClass,
368 PVOID Buffer);
369
370 VOID
371 RxPurgeNetFcb(
372 PFCB Fcb,
373 PRX_CONTEXT LocalContext);
374
375 NTSTATUS
376 RxQueryAlternateNameInfo(
377 PRX_CONTEXT RxContext,
378 PFILE_NAME_INFORMATION AltNameInfo);
379
380 NTSTATUS
381 RxQueryBasicInfo(
382 PRX_CONTEXT RxContext,
383 PFILE_BASIC_INFORMATION BasicInfo);
384
385 NTSTATUS
386 RxQueryCompressedInfo(
387 PRX_CONTEXT RxContext,
388 PFILE_COMPRESSION_INFORMATION CompressionInfo);
389
390 NTSTATUS
391 RxQueryDirectory(
392 PRX_CONTEXT RxContext);
393
394 NTSTATUS
395 RxQueryEaInfo(
396 PRX_CONTEXT RxContext,
397 PFILE_EA_INFORMATION EaInfo);
398
399 NTSTATUS
400 RxQueryInternalInfo(
401 PRX_CONTEXT RxContext,
402 PFILE_INTERNAL_INFORMATION InternalInfo);
403
404 NTSTATUS
405 RxQueryNameInfo(
406 PRX_CONTEXT RxContext,
407 PFILE_NAME_INFORMATION NameInfo);
408
409 NTSTATUS
410 RxQueryPipeInfo(
411 PRX_CONTEXT RxContext,
412 PFILE_PIPE_INFORMATION PipeInfo);
413
414 NTSTATUS
415 RxQueryPositionInfo(
416 PRX_CONTEXT RxContext,
417 PFILE_POSITION_INFORMATION PositionInfo);
418
419 NTSTATUS
420 RxQueryStandardInfo(
421 PRX_CONTEXT RxContext,
422 PFILE_STANDARD_INFORMATION StandardInfo);
423
424 VOID
425 NTAPI
426 RxReadRegistryParameters(
427 VOID);
428
429 VOID
430 NTAPI
431 RxReleaseFileForNtCreateSection(
432 PFILE_OBJECT FileObject);
433
434 NTSTATUS
435 NTAPI
436 RxReleaseForCcFlush(
437 PFILE_OBJECT FileObject,
438 PDEVICE_OBJECT DeviceObject);
439
440 PRX_CONTEXT
441 RxRemoveOverflowEntry(
442 PRDBSS_DEVICE_OBJECT DeviceObject,
443 WORK_QUEUE_TYPE Queue);
444
445 NTSTATUS
446 RxSearchForCollapsibleOpen(
447 PRX_CONTEXT RxContext,
448 ACCESS_MASK DesiredAccess,
449 ULONG ShareAccess);
450
451 NTSTATUS
452 RxSetAllocationInfo(
453 PRX_CONTEXT RxContext);
454
455 NTSTATUS
456 RxSetBasicInfo(
457 PRX_CONTEXT RxContext);
458
459 NTSTATUS
460 RxSetDispositionInfo(
461 PRX_CONTEXT RxContext);
462
463 NTSTATUS
464 RxSetEndOfFileInfo(
465 PRX_CONTEXT RxContext);
466
467 NTSTATUS
468 RxSetPipeInfo(
469 PRX_CONTEXT RxContext);
470
471 NTSTATUS
472 RxSetPositionInfo(
473 PRX_CONTEXT RxContext);
474
475 NTSTATUS
476 RxSetRenameInfo(
477 PRX_CONTEXT RxContext);
478
479 NTSTATUS
480 RxSetSimpleInfo(
481 PRX_CONTEXT RxContext);
482
483 VOID
484 RxSetupNetFileObject(
485 PRX_CONTEXT RxContext);
486
487 NTSTATUS
488 RxSystemControl(
489 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
490 IN PIRP Irp);
491
492 VOID
493 RxUninitializeCacheMap(
494 PRX_CONTEXT RxContext,
495 PFILE_OBJECT FileObject,
496 PLARGE_INTEGER TruncateSize);
497
498 VOID
499 RxUnstart(
500 PRX_CONTEXT Context,
501 PRDBSS_DEVICE_OBJECT DeviceObject);
502
503 NTSTATUS
504 RxXXXControlFileCallthru(
505 PRX_CONTEXT Context);
506
507 PVOID
508 NTAPI
509 _RxAllocatePoolWithTag(
510 _In_ POOL_TYPE PoolType,
511 _In_ SIZE_T NumberOfBytes,
512 _In_ ULONG Tag);
513
514 VOID
515 NTAPI
516 _RxFreePool(
517 _In_ PVOID Buffer);
518
519 VOID
520 NTAPI
521 _RxFreePoolWithTag(
522 _In_ PVOID Buffer,
523 _In_ ULONG Tag);
524
525 WCHAR RxStarForTemplate = '*';
526 WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
527 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
528 BOOLEAN DisableFlushOnCleanup = FALSE;
529 ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;
530 LIST_ENTRY RxActiveContexts;
531 NPAGED_LOOKASIDE_LIST RxContextLookasideList;
532 FAST_MUTEX RxContextPerFileSerializationMutex;
533 RDBSS_DATA RxData;
534 FCB RxDeviceFCB;
535 BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
536 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
537 {
538 { RxCommonDispatchProblem },
539 { RxCommonDispatchProblem },
540 { RxCommonDevFCBClose },
541 { RxCommonDispatchProblem },
542 { RxCommonDispatchProblem },
543 { RxCommonDispatchProblem },
544 { RxCommonDispatchProblem },
545 { RxCommonDispatchProblem },
546 { RxCommonDispatchProblem },
547 { RxCommonDispatchProblem },
548 { RxCommonDevFCBQueryVolInfo },
549 { RxCommonDispatchProblem },
550 { RxCommonDispatchProblem },
551 { RxCommonDevFCBFsCtl },
552 { RxCommonDevFCBIoCtl },
553 { RxCommonDevFCBIoCtl },
554 { RxCommonDispatchProblem },
555 { RxCommonDispatchProblem },
556 { RxCommonDevFCBCleanup },
557 { RxCommonDispatchProblem },
558 { RxCommonDispatchProblem },
559 { RxCommonDispatchProblem },
560 { RxCommonUnimplemented },
561 { RxCommonUnimplemented },
562 { RxCommonUnimplemented },
563 { RxCommonUnimplemented },
564 { RxCommonUnimplemented },
565 { RxCommonUnimplemented },
566 };
567 RDBSS_EXPORTS RxExports;
568 FAST_IO_DISPATCH RxFastIoDispatch;
569 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
570 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
571 {
572 { RxCommonCreate },
573 { RxCommonUnimplemented },
574 { RxCommonClose },
575 { RxCommonRead },
576 { RxCommonWrite },
577 { RxCommonQueryInformation },
578 { RxCommonSetInformation },
579 { RxCommonQueryEa },
580 { RxCommonSetEa },
581 { RxCommonFlushBuffers },
582 { RxCommonQueryVolumeInformation },
583 { RxCommonSetVolumeInformation },
584 { RxCommonDirectoryControl },
585 { RxCommonFileSystemControl },
586 { RxCommonDeviceControl },
587 { RxCommonDeviceControl },
588 { RxCommonUnimplemented },
589 { RxCommonLockControl },
590 { RxCommonCleanup },
591 { RxCommonUnimplemented },
592 { RxCommonQuerySecurity },
593 { RxCommonSetSecurity },
594 { RxCommonUnimplemented },
595 { RxCommonUnimplemented },
596 { RxCommonUnimplemented },
597 { RxCommonQueryQuotaInformation },
598 { RxCommonSetQuotaInformation },
599 { RxCommonUnimplemented },
600 };
601 ULONG RxFsdEntryCount;
602 LIST_ENTRY RxIrpsList;
603 KSPIN_LOCK RxIrpsListSpinLock;
604 KMUTEX RxScavengerMutex;
605 KMUTEX RxSerializationMutex;
606 UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
607 KSPIN_LOCK TopLevelIrpSpinLock;
608 LIST_ENTRY TopLevelIrpAllocatedContextsList;
609 BOOLEAN RxForceQFIPassThrough = FALSE;
610 BOOLEAN RxNoAsync = FALSE;
611
612 DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
613
614 #if RDBSS_ASSERTS
615 #ifdef ASSERT
616 #undef ASSERT
617 #endif
618
619 #define ASSERT(exp) \
620 if (!(exp)) \
621 { \
622 RxAssert(#exp, __FILE__, __LINE__, NULL); \
623 }
624 #endif
625
626 #if RX_POOL_WRAPPER
627 #undef RxAllocatePool
628 #undef RxAllocatePoolWithTag
629 #undef RxFreePool
630
631 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
632 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
633 #define RxFreePool _RxFreePool
634 #define RxFreePoolWithTag _RxFreePoolWithTag
635 #endif
636
637 /* FUNCTIONS ****************************************************************/
638
639 /*
640 * @implemented
641 */
642 VOID
643 CheckForLoudOperations(
644 PRX_CONTEXT RxContext)
645 {
646 PAGED_CODE();
647
648 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
649
650 /* Are loud operations enabled? */
651 if (RxLoudLowIoOpsEnabled)
652 {
653 PFCB Fcb;
654
655 /* If so, the operation will be loud only if filename ends with all.scr */
656 Fcb = (PFCB)RxContext->pFcb;
657 if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
658 L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
659 {
660 SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
661 }
662 }
663 #undef ALLSCR_LENGTH
664 }
665
666 /*
667 * @implemented
668 */
669 VOID
670 __RxInitializeTopLevelIrpContext(
671 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
672 IN PIRP Irp,
673 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
674 IN ULONG Flags)
675 {
676 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
677
678 RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
679 TopLevelContext->Irp = Irp;
680 TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
681 TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
682 TopLevelContext->RxDeviceObject = RxDeviceObject;
683 TopLevelContext->Previous = IoGetTopLevelIrp();
684 TopLevelContext->Thread = PsGetCurrentThread();
685
686 /* We cannot add to list something that'd come from stack */
687 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
688 {
689 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext);
690 }
691 }
692
693 /*
694 * @implemented
695 */
696 VOID
697 __RxWriteReleaseResources(
698 PRX_CONTEXT RxContext,
699 BOOLEAN ResourceOwnerSet,
700 ULONG LineNumber,
701 PCSTR FileName,
702 ULONG SerialNumber)
703 {
704 PFCB Fcb;
705
706 PAGED_CODE();
707
708 ASSERT(RxContext != NULL);
709
710 Fcb = (PFCB)RxContext->pFcb;
711 ASSERT(Fcb != NULL);
712
713 /* If FCB resource was acquired, release it */
714 if (RxContext->FcbResourceAcquired)
715 {
716 /* Taking care of owner */
717 if (ResourceOwnerSet)
718 {
719 RxReleaseFcbForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
720 }
721 else
722 {
723 RxReleaseFcb(RxContext, Fcb);
724 }
725
726 RxContext->FcbResourceAcquired = FALSE;
727 }
728
729 /* If FCB paging resource was acquired, release it */
730 if (RxContext->FcbPagingIoResourceAcquired)
731 {
732 /* Taking care of owner */
733 if (ResourceOwnerSet)
734 {
735 RxReleasePagingIoResourceForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
736 }
737 else
738 {
739 RxReleasePagingIoResource(RxContext, Fcb);
740 }
741
742 /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
743 }
744 }
745
746 /*
747 * @implemented
748 */
749 VOID
750 RxAddToTopLevelIrpAllocatedContextsList(
751 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
752 {
753 KIRQL OldIrql;
754
755 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
756
757 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
758 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
759
760 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
761 InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
762 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
763 }
764
765 /*
766 * @implemented
767 */
768 VOID
769 NTAPI
770 RxAddToWorkque(
771 IN PRX_CONTEXT RxContext,
772 IN PIRP Irp)
773 {
774 ULONG Queued;
775 KIRQL OldIrql;
776 WORK_QUEUE_TYPE Queue;
777 PIO_STACK_LOCATION Stack;
778
779 Stack = RxContext->CurrentIrpSp;
780 RxContext->PostRequest = FALSE;
781
782 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
783 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
784 Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
785 {
786 Queue = DelayedWorkQueue;
787 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
788 }
789 else
790 {
791 Queue = CriticalWorkQueue;
792 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
793 }
794
795 /* Check for overflow */
796 if (Stack->FileObject != NULL)
797 {
798 KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
799
800 Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
801 /* In case of an overflow, add the new queued call to the overflow list */
802 if (Queued > 1)
803 {
804 InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
805 InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
806 ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
807
808 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
809 return;
810 }
811
812 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
813 }
814
815 ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
816 ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
817 }
818
819 /*
820 * @implemented
821 */
822 VOID
823 RxAdjustFileTimesAndSize(
824 PRX_CONTEXT Context)
825 {
826 PFCB Fcb;
827 PFOBX Fobx;
828 NTSTATUS Status;
829 PFILE_OBJECT FileObject;
830 LARGE_INTEGER CurrentTime;
831 FILE_BASIC_INFORMATION FileBasicInfo;
832 FILE_END_OF_FILE_INFORMATION FileEOFInfo;
833 BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
834
835 PAGED_CODE();
836
837 FileObject = Context->CurrentIrpSp->FileObject;
838 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
839 if (FileObject->PrivateCacheMap == NULL)
840 {
841 return;
842 }
843
844 /* Get now */
845 KeQuerySystemTime(&CurrentTime);
846
847 Fobx = (PFOBX)Context->pFobx;
848 /* Was the file modified? */
849 FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
850 /* We'll set last write if it was modified and user didn't update yet */
851 SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
852 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
853 SetLastAccess = SetLastWrite ||
854 (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
855 !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
856 /* We'll set last change if it was modified and user didn't update yet */
857 SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
858
859 /* Nothing to update? Job done */
860 if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
861 {
862 return;
863 }
864
865 Fcb = (PFCB)Context->pFcb;
866 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
867 NeedUpdate = FALSE;
868 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
869
870 /* Update lastwrite time if required */
871 if (SetLastWrite)
872 {
873 NeedUpdate = TRUE;
874 Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
875 FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
876 }
877
878 /* Update lastaccess time if required */
879 if (SetLastAccess)
880 {
881 NeedUpdate = TRUE;
882 Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
883 FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
884 }
885
886 /* Update lastchange time if required */
887 if (SetLastChange)
888 {
889 NeedUpdate = TRUE;
890 Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
891 FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
892 }
893
894 /* If one of the date was modified, issue a call to mini-rdr */
895 if (NeedUpdate)
896 {
897 Context->Info.FileInformationClass = FileBasicInformation;
898 Context->Info.Buffer = &FileBasicInfo;
899 Context->Info.Length = sizeof(FileBasicInfo);
900
901 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
902 (void)Status;
903 }
904
905 /* If the file was modified, update its EOF */
906 if (FileModified)
907 {
908 FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
909
910 Context->Info.FileInformationClass = FileEndOfFileInformation;
911 Context->Info.Buffer = &FileEOFInfo;
912 Context->Info.Length = sizeof(FileEOFInfo);
913
914 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
915 (void)Status;
916 }
917 }
918
919 /*
920 * @implemented
921 */
922 NTSTATUS
923 RxAllocateCanonicalNameBuffer(
924 PRX_CONTEXT RxContext,
925 PUNICODE_STRING CanonicalName,
926 USHORT CanonicalLength)
927 {
928 PAGED_CODE();
929
930 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
931
932 /* Context must be free of any already allocated name */
933 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
934
935 /* Validate string length */
936 if (CanonicalLength > USHRT_MAX - 1)
937 {
938 CanonicalName->Buffer = NULL;
939 return STATUS_OBJECT_PATH_INVALID;
940 }
941
942 CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
943 if (CanonicalName->Buffer == NULL)
944 {
945 return STATUS_INSUFFICIENT_RESOURCES;
946 }
947
948 CanonicalName->Length = 0;
949 CanonicalName->MaximumLength = CanonicalLength;
950
951 /* Set the two places - they must always be identical */
952 RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
953 RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
954
955 return STATUS_SUCCESS;
956 }
957
958 /*
959 * @implemented
960 */
961 VOID
962 RxCancelNotifyChangeDirectoryRequestsForFobx(
963 PFOBX Fobx)
964 {
965 KIRQL OldIrql;
966 PLIST_ENTRY Entry;
967 PRX_CONTEXT Context;
968 LIST_ENTRY ContextsToCancel;
969
970 /* Init a list for the contexts to cancel */
971 InitializeListHead(&ContextsToCancel);
972
973 /* Lock our list lock */
974 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
975
976 /* Now, browse all the active contexts, to find the associated ones */
977 Entry = RxActiveContexts.Flink;
978 while (Entry != &RxActiveContexts)
979 {
980 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
981 Entry = Entry->Flink;
982
983 /* Not the IRP we're looking for, ignore */
984 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
985 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
986 {
987 continue;
988 }
989
990 /* Not the FOBX we're looking for, ignore */
991 if ((PFOBX)Context->pFobx != Fobx)
992 {
993 continue;
994 }
995
996 /* No cancel routine (can't be cancel, then), ignore */
997 if (Context->MRxCancelRoutine == NULL)
998 {
999 continue;
1000 }
1001
1002 /* Mark our context as cancelled */
1003 SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1004
1005 /* Move it to our list */
1006 RemoveEntryList(&Context->ContextListEntry);
1007 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1008
1009 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1010 }
1011
1012 /* Done with the contexts */
1013 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1014
1015 /* Now, handle all our "extracted" contexts */
1016 while (!IsListEmpty(&ContextsToCancel))
1017 {
1018 Entry = RemoveHeadList(&ContextsToCancel);
1019 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1020
1021 /* If they had an associated IRP (should be always true) */
1022 if (Context->CurrentIrp != NULL)
1023 {
1024 /* Then, call cancel routine */
1025 ASSERT(Context->MRxCancelRoutine != NULL);
1026 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1027 Context->MRxCancelRoutine(Context);
1028 }
1029
1030 /* And delete the context */
1031 RxDereferenceAndDeleteRxContext(Context);
1032 }
1033 }
1034
1035 /*
1036 * @implemented
1037 */
1038 NTSTATUS
1039 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
1040 PV_NET_ROOT VNetRoot,
1041 BOOLEAN ForceFilesClosed)
1042 {
1043 KIRQL OldIrql;
1044 NTSTATUS Status;
1045 PLIST_ENTRY Entry;
1046 PRX_CONTEXT Context;
1047 LIST_ENTRY ContextsToCancel;
1048
1049 /* Init a list for the contexts to cancel */
1050 InitializeListHead(&ContextsToCancel);
1051
1052 /* Lock our list lock */
1053 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1054
1055 /* Assume success */
1056 Status = STATUS_SUCCESS;
1057
1058 /* Now, browse all the active contexts, to find the associated ones */
1059 Entry = RxActiveContexts.Flink;
1060 while (Entry != &RxActiveContexts)
1061 {
1062 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1063 Entry = Entry->Flink;
1064
1065 /* Not the IRP we're looking for, ignore */
1066 if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
1067 Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
1068 {
1069 continue;
1070 }
1071
1072 /* Not the VNetRoot we're looking for, ignore */
1073 if (Context->pFcb == NULL ||
1074 (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
1075 {
1076 continue;
1077 }
1078
1079 /* No cancel routine (can't be cancel, then), ignore */
1080 if (Context->MRxCancelRoutine == NULL)
1081 {
1082 continue;
1083 }
1084
1085 /* At that point, we found a matching context
1086 * If we're not asked to force close, then fail - it's still open
1087 */
1088 if (!ForceFilesClosed)
1089 {
1090 Status = STATUS_FILES_OPEN;
1091 break;
1092 }
1093
1094 /* Mark our context as cancelled */
1095 SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
1096
1097 /* Move it to our list */
1098 RemoveEntryList(&Context->ContextListEntry);
1099 InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
1100
1101 InterlockedIncrement((volatile long *)&Context->ReferenceCount);
1102 }
1103
1104 /* Done with the contexts */
1105 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1106
1107 if (Status != STATUS_SUCCESS)
1108 {
1109 return Status;
1110 }
1111
1112 /* Now, handle all our "extracted" contexts */
1113 while (!IsListEmpty(&ContextsToCancel))
1114 {
1115 Entry = RemoveHeadList(&ContextsToCancel);
1116 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
1117
1118 /* If they had an associated IRP (should be always true) */
1119 if (Context->CurrentIrp != NULL)
1120 {
1121 /* Then, call cancel routine */
1122 ASSERT(Context->MRxCancelRoutine != NULL);
1123 DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
1124 Context->MRxCancelRoutine(Context);
1125 }
1126
1127 /* And delete the context */
1128 RxDereferenceAndDeleteRxContext(Context);
1129 }
1130
1131 return Status;
1132 }
1133
1134 VOID
1135 NTAPI
1136 RxCancelRoutine(
1137 PDEVICE_OBJECT DeviceObject,
1138 PIRP Irp)
1139 {
1140 UNIMPLEMENTED;
1141 }
1142
1143 /*
1144 * @implemented
1145 */
1146 NTSTATUS
1147 RxCanonicalizeFileNameByServerSpecs(
1148 PRX_CONTEXT RxContext,
1149 PUNICODE_STRING NetRootName)
1150 {
1151 USHORT NextChar, CurChar;
1152 USHORT MaxChars;
1153
1154 PAGED_CODE();
1155
1156 /* Validate file name is not empty */
1157 MaxChars = NetRootName->Length / sizeof(WCHAR);
1158 if (MaxChars == 0)
1159 {
1160 return STATUS_MORE_PROCESSING_REQUIRED;
1161 }
1162
1163 /* Validate name is correct */
1164 for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
1165 {
1166 USHORT i;
1167
1168 for (i = NextChar + 1; i < MaxChars; ++i)
1169 {
1170 if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
1171 {
1172 break;
1173 }
1174 }
1175
1176 CurChar = i - 1;
1177 if (CurChar == NextChar)
1178 {
1179 if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
1180 {
1181 continue;
1182 }
1183
1184 if (CurChar != 0)
1185 {
1186 if (CurChar >= MaxChars - 1)
1187 {
1188 continue;
1189 }
1190
1191 if (NetRootName->Buffer[CurChar + 1] != ':')
1192 {
1193 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1194 }
1195 }
1196 else
1197 {
1198 if (NetRootName->Buffer[1] != ':')
1199 {
1200 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1201 }
1202 }
1203 }
1204 else
1205 {
1206 if ((CurChar - NextChar) == 1)
1207 {
1208 if (NetRootName->Buffer[NextChar + 2] != '.')
1209 {
1210 continue;
1211 }
1212
1213 if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
1214 {
1215 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1216 }
1217 }
1218 else
1219 {
1220 if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
1221 || NetRootName->Buffer[NextChar + 1] != '.')
1222 {
1223 continue;
1224 }
1225
1226 if (NetRootName->Buffer[NextChar + 2] == '.')
1227 {
1228 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1229 }
1230 }
1231 }
1232 }
1233
1234 return STATUS_MORE_PROCESSING_REQUIRED;
1235 }
1236
1237 NTSTATUS
1238 RxCanonicalizeNameAndObtainNetRoot(
1239 PRX_CONTEXT RxContext,
1240 PUNICODE_STRING FileName,
1241 PUNICODE_STRING NetRootName)
1242 {
1243 NTSTATUS Status;
1244 NET_ROOT_TYPE NetRootType;
1245 UNICODE_STRING CanonicalName;
1246
1247 PAGED_CODE();
1248
1249 NetRootType = NET_ROOT_WILD;
1250
1251 RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1252 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1253
1254 /* if not relative opening, just handle the passed name */
1255 if (RxContext->CurrentIrpSp->FileObject->RelatedFileObject == NULL)
1256 {
1257 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1258 if (!NT_SUCCESS(Status))
1259 {
1260 return Status;
1261 }
1262 }
1263 else
1264 {
1265 PFCB Fcb;
1266
1267 /* Make sure we have a valid FCB and a FOBX */
1268 Fcb = RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext;
1269 if (Fcb == NULL ||
1270 RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext2 == NULL)
1271 {
1272 return STATUS_INVALID_PARAMETER;
1273 }
1274
1275 if (!NodeTypeIsFcb(Fcb))
1276 {
1277 return STATUS_INVALID_PARAMETER;
1278 }
1279
1280 UNIMPLEMENTED;
1281 }
1282
1283 /* Get/Create the associated VNetRoot for opening */
1284 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1285 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1286 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
1287 {
1288 ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1289
1290 RxFreeCanonicalNameBuffer(RxContext);
1291 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1292 if (NT_SUCCESS(Status))
1293 {
1294 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1295 }
1296 }
1297
1298 /* Filename cannot contain wildcards */
1299 if (FsRtlDoesNameContainWildCards(NetRootName))
1300 {
1301 Status = STATUS_OBJECT_NAME_INVALID;
1302 }
1303
1304 /* Make sure file name is correct */
1305 if (NT_SUCCESS(Status))
1306 {
1307 Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1308 }
1309
1310 /* Give the mini-redirector a chance to prepare the name */
1311 if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
1312 {
1313 if (RxContext->Create.pNetRoot != NULL)
1314 {
1315 NTSTATUS IgnoredStatus;
1316
1317 MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1318 MRxPreparseName, (RxContext, NetRootName));
1319 (void)IgnoredStatus;
1320 }
1321 }
1322
1323 return Status;
1324 }
1325
1326 VOID
1327 NTAPI
1328 RxCheckFcbStructuresForAlignment(
1329 VOID)
1330 {
1331 UNIMPLEMENTED;
1332 }
1333
1334 #if DBG
1335 NTSTATUS
1336 RxCheckShareAccess(
1337 _In_ ACCESS_MASK DesiredAccess,
1338 _In_ ULONG DesiredShareAccess,
1339 _Inout_ PFILE_OBJECT FileObject,
1340 _Inout_ PSHARE_ACCESS ShareAccess,
1341 _In_ BOOLEAN Update,
1342 _In_ PSZ where,
1343 _In_ PSZ wherelogtag)
1344 {
1345 PAGED_CODE();
1346
1347 RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1348 RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1349
1350 return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
1351 }
1352 #endif
1353
1354 /*
1355 * @implemented
1356 */
1357 NTSTATUS
1358 RxCheckShareAccessPerSrvOpens(
1359 IN PFCB Fcb,
1360 IN ACCESS_MASK DesiredAccess,
1361 IN ULONG DesiredShareAccess)
1362 {
1363 BOOLEAN ReadAccess;
1364 BOOLEAN WriteAccess;
1365 BOOLEAN DeleteAccess;
1366 PSHARE_ACCESS ShareAccess;
1367
1368 PAGED_CODE();
1369
1370 ShareAccess = &Fcb->ShareAccessPerSrvOpens;
1371
1372 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1373 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1374
1375 /* Check if any access wanted */
1376 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
1377 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
1378 DeleteAccess = (DesiredAccess & DELETE) != 0;
1379
1380 if (ReadAccess || WriteAccess || DeleteAccess)
1381 {
1382 BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1383 BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1384 BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1385
1386 /* Check whether there's a violation */
1387 if ((ReadAccess &&
1388 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1389 (WriteAccess &&
1390 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1391 (DeleteAccess &&
1392 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1393 ((ShareAccess->Readers != 0) && !SharedRead) ||
1394 ((ShareAccess->Writers != 0) && !SharedWrite) ||
1395 ((ShareAccess->Deleters != 0) && !SharedDelete))
1396 {
1397 return STATUS_SHARING_VIOLATION;
1398 }
1399 }
1400
1401 return STATUS_SUCCESS;
1402 }
1403
1404 VOID
1405 RxCleanupPipeQueues(
1406 PRX_CONTEXT Context)
1407 {
1408 UNIMPLEMENTED;
1409 }
1410
1411 /*
1412 * @implemented
1413 */
1414 NTSTATUS
1415 RxCloseAssociatedSrvOpen(
1416 IN PFOBX Fobx,
1417 IN PRX_CONTEXT RxContext OPTIONAL)
1418 {
1419 PFCB Fcb;
1420 NTSTATUS Status;
1421 PSRV_OPEN SrvOpen;
1422 BOOLEAN CloseSrvOpen;
1423 PRX_CONTEXT LocalContext;
1424
1425 PAGED_CODE();
1426
1427 /* Assume SRV_OPEN is already closed */
1428 CloseSrvOpen = FALSE;
1429 /* If we have a FOBX, we'll have to close it */
1430 if (Fobx != NULL)
1431 {
1432 /* If the FOBX isn't closed yet */
1433 if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1434 {
1435 SrvOpen = Fobx->SrvOpen;
1436 Fcb = (PFCB)SrvOpen->pFcb;
1437 /* Check whether we've to close SRV_OPEN first */
1438 if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1439 {
1440 CloseSrvOpen = TRUE;
1441 }
1442 else
1443 {
1444 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1445
1446 /* Not much to do */
1447 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1448
1449 if (SrvOpen->OpenCount > 0)
1450 {
1451 --SrvOpen->OpenCount;
1452 }
1453 }
1454 }
1455
1456 /* No need to close SRV_OPEN, so close FOBX */
1457 if (!CloseSrvOpen)
1458 {
1459 RxMarkFobxOnClose(Fobx);
1460
1461 return STATUS_SUCCESS;
1462 }
1463 }
1464 else
1465 {
1466 /* No FOBX? No RX_CONTEXT, ok, job done! */
1467 if (RxContext == NULL)
1468 {
1469 return STATUS_SUCCESS;
1470 }
1471
1472 /* Get the FCB from RX_CONTEXT */
1473 Fcb = (PFCB)RxContext->pFcb;
1474 SrvOpen = NULL;
1475 }
1476
1477 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1478 if (RxContext == NULL)
1479 {
1480 ASSERT(Fobx != NULL);
1481
1482 LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
1483 if (LocalContext == NULL)
1484 {
1485 return STATUS_INSUFFICIENT_RESOURCES;
1486 }
1487
1488 LocalContext->MajorFunction = 2;
1489 LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1490 LocalContext->pFobx = (PMRX_FOBX)Fobx;
1491 LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1492 }
1493 else
1494 {
1495 LocalContext = RxContext;
1496 }
1497
1498 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1499
1500 /* Now, close the FOBX */
1501 if (Fobx != NULL)
1502 {
1503 RxMarkFobxOnClose(Fobx);
1504 }
1505 else
1506 {
1507 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1508 }
1509
1510 /* If not a "standard" file, SRV_OPEN can be null */
1511 if (SrvOpen == NULL)
1512 {
1513 ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
1514 RxDereferenceNetFcb(Fcb);
1515
1516 if (LocalContext != RxContext)
1517 {
1518 RxDereferenceAndDeleteRxContext(LocalContext);
1519 }
1520
1521 return STATUS_SUCCESS;
1522 }
1523
1524 /* If SRV_OPEN isn't in a good condition, nothing to close */
1525 if (SrvOpen->Condition != Condition_Good)
1526 {
1527 if (LocalContext != RxContext)
1528 {
1529 RxDereferenceAndDeleteRxContext(LocalContext);
1530 }
1531
1532 return STATUS_SUCCESS;
1533 }
1534
1535 /* Decrease open count */
1536 if (SrvOpen->OpenCount > 0)
1537 {
1538 --SrvOpen->OpenCount;
1539 }
1540
1541 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1542 if (SrvOpen->OpenCount == 1)
1543 {
1544 if (!IsListEmpty(&SrvOpen->FobxList))
1545 {
1546 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1547 {
1548 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1549 }
1550 }
1551 }
1552
1553 /* Nothing left, purge FCB */
1554 if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1555 {
1556 RxPurgeNetFcb(Fcb, LocalContext);
1557 }
1558
1559 /* Already closed? Job done! */
1560 SrvOpen = Fobx->SrvOpen;
1561 if (SrvOpen == NULL ||
1562 (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1563 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1564 {
1565 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1566 if (LocalContext != RxContext)
1567 {
1568 RxDereferenceAndDeleteRxContext(LocalContext);
1569 }
1570
1571 return STATUS_SUCCESS;
1572 }
1573
1574 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1575
1576 /* Inform mini-rdr about closing */
1577 MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1578 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1579 Status, RxContext, Fobx, Fcb, SrvOpen);
1580
1581 /* And mark as such */
1582 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1583 SrvOpen->Key = (PVOID)-1;
1584
1585 /* If we were delayed, we're not! */
1586 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1587 {
1588 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1589 }
1590
1591 /* Clear access */
1592 RxRemoveShareAccessPerSrvOpens(SrvOpen);
1593 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
1594
1595 /* Dereference */
1596 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1597
1598 /* Mark the FOBX closed as well */
1599 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1600
1601 if (LocalContext != RxContext)
1602 {
1603 RxDereferenceAndDeleteRxContext(LocalContext);
1604 }
1605
1606 return Status;
1607 }
1608
1609 /*
1610 * @implemented
1611 */
1612 NTSTATUS
1613 RxCollapseOrCreateSrvOpen(
1614 PRX_CONTEXT RxContext)
1615 {
1616 PFCB Fcb;
1617 NTSTATUS Status;
1618 ULONG Disposition;
1619 PSRV_OPEN SrvOpen;
1620 USHORT ShareAccess;
1621 PIO_STACK_LOCATION Stack;
1622 ACCESS_MASK DesiredAccess;
1623 RX_BLOCK_CONDITION FcbCondition;
1624
1625 PAGED_CODE();
1626
1627 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1628
1629 Fcb = (PFCB)RxContext->pFcb;
1630 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1631 ++Fcb->UncleanCount;
1632
1633 Stack = RxContext->CurrentIrpSp;
1634 DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1635 ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1636
1637 Disposition = RxContext->Create.NtCreateParameters.Disposition;
1638
1639 /* Try to find a reusable SRV_OPEN */
1640 Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
1641 if (Status == STATUS_NOT_FOUND)
1642 {
1643 /* If none found, create one */
1644 SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb);
1645 if (SrvOpen == NULL)
1646 {
1647 Status = STATUS_INSUFFICIENT_RESOURCES;
1648 }
1649 else
1650 {
1651 SrvOpen->DesiredAccess = DesiredAccess;
1652 SrvOpen->ShareAccess = ShareAccess;
1653 Status = STATUS_SUCCESS;
1654 }
1655
1656 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1657
1658 if (Status != STATUS_SUCCESS)
1659 {
1660 FcbCondition = Condition_Bad;
1661 }
1662 else
1663 {
1664 RxInitiateSrvOpenKeyAssociation(SrvOpen);
1665
1666 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1667 RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1668 /* Inform the mini-rdr we're handling a create */
1669 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCreate, (RxContext));
1670 ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1671
1672 DPRINT("MRxCreate returned: %x\n", Status);
1673 if (Status == STATUS_SUCCESS)
1674 {
1675 /* In case of overwrite, reset file size */
1676 if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
1677 {
1678 RxAcquirePagingIoResource(RxContext, Fcb);
1679 Fcb->Header.AllocationSize.QuadPart = 0LL;
1680 Fcb->Header.FileSize.QuadPart = 0LL;
1681 Fcb->Header.ValidDataLength.QuadPart = 0LL;
1682 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1683 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1684 RxReleasePagingIoResource(RxContext, Fcb);
1685 }
1686 else
1687 {
1688 /* Otherwise, adjust sizes */
1689 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1690 if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1691 {
1692 RxAdjustAllocationSizeforCC(Fcb);
1693 }
1694 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1695 }
1696 }
1697
1698 /* Set the IoStatus with information returned by mini-rdr */
1699 RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1700
1701 SrvOpen->OpenStatus = Status;
1702 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1703 RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
1704
1705 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1706
1707 RxCompleteSrvOpenKeyAssociation(SrvOpen);
1708
1709 if (Status == STATUS_SUCCESS)
1710 {
1711 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1712 {
1713 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
1714 }
1715 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1716 FcbCondition = Condition_Good;
1717 }
1718 else
1719 {
1720 FcbCondition = Condition_Bad;
1721 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1722 RxContext->pRelevantSrvOpen = NULL;
1723
1724 if (RxContext->pFobx != NULL)
1725 {
1726 RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
1727 RxContext->pFobx = NULL;
1728 }
1729 }
1730 }
1731
1732 /* Set FCB state - good or bad - depending on whether create succeed */
1733 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb, Fcb->Condition);
1734 RxTransitionNetFcb(Fcb, FcbCondition);
1735 }
1736 else if (Status == STATUS_SUCCESS)
1737 {
1738 BOOLEAN IsGood, ExtraOpen;
1739
1740 /* A reusable SRV_OPEN was found */
1741 RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
1742 ExtraOpen = FALSE;
1743
1744 SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1745
1746 IsGood = (SrvOpen->Condition == Condition_Good);
1747 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1748 if (!StableCondition(SrvOpen->Condition))
1749 {
1750 RxReferenceSrvOpen(SrvOpen);
1751 ++SrvOpen->OpenCount;
1752 ExtraOpen = TRUE;
1753
1754 RxReleaseFcb(RxContext, Fcb);
1755 RxContext->Create.FcbAcquired = FALSE;
1756
1757 RxWaitForStableSrvOpen(SrvOpen, RxContext);
1758
1759 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, Fcb)))
1760 {
1761 RxContext->Create.FcbAcquired = TRUE;
1762 }
1763
1764 IsGood = (SrvOpen->Condition == Condition_Good);
1765 }
1766
1767 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1768 if (IsGood)
1769 {
1770 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1771
1772 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1773 }
1774 else
1775 {
1776 Status = SrvOpen->OpenStatus;
1777 }
1778
1779 if (ExtraOpen)
1780 {
1781 --SrvOpen->OpenCount;
1782 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1783 }
1784 }
1785
1786 --Fcb->UncleanCount;
1787
1788 DPRINT("Status: %x\n", Status);
1789 return Status;
1790 }
1791
1792 /*
1793 * @implemented
1794 */
1795 NTSTATUS
1796 NTAPI
1797 RxCommonCleanup(
1798 PRX_CONTEXT Context)
1799 {
1800 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1801 PFCB Fcb;
1802 PFOBX Fobx;
1803 ULONG OpenCount;
1804 NTSTATUS Status;
1805 PNET_ROOT NetRoot;
1806 PFILE_OBJECT FileObject;
1807 LARGE_INTEGER TruncateSize;
1808 PLARGE_INTEGER TruncateSizePtr;
1809 BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1810
1811 PAGED_CODE();
1812
1813 Fcb = (PFCB)Context->pFcb;
1814 Fobx = (PFOBX)Context->pFobx;
1815 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1816
1817 /* File system closing, it's OK */
1818 if (Fobx == NULL)
1819 {
1820 if (Fcb->UncleanCount > 0)
1821 {
1822 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1823 }
1824
1825 return STATUS_SUCCESS;
1826 }
1827
1828 /* Check we have a correct FCB type */
1829 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
1830 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
1831 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1832 NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
1833 {
1834 DPRINT1("Invalid Fcb type for %p\n", Fcb);
1835 RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1836 }
1837
1838 FileObject = Context->CurrentIrpSp->FileObject;
1839 ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
1840
1841 RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1842
1843 Status = RxAcquireExclusiveFcb(Context, Fcb);
1844 if (!NT_SUCCESS(Status))
1845 {
1846 return Status;
1847 }
1848
1849 FcbAcquired = TRUE;
1850
1851 Fobx->AssociatedFileObject = NULL;
1852
1853 /* In case it was already orphaned */
1854 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
1855 {
1856 ASSERT(Fcb->UncleanCount != 0);
1857 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1858
1859 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1860 {
1861 --Fcb->UncachedUncleanCount;
1862 }
1863
1864 /* Inform mini-rdr */
1865 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1866
1867 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1868 --Fobx->SrvOpen->UncleanFobxCount;
1869
1870 RxUninitializeCacheMap(Context, FileObject, NULL);
1871
1872 RxReleaseFcb(Context, Fcb);
1873
1874 return STATUS_SUCCESS;
1875 }
1876
1877 /* Report the fact that file could be set as delete on close */
1878 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1879 {
1880 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
1881 }
1882
1883 /* Cancel any pending notification */
1884 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
1885
1886 /* Backup open count before we start playing with it */
1887 OpenCount = Fcb->ShareAccess.OpenCount;
1888
1889 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1890 FcbTableAcquired = FALSE;
1891 LeftForDelete = FALSE;
1892 OneLeft = (Fcb->UncleanCount == 1);
1893
1894 _SEH2_TRY
1895 {
1896 /* Unclean count and delete on close? Verify whether we're the one */
1897 if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
1898 {
1899 if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
1900 {
1901 FcbTableAcquired = TRUE;
1902 }
1903 else
1904 {
1905 RxReleaseFcb(Context, Fcb);
1906
1907 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
1908
1909 Status = RxAcquireExclusiveFcb(Context, Fcb);
1910 if (Status != STATUS_SUCCESS)
1911 {
1912 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1913 return Status;
1914 }
1915
1916 FcbTableAcquired = TRUE;
1917 }
1918
1919 /* That means we'll perform the delete on close! */
1920 if (Fcb->UncleanCount == 1)
1921 {
1922 LeftForDelete = TRUE;
1923 }
1924 else
1925 {
1926 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1927 FcbTableAcquired = FALSE;
1928 }
1929 }
1930
1931 IsFile = FALSE;
1932 TruncateSizePtr = NULL;
1933 /* Handle cleanup for pipes and printers */
1934 if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
1935 {
1936 RxCleanupPipeQueues(Context);
1937 }
1938 /* Handle cleanup for files */
1939 else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
1940 {
1941 Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
1942 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
1943 {
1944 /* First, unlock */
1945 FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
1946
1947 /* If there are still locks to release, proceed */
1948 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
1949 {
1950 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
1951 Context->LowIoContext.ParamsFor.Locks.Flags = 0;
1952 Status = RxLowIoLockControlShell(Context);
1953 }
1954
1955 /* Fix times and size */
1956 RxAdjustFileTimesAndSize(Context);
1957
1958 /* If we're the only one left... */
1959 if (OneLeft)
1960 {
1961 /* And if we're supposed to delete on close */
1962 if (LeftForDelete)
1963 {
1964 /* Update the sizes */
1965 RxAcquirePagingIoResource(Context, Fcb);
1966 Fcb->Header.FileSize.QuadPart = 0;
1967 Fcb->Header.ValidDataLength.QuadPart = 0;
1968 RxReleasePagingIoResource(Context, Fcb);
1969 }
1970 /* Otherwise, call the mini-rdr to adjust sizes */
1971 else
1972 {
1973 /* File got grown up, fill with zeroes */
1974 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
1975 (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
1976 {
1977 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
1978 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1979 }
1980
1981 /* File was truncated, let mini-rdr proceed */
1982 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
1983 {
1984 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
1985 ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
1986
1987 /* Keep track of file change for Cc uninit */
1988 TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
1989 TruncateSizePtr = &TruncateSize;
1990 }
1991 }
1992 }
1993
1994 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1995 if (NeedPurge)
1996 {
1997 if (!OneLeft)
1998 {
1999 NeedPurge = FALSE;
2000 }
2001 }
2002 /* Otherwise, try to see whether we can purge */
2003 else
2004 {
2005 NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
2006 }
2007
2008 IsFile = TRUE;
2009 }
2010 }
2011
2012 /* We have to still be there! */
2013 ASSERT(Fcb->UncleanCount != 0);
2014 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
2015
2016 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2017 {
2018 --Fcb->UncachedUncleanCount;
2019 }
2020
2021 /* Inform mini-rdr about ongoing cleanup */
2022 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
2023
2024 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
2025 --Fobx->SrvOpen->UncleanFobxCount;
2026
2027 /* Flush cache */
2028 if (DisableFlushOnCleanup)
2029 {
2030 /* Only if we're the last standing */
2031 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
2032 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
2033 {
2034 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
2035 RxFlushFcbInSystemCache(Fcb, TRUE);
2036 }
2037 }
2038 else
2039 {
2040 /* Always */
2041 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2042 {
2043 DPRINT("Flushing %p on cleanup\n", Context);
2044 RxFlushFcbInSystemCache(Fcb, TRUE);
2045 }
2046 }
2047
2048 /* If only remaining uncached & unclean, then flush and purge */
2049 if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
2050 {
2051 if (Fcb->UncachedUncleanCount != 0)
2052 {
2053 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
2054 Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
2055 {
2056 DPRINT("Flushing FCB in system cache for %p\n", Context);
2057 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
2058 }
2059 }
2060 }
2061
2062 /* If purge required, and not about to delete, flush */
2063 if (!LeftForDelete && NeedPurge)
2064 {
2065 DPRINT("Flushing FCB in system cache for %p\n", Context);
2066 RxFlushFcbInSystemCache(Fcb, TRUE);
2067 }
2068
2069 /* If it was a file, drop cache */
2070 if (IsFile)
2071 {
2072 DPRINT("Uninit cache map for file\n");
2073 RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
2074 }
2075
2076 /* If that's the one left for deletion, or if it needs purge, flush */
2077 if (LeftForDelete || NeedPurge)
2078 {
2079 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
2080 /* If that's for deletion, also remove from FCB table */
2081 if (LeftForDelete)
2082 {
2083 RxRemoveNameNetFcb(Fcb);
2084 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2085 FcbTableAcquired = FALSE;
2086 }
2087 }
2088
2089 /* Remove any share access */
2090 if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
2091 {
2092 RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
2093 }
2094
2095 /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
2096 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
2097 RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
2098 {
2099 NTSTATUS InternalStatus;
2100 PRX_CONTEXT InternalContext;
2101
2102 /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
2103 InternalStatus = STATUS_UNSUCCESSFUL;
2104 InternalContext = RxCreateRxContext(Context->CurrentIrp,
2105 Fcb->RxDeviceObject,
2106 RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
2107 if (InternalContext != NULL)
2108 {
2109 FILE_END_OF_FILE_INFORMATION FileEOF;
2110
2111 InternalStatus = STATUS_SUCCESS;
2112
2113 /* Initialize the context for file information set */
2114 InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
2115 InternalContext->pFobx = (PMRX_FOBX)Fobx;
2116 InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
2117
2118 /* Get EOF from the FCB */
2119 FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
2120 InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
2121 InternalContext->Info.Buffer = &FileEOF;
2122 InternalContext->Info.Length = sizeof(FileEOF);
2123
2124 /* Call the mini-rdr */
2125 MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
2126
2127 /* We're done */
2128 RxDereferenceAndDeleteRxContext(InternalContext);
2129 }
2130
2131 /* We tried, so, clean the FOBX flag */
2132 ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
2133 /* If it failed, then, disable collapsing on the FCB */
2134 if (!NT_SUCCESS(InternalStatus))
2135 {
2136 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2137 }
2138 }
2139
2140 /* We're clean! */
2141 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
2142
2143 FcbAcquired = FALSE;
2144 RxReleaseFcb(Context, Fcb);
2145 }
2146 _SEH2_FINALLY
2147 {
2148 if (FcbAcquired)
2149 {
2150 RxReleaseFcb(Context, Fcb);
2151 }
2152
2153 if (FcbTableAcquired)
2154 {
2155 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2156 }
2157 }
2158 _SEH2_END;
2159
2160 return Status;
2161 #undef BugCheckFileId
2162 }
2163
2164 NTSTATUS
2165 NTAPI
2166 RxCommonClose(
2167 PRX_CONTEXT Context)
2168 {
2169 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
2170 PFCB Fcb;
2171 PFOBX Fobx;
2172 NTSTATUS Status;
2173 PFILE_OBJECT FileObject;
2174 BOOLEAN DereferenceFobx, AcquiredFcb;
2175
2176 PAGED_CODE();
2177
2178 Fcb = (PFCB)Context->pFcb;
2179 Fobx = (PFOBX)Context->pFobx;
2180 FileObject = Context->CurrentIrpSp->FileObject;
2181 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
2182
2183 Status = RxAcquireExclusiveFcb(Context, Fcb);
2184 if (!NT_SUCCESS(Status))
2185 {
2186 return Status;
2187 }
2188
2189 AcquiredFcb = TRUE;
2190 _SEH2_TRY
2191 {
2192 BOOLEAN Freed;
2193
2194 /* Check our FCB type is expected */
2195 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
2196 (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
2197 (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
2198 {
2199 RxBugCheck(NodeType(Fcb), 0, 0);
2200 }
2201
2202 RxReferenceNetFcb(Fcb);
2203
2204 DereferenceFobx = FALSE;
2205 /* If we're not closing FS */
2206 if (Fobx != NULL)
2207 {
2208 PSRV_OPEN SrvOpen;
2209 PSRV_CALL SrvCall;
2210
2211 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
2212 SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
2213 /* Handle delayed close */
2214 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2215 {
2216 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
2217 {
2218 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
2219 {
2220 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
2221
2222 if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
2223 {
2224 if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
2225 {
2226 InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
2227 }
2228 else
2229 {
2230 DereferenceFobx = TRUE;
2231 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
2232 }
2233 }
2234 }
2235 }
2236 }
2237
2238 /* If we reach maximum of delayed close/or if there are no delayed close */
2239 if (!DereferenceFobx)
2240 {
2241 PNET_ROOT NetRoot;
2242
2243 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2244 if (NetRoot->Type != NET_ROOT_PRINT)
2245 {
2246 /* Delete if asked */
2247 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
2248 {
2249 RxScavengeRelatedFobxs(Fcb);
2250 RxSynchronizeWithScavenger(Context);
2251
2252 RxReleaseFcb(Context, Fcb);
2253
2254 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2255 RxOrphanThisFcb(Fcb);
2256 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2257
2258 Status = RxAcquireExclusiveFcb(Context, Fcb);
2259 ASSERT(NT_SUCCESS(Status));
2260 }
2261 }
2262 }
2263
2264 RxMarkFobxOnClose(Fobx);
2265 }
2266
2267 if (DereferenceFobx)
2268 {
2269 ASSERT(Fobx != NULL);
2270 RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
2271 }
2272 else
2273 {
2274 RxCloseAssociatedSrvOpen(Fobx, Context);
2275 if (Fobx != NULL)
2276 {
2277 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
2278 }
2279 }
2280
2281 Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
2282 AcquiredFcb = !Freed;
2283
2284 FileObject->FsContext = (PVOID)-1;
2285
2286 if (Freed)
2287 {
2288 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2289 }
2290 else
2291 {
2292 RxReleaseFcb(Context, Fcb);
2293 AcquiredFcb = FALSE;
2294 }
2295 }
2296 _SEH2_FINALLY
2297 {
2298 if (_SEH2_AbnormalTermination())
2299 {
2300 if (AcquiredFcb)
2301 {
2302 RxReleaseFcb(Context, Fcb);
2303 }
2304 }
2305 else
2306 {
2307 ASSERT(!AcquiredFcb);
2308 }
2309 }
2310 _SEH2_END;
2311
2312 DPRINT("Status: %x\n", Status);
2313 return Status;
2314 #undef BugCheckFileId
2315 }
2316
2317 /*
2318 * @implemented
2319 */
2320 NTSTATUS
2321 NTAPI
2322 RxCommonCreate(
2323 PRX_CONTEXT Context)
2324 {
2325 PIRP Irp;
2326 NTSTATUS Status;
2327 PFILE_OBJECT FileObject;
2328 PIO_STACK_LOCATION Stack;
2329
2330 PAGED_CODE();
2331
2332 DPRINT("RxCommonCreate(%p)\n", Context);
2333
2334 Irp = Context->CurrentIrp;
2335 Stack = Context->CurrentIrpSp;
2336 FileObject = Stack->FileObject;
2337
2338 /* Check whether that's a device opening */
2339 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2340 {
2341 FileObject->FsContext = &RxDeviceFCB;
2342 FileObject->FsContext2 = NULL;
2343
2344 ++RxDeviceFCB.NodeReferenceCount;
2345 ++RxDeviceFCB.OpenCount;
2346
2347 Irp->IoStatus.Information = FILE_OPENED;
2348 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2349
2350 Status = STATUS_SUCCESS;
2351 }
2352 else
2353 {
2354 PFCB RelatedFcb = NULL;
2355
2356 /* Make sure caller is consistent */
2357 if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
2358 (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
2359 {
2360 DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2361 return STATUS_INVALID_PARAMETER;
2362 }
2363
2364 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2365 Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2366 Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2367 DPRINT("FileName: %wZ\n", &FileObject->FileName);
2368
2369 if (FileObject->RelatedFileObject != NULL)
2370 {
2371 RelatedFcb = FileObject->RelatedFileObject->FsContext;
2372 DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2373 }
2374
2375 /* Going to rename? */
2376 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
2377 {
2378 DPRINT("TargetDir!\n");
2379 }
2380
2381 /* Copy create parameters to the context */
2382 RxCopyCreateParameters(Context);
2383
2384 /* If the caller wants to establish a connection, go ahead */
2385 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2386 {
2387 Status = RxCreateTreeConnect(Context);
2388 }
2389 else
2390 {
2391 /* Validate file name */
2392 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2393 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2394 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2395 {
2396 FileObject->FileName.Length -= sizeof(WCHAR);
2397 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2398 FileObject->FileName.Length);
2399
2400 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2401 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2402 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2403 {
2404 return STATUS_OBJECT_NAME_INVALID;
2405 }
2406 }
2407
2408 /* Attempt to open the file */
2409 do
2410 {
2411 UNICODE_STRING NetRootName;
2412
2413 /* Strip last \ if required */
2414 if (FileObject->FileName.Length != 0 &&
2415 FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2416 {
2417 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2418 {
2419 return STATUS_OBJECT_NAME_INVALID;
2420 }
2421
2422 FileObject->FileName.Length -= sizeof(WCHAR);
2423 Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
2424 }
2425
2426 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
2427 {
2428 FileObject->Flags |= FO_WRITE_THROUGH;
2429 }
2430
2431 /* Get the associated net root to opening */
2432 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2433 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2434 {
2435 break;
2436 }
2437
2438 /* And attempt to open */
2439 Status = RxCreateFromNetRoot(Context, &NetRootName);
2440 if (Status == STATUS_SHARING_VIOLATION)
2441 {
2442 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2443
2444 /* If that happens for file creation, fail for real */
2445 if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
2446 {
2447 Status = STATUS_OBJECT_NAME_COLLISION;
2448 }
2449 else
2450 {
2451 /* Otherwise, if possible, attempt to scavenger current FOBX
2452 * to check whether a dormant FOBX is the reason for sharing violation
2453 */
2454 if (Context->Create.TryForScavengingOnSharingViolation &&
2455 !Context->Create.ScavengingAlreadyTried)
2456 {
2457 /* Only doable with a VNetRoot */
2458 if (Context->Create.pVNetRoot != NULL)
2459 {
2460 PV_NET_ROOT VNetRoot;
2461 NT_CREATE_PARAMETERS SavedParameters;
2462
2463 /* Save create parameters */
2464 RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
2465
2466 /* Reference the VNetRoot for the scavenging time */
2467 VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
2468 RxReferenceVNetRoot(VNetRoot);
2469
2470 /* Prepare the RX_CONTEXT for reuse */
2471 RxpPrepareCreateContextForReuse(Context);
2472 RxReinitializeContext(Context);
2473
2474 /* Copy what we saved */
2475 RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
2476
2477 /* And recopy what can be */
2478 RxCopyCreateParameters(Context);
2479
2480 /* And start purging, then scavenging FOBX */
2481 RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
2482 DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
2483 RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
2484 NULL, TRUE);
2485
2486 /* Ask for a second round */
2487 Status = STATUS_MORE_PROCESSING_REQUIRED;
2488
2489 /* Keep track we already scavenged */
2490 Context->Create.ScavengingAlreadyTried = TRUE;
2491
2492 /* Reference our SRV_CALL for CBS handling */
2493 RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
2494 RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
2495
2496 /* Drop our extra reference */
2497 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
2498 }
2499 }
2500 }
2501 }
2502 else if (Status == STATUS_REPARSE)
2503 {
2504 Context->CurrentIrp->IoStatus.Information = 0;
2505 }
2506 else
2507 {
2508 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2509 }
2510 }
2511 while (Status == STATUS_MORE_PROCESSING_REQUIRED);
2512 }
2513
2514 if (Status == STATUS_RETRY)
2515 {
2516 RxpPrepareCreateContextForReuse(Context);
2517 }
2518 ASSERT(Status != STATUS_PENDING);
2519 }
2520
2521 DPRINT("Status: %lx\n", Status);
2522 return Status;
2523 }
2524
2525 /*
2526 * @implemented
2527 */
2528 NTSTATUS
2529 NTAPI
2530 RxCommonDevFCBCleanup(
2531 PRX_CONTEXT Context)
2532 {
2533 PMRX_FCB Fcb;
2534 NTSTATUS Status;
2535
2536 PAGED_CODE();
2537
2538 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2539
2540 Fcb = Context->pFcb;
2541 Status = STATUS_SUCCESS;
2542 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2543
2544 /* Our FOBX if set, has to be a VNetRoot */
2545 if (Context->pFobx != NULL)
2546 {
2547 RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2548 if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2549 {
2550 Status = STATUS_INVALID_DEVICE_REQUEST;
2551 }
2552 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2553 }
2554 else
2555 {
2556 --Fcb->UncleanCount;
2557 }
2558
2559 return Status;
2560 }
2561
2562 /*
2563 * @implemented
2564 */
2565 NTSTATUS
2566 NTAPI
2567 RxCommonDevFCBClose(
2568 PRX_CONTEXT Context)
2569 {
2570 PMRX_FCB Fcb;
2571 NTSTATUS Status;
2572 PMRX_V_NET_ROOT NetRoot;
2573
2574 PAGED_CODE();
2575
2576 DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2577
2578 Fcb = Context->pFcb;
2579 NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2580 Status = STATUS_SUCCESS;
2581 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2582
2583 /* Our FOBX if set, has to be a VNetRoot */
2584 if (NetRoot != NULL)
2585 {
2586 RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2587 if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2588 {
2589 --NetRoot->NumberOfOpens;
2590 RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2591 }
2592 else
2593 {
2594 Status = STATUS_NOT_IMPLEMENTED;
2595 }
2596 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2597 }
2598 else
2599 {
2600 --Fcb->OpenCount;
2601 }
2602
2603 return Status;
2604 }
2605
2606 NTSTATUS
2607 NTAPI
2608 RxCommonDevFCBFsCtl(
2609 PRX_CONTEXT Context)
2610 {
2611 UNIMPLEMENTED;
2612 return STATUS_NOT_IMPLEMENTED;
2613 }
2614
2615 /*
2616 * @implemented
2617 */
2618 NTSTATUS
2619 NTAPI
2620 RxCommonDevFCBIoCtl(
2621 PRX_CONTEXT Context)
2622 {
2623 NTSTATUS Status;
2624
2625 PAGED_CODE();
2626
2627 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2628
2629 if (Context->pFobx != NULL)
2630 {
2631 return STATUS_INVALID_HANDLE;
2632 }
2633
2634 /* Is that a prefix claim from MUP? */
2635 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2636 {
2637 return RxPrefixClaim(Context);
2638 }
2639
2640 /* Otherwise, pass through the mini-rdr */
2641 Status = RxXXXControlFileCallthru(Context);
2642 if (Status != STATUS_PENDING)
2643 {
2644 if (Context->PostRequest)
2645 {
2646 Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2647 Status = RxFsdPostRequest(Context);
2648 }
2649 }
2650
2651 DPRINT("Status: %lx\n", Status);
2652 return Status;
2653 }
2654
2655 NTSTATUS
2656 NTAPI
2657 RxCommonDevFCBQueryVolInfo(
2658 PRX_CONTEXT Context)
2659 {
2660 UNIMPLEMENTED;
2661 return STATUS_NOT_IMPLEMENTED;
2662 }
2663
2664 /*
2665 * @implemented
2666 */
2667 NTSTATUS
2668 NTAPI
2669 RxCommonDeviceControl(
2670 PRX_CONTEXT Context)
2671 {
2672 NTSTATUS Status;
2673
2674 PAGED_CODE();
2675
2676 /* Prefix claim is only allowed for device, not files */
2677 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2678 {
2679 return STATUS_INVALID_DEVICE_REQUEST;
2680 }
2681
2682 /* Submit to mini-rdr */
2683 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
2684 Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
2685 if (Status == STATUS_PENDING)
2686 {
2687 RxDereferenceAndDeleteRxContext_Real(Context);
2688 }
2689
2690 return Status;
2691 }
2692
2693 /*
2694 * @implemented
2695 */
2696 NTSTATUS
2697 NTAPI
2698 RxCommonDirectoryControl(
2699 PRX_CONTEXT Context)
2700 {
2701 PFCB Fcb;
2702 PFOBX Fobx;
2703 NTSTATUS Status;
2704 PIO_STACK_LOCATION Stack;
2705
2706 PAGED_CODE();
2707
2708 Fcb = (PFCB)Context->pFcb;
2709 Fobx = (PFOBX)Context->pFobx;
2710 Stack = Context->CurrentIrpSp;
2711 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2712
2713 /* Call the appropriate helper */
2714 if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2715 {
2716 Status = RxQueryDirectory(Context);
2717 }
2718 else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2719 {
2720 Status = RxNotifyChangeDirectory(Context);
2721 if (Status == STATUS_PENDING)
2722 {
2723 RxDereferenceAndDeleteRxContext_Real(Context);
2724 }
2725 }
2726 else
2727 {
2728 Status = STATUS_INVALID_DEVICE_REQUEST;
2729 }
2730
2731 return Status;
2732 }
2733
2734 NTSTATUS
2735 NTAPI
2736 RxCommonDispatchProblem(
2737 PRX_CONTEXT Context)
2738 {
2739 UNIMPLEMENTED;
2740 return STATUS_NOT_IMPLEMENTED;
2741 }
2742
2743 NTSTATUS
2744 NTAPI
2745 RxCommonFileSystemControl(
2746 PRX_CONTEXT Context)
2747 {
2748 PIRP Irp;
2749 ULONG ControlCode;
2750 PIO_STACK_LOCATION Stack;
2751
2752 PAGED_CODE();
2753
2754 Irp = Context->CurrentIrp;
2755 Stack = Context->CurrentIrpSp;
2756 ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
2757
2758 DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
2759
2760 UNIMPLEMENTED;
2761 return STATUS_NOT_IMPLEMENTED;
2762 }
2763
2764 NTSTATUS
2765 NTAPI
2766 RxCommonFlushBuffers(
2767 PRX_CONTEXT Context)
2768 {
2769 UNIMPLEMENTED;
2770 return STATUS_NOT_IMPLEMENTED;
2771 }
2772
2773 NTSTATUS
2774 NTAPI
2775 RxCommonLockControl(
2776 PRX_CONTEXT Context)
2777 {
2778 UNIMPLEMENTED;
2779 return STATUS_NOT_IMPLEMENTED;
2780 }
2781
2782 NTSTATUS
2783 NTAPI
2784 RxCommonQueryEa(
2785 PRX_CONTEXT Context)
2786 {
2787 UNIMPLEMENTED;
2788 return STATUS_NOT_IMPLEMENTED;
2789 }
2790
2791 /*
2792 * @implemented
2793 */
2794 NTSTATUS
2795 NTAPI
2796 RxCommonQueryInformation(
2797 PRX_CONTEXT Context)
2798 {
2799 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2800 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2801 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2802
2803 PFCB Fcb;
2804 PIRP Irp;
2805 PFOBX Fobx;
2806 BOOLEAN Locked;
2807 NTSTATUS Status;
2808 PIO_STACK_LOCATION Stack;
2809 FILE_INFORMATION_CLASS FileInfoClass;
2810
2811 PAGED_CODE();
2812
2813 Fcb = (PFCB)Context->pFcb;
2814 Fobx = (PFOBX)Context->pFobx;
2815 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2816
2817 Irp = Context->CurrentIrp;
2818 Stack = Context->CurrentIrpSp;
2819 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2820 Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2821
2822 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2823 FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2824
2825 Locked = FALSE;
2826 _SEH2_TRY
2827 {
2828 PVOID Buffer;
2829
2830 /* Get a writable buffer */
2831 Buffer = RxMapSystemBuffer(Context);
2832 if (Buffer == NULL)
2833 {
2834 Status = STATUS_INSUFFICIENT_RESOURCES;
2835 _SEH2_LEAVE;
2836 }
2837 /* Zero it */
2838 RtlZeroMemory(Buffer, Context->Info.Length);
2839
2840 /* Validate file type */
2841 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
2842 {
2843 if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2844 {
2845 Status = STATUS_INVALID_PARAMETER;
2846 _SEH2_LEAVE;
2847 }
2848 else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
2849 {
2850 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
2851 {
2852 Status = STATUS_NOT_IMPLEMENTED;
2853 }
2854 else
2855 {
2856 Status = STATUS_INVALID_PARAMETER;
2857 }
2858
2859 _SEH2_LEAVE;
2860 }
2861 }
2862
2863 /* Acquire the right lock */
2864 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
2865 FileInfoClass != FileNameInformation)
2866 {
2867 if (FileInfoClass == FileCompressionInformation)
2868 {
2869 Status = RxAcquireExclusiveFcb(Context, Fcb);
2870 }
2871 else
2872 {
2873 Status = RxAcquireSharedFcb(Context, Fcb);
2874 }
2875
2876 if (Status == STATUS_LOCK_NOT_GRANTED)
2877 {
2878 Status = STATUS_PENDING;
2879 _SEH2_LEAVE;
2880 }
2881 else if (!NT_SUCCESS(Status))
2882 {
2883 _SEH2_LEAVE;
2884 }
2885
2886 Locked = TRUE;
2887 }
2888
2889 /* Dispatch to the right helper */
2890 switch (FileInfoClass)
2891 {
2892 case FileBasicInformation:
2893 Status = RxQueryBasicInfo(Context, Buffer);
2894 break;
2895
2896 case FileStandardInformation:
2897 Status = RxQueryStandardInfo(Context, Buffer);
2898 break;
2899
2900 case FileInternalInformation:
2901 Status = RxQueryInternalInfo(Context, Buffer);
2902 break;
2903
2904 case FileEaInformation:
2905 Status = RxQueryEaInfo(Context, Buffer);
2906 break;
2907
2908 case FileNameInformation:
2909 Status = RxQueryNameInfo(Context, Buffer);
2910 break;
2911
2912 case FileAllInformation:
2913 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
2914 if (!NT_SUCCESS(Status))
2915 {
2916 break;
2917 }
2918
2919 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
2920 if (!NT_SUCCESS(Status))
2921 {
2922 break;
2923 }
2924
2925 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2926 sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
2927 if (!NT_SUCCESS(Status))
2928 {
2929 break;
2930 }
2931
2932 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2933 sizeof(FILE_STANDARD_INFORMATION) +
2934 sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
2935 if (!NT_SUCCESS(Status))
2936 {
2937 break;
2938 }
2939
2940 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2941 sizeof(FILE_STANDARD_INFORMATION) +
2942 sizeof(FILE_INTERNAL_INFORMATION) +
2943 sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
2944 if (!NT_SUCCESS(Status))
2945 {
2946 break;
2947 }
2948
2949 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2950 sizeof(FILE_STANDARD_INFORMATION) +
2951 sizeof(FILE_INTERNAL_INFORMATION) +
2952 sizeof(FILE_EA_INFORMATION) +
2953 sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
2954 break;
2955
2956 case FileAlternateNameInformation:
2957 Status = RxQueryAlternateNameInfo(Context, Buffer);
2958 break;
2959
2960 case FilePipeInformation:
2961 case FilePipeLocalInformation:
2962 case FilePipeRemoteInformation:
2963 Status = RxQueryPipeInfo(Context, Buffer);
2964 break;
2965
2966 case FileCompressionInformation:
2967 Status = RxQueryCompressedInfo(Context, Buffer);
2968 break;
2969
2970 default:
2971 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
2972 Status = Context->IoStatusBlock.Status;
2973 break;
2974 }
2975
2976 if (Context->Info.Length < 0)
2977 {
2978 Status = STATUS_BUFFER_OVERFLOW;
2979 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2980 }
2981
2982 Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
2983 }
2984 _SEH2_FINALLY
2985 {
2986 if (Locked)
2987 {
2988 RxReleaseFcb(Context, Fcb);
2989 }
2990 }
2991 _SEH2_END;
2992
2993 DPRINT("Status: %x\n", Status);
2994 return Status;
2995
2996 #undef SET_SIZE_AND_QUERY
2997 }
2998
2999 NTSTATUS
3000 NTAPI
3001 RxCommonQueryQuotaInformation(
3002 PRX_CONTEXT Context)
3003 {
3004 UNIMPLEMENTED;
3005 return STATUS_NOT_IMPLEMENTED;
3006 }
3007
3008 NTSTATUS
3009 NTAPI
3010 RxCommonQuerySecurity(
3011 PRX_CONTEXT Context)
3012 {
3013 UNIMPLEMENTED;
3014 return STATUS_NOT_IMPLEMENTED;
3015 }
3016
3017 /*
3018 * @implemented
3019 */
3020 NTSTATUS
3021 NTAPI
3022 RxCommonQueryVolumeInformation(
3023 PRX_CONTEXT Context)
3024 {
3025 PIRP Irp;
3026 PFCB Fcb;
3027 PFOBX Fobx;
3028 NTSTATUS Status;
3029 PIO_STACK_LOCATION Stack;
3030
3031 PAGED_CODE();
3032
3033 Fcb = (PFCB)Context->pFcb;
3034 Fobx = (PFOBX)Context->pFobx;
3035
3036 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3037
3038 Irp = Context->CurrentIrp;
3039 Stack = Context->CurrentIrpSp;
3040 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
3041 Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
3042
3043 Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
3044 Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
3045 Context->Info.Length = Stack->Parameters.QueryVolume.Length;
3046
3047 /* Forward to mini-rdr */
3048 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
3049
3050 /* Post request if mini-rdr asked to */
3051 if (Context->PostRequest)
3052 {
3053 Status = RxFsdPostRequest(Context);
3054 }
3055 else
3056 {
3057 Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
3058 }
3059
3060 DPRINT("Status: %x\n", Status);
3061 return Status;
3062 }
3063
3064 NTSTATUS
3065 NTAPI
3066 RxCommonRead(
3067 PRX_CONTEXT RxContext)
3068 {
3069 PFCB Fcb;
3070 PIRP Irp;
3071 PFOBX Fobx;
3072 NTSTATUS Status;
3073 PNET_ROOT NetRoot;
3074 PVOID SystemBuffer;
3075 PFILE_OBJECT FileObject;
3076 LARGE_INTEGER ByteOffset;
3077 PIO_STACK_LOCATION Stack;
3078 PLOWIO_CONTEXT LowIoContext;
3079 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3080 ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3081 BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
3082
3083 PAGED_CODE();
3084
3085 Fcb = (PFCB)RxContext->pFcb;
3086 Fobx = (PFOBX)RxContext->pFobx;
3087 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3088
3089 /* Get some parameters */
3090 Irp = RxContext->CurrentIrp;
3091 Stack = RxContext->CurrentIrpSp;
3092 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3093 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3094 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3095 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3096 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3097 ReadLength = Stack->Parameters.Read.Length;
3098 ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
3099 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
3100 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3101
3102 RxItsTheSameContext();
3103
3104 Irp->IoStatus.Information = 0;
3105
3106 /* Should the read be loud - so far, it's just ignored on ReactOS:
3107 * s/DPRINT/DPRINT1/g will make it loud
3108 */
3109 LowIoContext = &RxContext->LowIoContext;
3110 CheckForLoudOperations(RxContext);
3111 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3112 {
3113 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3114 ByteOffset, ReadLength,
3115 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3116 }
3117
3118 RxDeviceObject = RxContext->RxDeviceObject;
3119 /* Update stats */
3120 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3121 {
3122 InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
3123
3124 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
3125 {
3126 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
3127 }
3128 Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
3129
3130 if (PagingIo)
3131 {
3132 ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
3133 }
3134 else if (NoCache)
3135 {
3136 ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
3137 }
3138 else
3139 {
3140 ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
3141 }
3142 }
3143
3144 /* A pagefile cannot be a pipe */
3145 IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
3146 if (IsPipe && PagingIo)
3147 {
3148 return STATUS_INVALID_DEVICE_REQUEST;
3149 }
3150
3151 /* Null-length read is no-op */
3152 if (ReadLength == 0)
3153 {
3154 return STATUS_SUCCESS;
3155 }
3156
3157 /* Validate FCB type */
3158 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
3159 {
3160 return STATUS_INVALID_DEVICE_REQUEST;
3161 }
3162
3163 /* Init the lowio context for possible forward */
3164 RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
3165
3166 PostRequest = FALSE;
3167 ReadCachingDisabled = FALSE;
3168 OwnerSet = FALSE;
3169 ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3170 FileObject = Stack->FileObject;
3171 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3172 _SEH2_TRY
3173 {
3174 LONGLONG FileSize;
3175
3176 /* If no caching, make sure current Cc data have been flushed */
3177 if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
3178 {
3179 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
3180 if (Status == STATUS_LOCK_NOT_GRANTED)
3181 {
3182 PostRequest = TRUE;
3183 _SEH2_LEAVE;
3184 }
3185 else if (Status != STATUS_SUCCESS)
3186 {
3187 _SEH2_LEAVE;
3188 }
3189
3190 ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
3191 CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
3192 RxReleasePagingIoResource(RxContext, Fcb);
3193
3194 if (!NT_SUCCESS(Irp->IoStatus.Status))
3195 {
3196 Status = Irp->IoStatus.Status;
3197 _SEH2_LEAVE;
3198 }
3199
3200 RxAcquirePagingIoResource(RxContext, Fcb);
3201 RxReleasePagingIoResource(RxContext, Fcb);
3202 }
3203
3204 /* Acquire the appropriate lock */
3205 if (PagingIo && !ReadCachingEnabled)
3206 {
3207 ASSERT(!IsPipe);
3208
3209 if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
3210 {
3211 PostRequest = TRUE;
3212 _SEH2_LEAVE;
3213 }
3214
3215 if (!CanWait)
3216 {
3217 LowIoContext->Resource = Fcb->Header.PagingIoResource;
3218 }
3219 }
3220 else
3221 {
3222 if (!ReadCachingEnabled)
3223 {
3224 if (!CanWait && NoCache)
3225 {
3226 Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
3227 if (Status == STATUS_LOCK_NOT_GRANTED)
3228 {
3229 DPRINT1("RdAsyLNG %x\n", RxContext);
3230 PostRequest = TRUE;
3231 _SEH2_LEAVE;
3232 }
3233 if (Status != STATUS_SUCCESS)
3234 {
3235 DPRINT1("RdAsyOthr %x\n", RxContext);
3236 _SEH2_LEAVE;
3237 }
3238
3239 if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
3240 {
3241 LowIoContext->Resource = Fcb->Header.Resource;
3242 }
3243 else
3244 {
3245 PostRequest = TRUE;
3246 _SEH2_LEAVE;
3247 }
3248 }
3249 else
3250 {
3251 Status = RxAcquireSharedFcb(RxContext, Fcb);
3252 if (Status == STATUS_LOCK_NOT_GRANTED)
3253 {
3254 PostRequest = TRUE;
3255 _SEH2_LEAVE;
3256 }
3257 else if (Status != STATUS_SUCCESS)
3258 {
3259 _SEH2_LEAVE;
3260 }
3261 }
3262 }
3263 }
3264
3265 RxItsTheSameContext();
3266
3267 ReadCachingDisabled = (ReadCachingEnabled == FALSE);
3268 if (IsPipe)
3269 {
3270 UNIMPLEMENTED;
3271 }
3272
3273 RxGetFileSizeWithLock(Fcb, &FileSize);
3274
3275 /* Make sure FLOCK doesn't conflict */
3276 if (!PagingIo)
3277 {
3278 if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
3279 {
3280 Status = STATUS_FILE_LOCK_CONFLICT;
3281 _SEH2_LEAVE;
3282 }
3283 }
3284
3285 /* Validate byteoffset vs length */
3286 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
3287 {
3288 if (ByteOffset.QuadPart >= FileSize)
3289 {
3290 Status = STATUS_END_OF_FILE;
3291 _SEH2_LEAVE;
3292 }
3293
3294 if (ReadLength > FileSize - ByteOffset.QuadPart)
3295 {
3296 ReadLength = FileSize - ByteOffset.QuadPart;
3297 }
3298 }
3299
3300 /* Read with Cc! */
3301 if (!PagingIo && !NoCache && ReadCachingEnabled &&
3302 !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
3303 {
3304 /* File was not cached yet, do it */
3305 if (FileObject->PrivateCacheMap == NULL)
3306 {
3307 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
3308 {
3309 Status = STATUS_FILE_CLOSED;
3310 _SEH2_LEAVE;
3311 }
3312
3313 RxAdjustAllocationSizeforCC(Fcb);
3314
3315 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
3316 FALSE, &RxData.CacheManagerCallbacks, Fcb);
3317
3318 if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
3319 {
3320 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3321 }
3322 else
3323 {
3324 CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
3325 SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3326 }
3327
3328 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3329 }
3330
3331 /* This should never happen - fix your RDR */
3332 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3333 {
3334 ASSERT(FALSE);
3335 ASSERT(CanWait);
3336
3337 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3338 Status = Irp->IoStatus.Status;
3339 ASSERT(NT_SUCCESS(Status));
3340 }
3341 else
3342 {
3343 /* Map buffer */
3344 SystemBuffer = RxNewMapUserBuffer(RxContext);
3345 if (SystemBuffer == NULL)
3346 {
3347 Status = STATUS_INSUFFICIENT_RESOURCES;
3348 _SEH2_LEAVE;
3349 }
3350
3351 SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3352
3353 RxItsTheSameContext();
3354
3355 /* Perform the read */
3356 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3357 {
3358 if (!ReadCachingEnabled)
3359 {
3360 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3361 }
3362
3363 RxItsTheSameContext();
3364
3365 PostRequest = TRUE;
3366 _SEH2_LEAVE;
3367 }
3368
3369 if (!ReadCachingEnabled)
3370 {
3371 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3372 }
3373
3374 Status = Irp->IoStatus.Status;
3375 ASSERT(NT_SUCCESS(Status));
3376 }
3377 }
3378 else
3379 {
3380 /* Validate the reading */
3381 if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3382 ByteOffset.QuadPart >= 4096)
3383 {
3384 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3385 ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3386 }
3387
3388 /* If it's consistent, forward to mini-rdr */
3389 if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3390 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3391 {
3392 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3393 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3394
3395 RxItsTheSameContext();
3396
3397 if (InFsp && ReadCachingDisabled)
3398 {
3399 ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3400 (PVOID)((ULONG_PTR)RxContext | 3));
3401 OwnerSet = TRUE;
3402 }
3403
3404 Status = RxLowIoReadShell(RxContext);
3405
3406 RxItsTheSameContext();
3407 }
3408 else
3409 {
3410 if (ByteOffset.QuadPart > FileSize)
3411 {
3412 ReadLength = 0;
3413 Irp->IoStatus.Information = ReadLength;
3414 _SEH2_LEAVE;
3415 }
3416
3417 if (ByteOffset.QuadPart + ReadLength > FileSize)
3418 {
3419 ReadLength = FileSize - ByteOffset.QuadPart;
3420 }
3421
3422 SystemBuffer = RxNewMapUserBuffer(RxContext);
3423 RtlZeroMemory(SystemBuffer, ReadLength);
3424 Irp->IoStatus.Information = ReadLength;
3425 }
3426 }
3427 }
3428 _SEH2_FINALLY
3429 {
3430 RxItsTheSameContext();
3431
3432 /* Post if required */
3433 if (PostRequest)
3434 {
3435 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3436 Status = RxFsdPostRequest(RxContext);
3437 }
3438 else
3439 {
3440 /* Update FO in case of sync IO */
3441 if (!IsPipe && !PagingIo)
3442 {
3443 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
3444 {
3445 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
3446 }
3447 }
3448 }
3449
3450 /* Set FastIo if read was a success */
3451 if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
3452 {
3453 if (!IsPipe && !PagingIo)
3454 {
3455 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
3456 }
3457 }
3458
3459 /* In case we're done (not expected any further processing */
3460 if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
3461 {
3462 /* Release everything that can be */
3463 if (ReadCachingDisabled)
3464 {
3465 if (PagingIo)
3466 {
3467 if (OwnerSet)
3468 {
3469 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3470 }
3471 else
3472 {
3473 RxReleasePagingIoResource(RxContext, Fcb);
3474 }
3475 }
3476 else
3477 {
3478 if (OwnerSet)
3479 {
3480 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3481 }
3482 else
3483 {
3484 RxReleaseFcb(RxContext, Fcb);
3485 }
3486 }
3487 }
3488
3489 /* Dereference/Delete context */
3490 if (PostRequest)
3491 {
3492 RxDereferenceAndDeleteRxContext(RxContext);
3493 }
3494 else
3495 {
3496 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
3497 {
3498 RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
3499 }
3500 }
3501
3502 /* We cannot return more than asked */
3503 if (Status == STATUS_SUCCESS)
3504 {
3505 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
3506 }
3507 }
3508 else
3509 {
3510 ASSERT(!Sync);
3511
3512 RxDereferenceAndDeleteRxContext(RxContext);
3513 }
3514 }
3515 _SEH2_END;
3516
3517 return Status;
3518 }
3519
3520 NTSTATUS
3521 NTAPI
3522 RxCommonSetEa(
3523 PRX_CONTEXT Context)
3524 {
3525 UNIMPLEMENTED;
3526 return STATUS_NOT_IMPLEMENTED;
3527 }
3528
3529 /*
3530 * @implemented
3531 */
3532 NTSTATUS
3533 NTAPI
3534 RxCommonSetInformation(
3535 PRX_CONTEXT Context)
3536 {
3537 PIRP Irp;
3538 PFCB Fcb;
3539 PFOBX Fobx;
3540 NTSTATUS Status;
3541 PNET_ROOT NetRoot;
3542 PIO_STACK_LOCATION Stack;
3543 FILE_INFORMATION_CLASS Class;
3544 BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
3545
3546 PAGED_CODE();
3547
3548 Fcb = (PFCB)Context->pFcb;
3549 Fobx = (PFOBX)Context->pFobx;
3550 DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
3551
3552 Irp = Context->CurrentIrp;
3553 Stack = Context->CurrentIrpSp;
3554 Class = Stack->Parameters.SetFile.FileInformationClass;
3555 DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
3556 Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
3557 Class, Stack->Parameters.SetFile.ReplaceIfExists);
3558
3559 Status = STATUS_SUCCESS;
3560 CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
3561 FcbTableAcquired = FALSE;
3562 FcbAcquired = FALSE;
3563 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
3564
3565 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3566
3567 _SEH2_TRY
3568 {
3569 /* Valide the node type first */
3570 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
3571 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
3572 {
3573 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
3574 {
3575 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3576 {
3577 Status = STATUS_SUCCESS;
3578 }
3579 }
3580 else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
3581 {
3582 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
3583 {
3584 _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
3585 }
3586 else
3587 {
3588 DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
3589 _SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER);
3590 }
3591 }
3592 }
3593
3594 /* We don't autorize advance operation */
3595 if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
3596 {
3597 DPRINT1("Not allowed\n");
3598
3599 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3600 }
3601
3602 /* For these to classes, we'll have to deal with the FCB table (removal)
3603 * We thus need the exclusive FCB table lock
3604 */
3605 if (Class == FileDispositionInformation || Class == FileRenameInformation)
3606 {
3607 RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
3608 RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
3609
3610 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
3611 {
3612 Context->PostRequest = TRUE;
3613 _SEH2_TRY_RETURN(Status = STATUS_PENDING);
3614 }
3615
3616 FcbTableAcquired = TRUE;
3617 }
3618
3619 /* Finally, if not paging file, we need exclusive FCB lock */
3620 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
3621 {
3622 Status = RxAcquireExclusiveFcb(Context, Fcb);
3623 if (Status == STATUS_LOCK_NOT_GRANTED)
3624 {
3625 Context->PostRequest = TRUE;
3626 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
3627 }
3628 else if (Status != STATUS_SUCCESS)
3629 {
3630 _SEH2_LEAVE;
3631 }
3632
3633 FcbAcquired = TRUE;
3634 }
3635
3636 Status = STATUS_SUCCESS;
3637
3638 /* And now, perform the job! */
3639 switch (Class)
3640 {
3641 case FileBasicInformation:
3642 Status = RxSetBasicInfo(Context);
3643 break;
3644
3645 case FileDispositionInformation:
3646 {
3647 PFILE_DISPOSITION_INFORMATION FDI;
3648
3649 /* Check whether user wants deletion */
3650 FDI = Irp->AssociatedIrp.SystemBuffer;
3651 if (FDI->DeleteFile)
3652 {
3653 /* If so, check whether it's doable */
3654 if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
3655 {
3656 Status = STATUS_CANNOT_DELETE;
3657 }
3658
3659 /* And if doable, already remove from FCB table */
3660 if (Status == STATUS_SUCCESS)
3661 {
3662 ASSERT(FcbAcquired && FcbTableAcquired);
3663 RxRemoveNameNetFcb(Fcb);
3664
3665 RxReleaseFcbTableLock(&NetRoot->FcbTable);
3666 FcbTableAcquired = FALSE;
3667 }
3668 }
3669
3670 /* If it succeed, perform the operation */
3671 if (Status == STATUS_SUCCESS)
3672 {
3673 Status = RxSetDispositionInfo(Context);
3674 }
3675
3676 break;
3677 }
3678
3679 case FilePositionInformation:
3680 Status = RxSetPositionInfo(Context);
3681 break;
3682
3683 case FileAllocationInformation:
3684 Status = RxSetAllocationInfo(Context);
3685 break;
3686
3687 case FileEndOfFileInformation:
3688 Status = RxSetEndOfFileInfo(Context);
3689 break;
3690
3691 case FilePipeInformation:
3692 case FilePipeLocalInformation:
3693 case FilePipeRemoteInformation:
3694 Status = RxSetPipeInfo(Context);
3695 break;
3696
3697 case FileRenameInformation:
3698 case FileLinkInformation:
3699 case FileMoveClusterInformation:
3700 /* If we can wait, try to perform the operation right now */
3701 if (CanWait)
3702 {
3703 /* Of course, collapsing is not doable anymore, file is
3704 * in an inbetween state
3705 */
3706 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
3707
3708 /* Set the information */
3709 Status = RxSetRenameInfo(Context);
3710 /* If it succeed, drop the current entry from FCB table */
3711 if (Status == STATUS_SUCCESS && Class == FileRenameInformation)
3712 {
3713 ASSERT(FcbAcquired && FcbTableAcquired);
3714 RxRemoveNameNetFcb(Fcb);
3715 }
3716 _SEH2_TRY_RETURN(Status);
3717 }
3718 /* Can't wait? Post for async retry */
3719 else
3720 {
3721 Status = RxFsdPostRequest(Context);
3722 _SEH2_TRY_RETURN(Status);
3723 }
3724 break;
3725
3726 case FileValidDataLengthInformation:
3727 if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL))
3728 {
3729 Status = STATUS_USER_MAPPED_FILE;
3730 }
3731 break;
3732
3733 case FileShortNameInformation:
3734 Status = RxSetSimpleInfo(Context);
3735 break;
3736
3737 default:
3738 DPRINT1("Insupported class: %x\n", Class);
3739 Status = STATUS_INVALID_PARAMETER;
3740
3741 break;
3742 }
3743
3744 try_exit: NOTHING;
3745 /* If mini-rdr was OK and wants a re-post on this, do it */
3746 if (Status == STATUS_SUCCESS)
3747 {
3748 if (Context->PostRequest)
3749 {
3750 Status = RxFsdPostRequest(Context);
3751 }
3752 }
3753 }
3754 _SEH2_FINALLY
3755 {
3756 /* Release any acquired lock */
3757 if (FcbAcquired)
3758 {
3759 RxReleaseFcb(Context, Fcb);
3760 }
3761
3762 if (FcbTableAcquired)
3763 {
3764 RxReleaseFcbTableLock(&NetRoot->FcbTable);
3765 }
3766 }
3767 _SEH2_END;
3768
3769 #undef _SEH2_TRY_RETURN
3770
3771 return Status;
3772 }
3773
3774 NTSTATUS
3775 NTAPI
3776 RxCommonSetQuotaInformation(
3777 PRX_CONTEXT Context)
3778 {
3779 UNIMPLEMENTED;
3780 return STATUS_NOT_IMPLEMENTED;
3781 }
3782
3783 NTSTATUS
3784 NTAPI
3785 RxCommonSetSecurity(
3786 PRX_CONTEXT Context)
3787 {
3788 UNIMPLEMENTED;
3789 return STATUS_NOT_IMPLEMENTED;
3790 }
3791
3792 NTSTATUS
3793 NTAPI
3794 RxCommonSetVolumeInformation(
3795 PRX_CONTEXT Context)
3796 {
3797 UNIMPLEMENTED;
3798 return STATUS_NOT_IMPLEMENTED;
3799 }
3800
3801 NTSTATUS
3802 NTAPI
3803 RxCommonUnimplemented(
3804 PRX_CONTEXT Context)
3805 {
3806 UNIMPLEMENTED;
3807 return STATUS_NOT_IMPLEMENTED;
3808 }
3809
3810 NTSTATUS
3811 NTAPI
3812 RxCommonWrite(
3813 PRX_CONTEXT RxContext)
3814 {
3815 PIRP Irp;
3816 PFCB Fcb;
3817 PFOBX Fobx;
3818 NTSTATUS Status;
3819 PNET_ROOT NetRoot;
3820 PSRV_OPEN SrvOpen;
3821 PFILE_OBJECT FileObject;
3822 PIO_STACK_LOCATION Stack;
3823 LARGE_INTEGER ByteOffset;
3824 NODE_TYPE_CODE NodeTypeCode;
3825 PLOWIO_CONTEXT LowIoContext;
3826 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3827 ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
3828 LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
3829 BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
3830
3831 PAGED_CODE();
3832
3833 Fcb = (PFCB)RxContext->pFcb;
3834 NodeTypeCode = NodeType(Fcb);
3835 /* Validate FCB type */
3836 if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
3837 NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
3838 {
3839 return STATUS_INVALID_DEVICE_REQUEST;
3840 }
3841
3842 /* We'll write to file, keep track of it */
3843 Fcb->IsFileWritten = TRUE;
3844
3845 Stack = RxContext->CurrentIrpSp;
3846 /* Set write through if asked */
3847 if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
3848 {
3849 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
3850 }
3851
3852 Fobx = (PFOBX)RxContext->pFobx;
3853 DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
3854
3855 /* Get some parameters */
3856 Irp = RxContext->CurrentIrp;
3857 NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
3858 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
3859 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
3860 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
3861 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
3862 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
3863 WriteLength = Stack->Parameters.Write.Length;
3864 ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
3865 DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
3866 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
3867
3868 RxItsTheSameContext();
3869
3870 RxContext->FcbResourceAcquired = FALSE;
3871 RxContext->FcbPagingIoResourceAcquired = FALSE;
3872
3873 LowIoContext = &RxContext->LowIoContext;
3874 CheckForLoudOperations(RxContext);
3875 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
3876 {
3877 DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
3878 ByteOffset, WriteLength,
3879 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
3880 }
3881
3882 RxDeviceObject = RxContext->RxDeviceObject;
3883 /* Update stats */
3884 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
3885 {
3886 InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
3887
3888 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
3889 {
3890 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
3891 }
3892 Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
3893
3894 if (PagingIo)
3895 {
3896 ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength);
3897 }
3898 else if (NoCache)
3899 {
3900 ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength);
3901 }
3902 else
3903 {
3904 ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength);
3905 }
3906 }
3907
3908 NetRoot = (PNET_ROOT)Fcb->NetRoot;
3909 IsPipe = (NetRoot->Type == NET_ROOT_PIPE);
3910 /* Keep track for normal writes */
3911 if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
3912 {
3913 NormalFile = TRUE;
3914 }
3915 else
3916 {
3917 NormalFile = FALSE;
3918 }
3919
3920 /* Zero-length write is immediate success */
3921 if (NormalFile && WriteLength == 0)
3922 {
3923 return STATUS_SUCCESS;
3924 }
3925
3926 /* Check whether we have input data */
3927 if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
3928 {
3929 return STATUS_INVALID_PARAMETER;
3930 }
3931
3932 /* Are we writting to EOF? */
3933 WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1));
3934 /* FIXME: validate length/offset */
3935
3936 /* Get our SRV_OPEN in case of normal write */
3937 if (Fobx != NULL)
3938 {
3939 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
3940 }
3941 else
3942 {
3943 SrvOpen = NULL;
3944 }
3945
3946 FileObject = Stack->FileObject;
3947
3948 /* If we have caching enabled, check whether we have to defer write */
3949 if (!NoCache)
3950 {
3951 if (RxWriteCacheingAllowed(Fcb, SrvOpen))
3952 {
3953 if (!CcCanIWrite(FileObject, WriteLength,
3954 (CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)),
3955 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE)))
3956 {
3957 BOOLEAN Retrying;
3958
3959 Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
3960
3961 RxPrePostIrp(RxContext, Irp);
3962
3963 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
3964
3965 CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
3966
3967 return STATUS_PENDING;
3968 }
3969 }
3970 }
3971
3972 /* Initialize the low IO context for write */
3973 RxInitializeLowIoContext(LowIoContext, LOWIO_OP_WRITE);
3974
3975 /* Initialize our (many) booleans */
3976 RecursiveWriteThrough = FALSE;
3977 CalledByLazyWriter = FALSE;
3978 SwitchBackToAsync = FALSE;
3979 ExtendingFile = FALSE;
3980 ExtendingValidData = FALSE;
3981 UnwindOutstandingAsync = FALSE;
3982 ResourceOwnerSet = FALSE;
3983 PostIrp = FALSE;
3984 ContextReferenced = FALSE;
3985
3986 #define _SEH2_TRY_RETURN(S) S; goto try_exit
3987
3988 _SEH2_TRY
3989 {
3990 /* No volume FCB here! */
3991 ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) ||
3992 (NodeTypeCode == RDBSS_NTC_SPOOLFILE) ||
3993 (NodeTypeCode == RDBSS_NTC_MAILSLOT));
3994
3995 /* Writing to EOF on a paging file is non sense */
3996 ASSERT(!(WriteToEof && PagingIo));
3997
3998 RxItsTheSameContext();
3999
4000 /* Start locking stuff */
4001 if (!PagingIo && !NoPreposting)
4002 {
4003 /* If it's already acquired, all fine */
4004 if (RxContext->FcbResourceAcquired)
4005 {
4006 ASSERT(!IsPipe);
4007 }
4008 else
4009 {
4010 /* Otherwise, try to acquire shared (excepted for pipes) */
4011 if (IsPipe)
4012 {
4013 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4014 }
4015 else if (CanWait ||
4016 (!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen)))
4017 {
4018 Status = RxAcquireSharedFcb(RxContext, Fcb);
4019 }
4020 else
4021 {
4022 Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
4023 }
4024
4025 /* We'll post IRP to retry */
4026 if (Status == STATUS_LOCK_NOT_GRANTED)
4027 {
4028 PostIrp = TRUE;
4029 DPRINT1("Failed to acquire lock!\n");
4030 _SEH2_TRY_RETURN(Status);
4031 }
4032
4033 /* We'll just fail */
4034 if (Status != STATUS_SUCCESS)
4035 {
4036 _SEH2_TRY_RETURN(Status);
4037 }
4038
4039 /* Resource acquired */
4040 RxContext->FcbResourceAcquired = TRUE;
4041 }
4042
4043 /* At that point, resource is acquired */
4044 if (IsPipe)
4045 {
4046 ASSERT(RxContext->FcbResourceAcquired);
4047 }
4048 else
4049 {
4050 BOOLEAN IsDormant;
4051
4052 /* Now, check whether we have to promote shared lock */
4053 if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4054 {
4055 IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
4056 }
4057 else
4058 {
4059 IsDormant = FALSE;
4060 }
4061
4062 /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
4063 if (RxIsFcbAcquiredShared(Fcb) &&
4064 ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart)
4065 {
4066 if (!IsDormant)
4067 {
4068 RxReleaseFcb(RxContext, Fcb);
4069 RxContext->FcbResourceAcquired = FALSE;
4070
4071 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4072 if (Status == STATUS_LOCK_NOT_GRANTED)
4073 {
4074 PostIrp = TRUE;
4075 DPRINT1("Failed to acquire lock!\n");
4076 _SEH2_TRY_RETURN(Status);
4077 }
4078
4079 if (Status != STATUS_SUCCESS)
4080 {
4081 _SEH2_TRY_RETURN(Status);
4082 }
4083
4084 RxContext->FcbResourceAcquired = TRUE;
4085 }
4086 }
4087
4088 /* If we're writing in VDL, or if we're dormant, shared lock is enough */
4089 if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart ||
4090 IsDormant)
4091 {
4092 if (RxIsFcbAcquiredExclusive(Fcb))
4093 {
4094 RxConvertToSharedFcb(RxContext, Fcb);
4095 }
4096 }
4097 else
4098 {
4099 /* We're extending file, disable collapsing */
4100 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
4101
4102 DPRINT("Disabling collapsing\n");
4103
4104 if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
4105 {
4106 SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
4107 }
4108 }
4109
4110 ASSERT(RxContext->FcbResourceAcquired);
4111 }
4112
4113 /* Keep track of the acquired resource */
4114 LowIoContext->Resource = Fcb->Header.Resource;
4115 }
4116 else
4117 {
4118 /* Paging IO */
4119 ASSERT(!IsPipe);
4120
4121 /* Lock the paging resource */
4122 RxAcquirePagingIoResourceShared(RxContext, Fcb, TRUE);
4123
4124 /* Keep track of the acquired resource */
4125 LowIoContext->Resource = Fcb->Header.PagingIoResource;
4126 }
4127
4128 if (IsPipe)
4129 {
4130 UNIMPLEMENTED;
4131 _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
4132 }
4133
4134 /* If it's a non cached write, or if caching is disallowed */
4135 if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4136 {
4137 /* If cache was previously enabled, we'll have to flush before writing */
4138 if (!PagingIo && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
4139 {
4140 LARGE_INTEGER FlushOffset;
4141
4142 /* FCB is lock */
4143 ASSERT(RxIsFcbAcquiredExclusive(Fcb) || RxIsFcbAcquiredShared(Fcb));
4144
4145 /* If shared, we'll have to relock exclusive */
4146 if (!RxIsFcbAcquiredExclusive(Fcb))
4147 {
4148 /* Release and retry exclusive */
4149 RxReleaseFcb(RxContext, Fcb);
4150 RxContext->FcbResourceAcquired = FALSE;
4151
4152 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4153 if (Status == STATUS_LOCK_NOT_GRANTED)
4154 {
4155 PostIrp = TRUE;
4156 DPRINT1("Failed to acquire lock for flush!\n");
4157 _SEH2_TRY_RETURN(Status);
4158 }
4159
4160 if (Status != STATUS_SUCCESS)
4161 {
4162 _SEH2_TRY_RETURN(Status);
4163 }
4164
4165 RxContext->FcbResourceAcquired = TRUE;
4166 }
4167
4168 /* Get the length to flush */
4169 if (WriteToEof)
4170 {
4171 RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart);
4172 }
4173 else
4174 {
4175 FlushOffset.QuadPart = ByteOffset.QuadPart;
4176 }
4177
4178 /* Perform the flushing */
4179 RxAcquirePagingIoResource(RxContext, Fcb);
4180 CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset,
4181 WriteLength, &Irp->IoStatus);
4182 RxReleasePagingIoResource(RxContext, Fcb);
4183
4184 /* Cannot continue if flushing failed */
4185 if (!NT_SUCCESS(Irp->IoStatus.Status))
4186 {
4187 _SEH2_TRY_RETURN(Status = Irp->IoStatus.Status);
4188 }
4189
4190 /* Synchronize */
4191 RxAcquirePagingIoResource(RxContext, Fcb);
4192 RxReleasePagingIoResource(RxContext, Fcb);
4193
4194 /* And purge */
4195 CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers,
4196 &FlushOffset, WriteLength, FALSE);
4197 }
4198 }
4199
4200 /* If not paging IO, check if write is allowed */
4201 if (!PagingIo)
4202 {
4203 if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp))
4204 {
4205 _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4206 }
4207 }
4208
4209 /* Get file sizes */
4210 ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4211 RxGetFileSizeWithLock(Fcb, &FileSize);
4212 ASSERT(ValidDataLength <= FileSize);
4213
4214 /* If paging IO, we cannot write past file size
4215 * so fix write length if needed
4216 */
4217 if (PagingIo)
4218 {
4219 if (ByteOffset.QuadPart >= FileSize)
4220 {
4221 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
4222 }
4223
4224 if (WriteLength > FileSize - ByteOffset.QuadPart)
4225 {
4226 WriteLength = FileSize - ByteOffset.QuadPart;
4227 }
4228 }
4229
4230 /* If we're being called by the lazywrite */
4231 if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread())
4232 {
4233 CalledByLazyWriter = TRUE;
4234
4235 /* Fail if we're beyong VDL */
4236 if (BooleanFlagOn(Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE))
4237 {
4238 if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) &&
4239 (ByteOffset.QuadPart < FileSize))
4240 {
4241 if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
4242 {
4243 _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4244 }
4245 }
4246 }
4247 }
4248
4249 /* If that's a recursive synchronous page write */
4250 if (BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
4251 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
4252 {
4253 PIRP TopIrp;
4254
4255 /* Check the top level IRP on the FastIO path */
4256 TopIrp = RxGetTopIrpIfRdbssIrp();
4257 if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP)
4258 {
4259 PIO_STACK_LOCATION IrpStack;
4260
4261 ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
4262
4263 /* If the top level IRP was a cached write for this file, keep track */
4264 IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
4265 if (IrpStack->MajorFunction == IRP_MJ_WRITE &&
4266 IrpStack->FileObject->FsContext == FileObject->FsContext)
4267 {
4268 RecursiveWriteThrough = TRUE;
4269 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
4270 }
4271 }
4272 }
4273
4274 /* Now, deal with file size and VDL */
4275 if (!CalledByLazyWriter && !RecursiveWriteThrough &&
4276 (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength))
4277 {
4278 /* Not sync? Let's make it sync, just the time we extended */
4279 if (!Sync)
4280 {
4281 CanWait = TRUE;
4282 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
4283 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4284 Sync = TRUE;
4285
4286 /* Keep track we'll have to switch back to async */
4287 if (NoCache)
4288 {
4289 SwitchBackToAsync = TRUE;
4290 }
4291 }
4292
4293 /* Release all the locks */
4294 RxWriteReleaseResources(RxContext, 0);
4295
4296 /* Acquire exclusive */
4297 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4298 if (Status == STATUS_LOCK_NOT_GRANTED)
4299 {
4300 PostIrp = TRUE;
4301 DPRINT1("Failed to acquire lock for extension!\n");
4302 _SEH2_TRY_RETURN(Status);
4303 }
4304
4305 if (Status != STATUS_SUCCESS)
4306 {
4307 _SEH2_TRY_RETURN(Status);
4308 }
4309
4310 RxContext->FcbResourceAcquired = TRUE;
4311
4312 RxItsTheSameContext();
4313
4314 /* Get the sizes again, to be sure they didn't change in the meantime */
4315 ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
4316 RxGetFileSizeWithLock(Fcb, &FileSize);
4317 ASSERT(ValidDataLength <= FileSize);
4318
4319 /* Check we can switch back to async? */
4320 if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
4321 (ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync)
4322 {
4323 SwitchBackToAsync = FALSE;
4324 }
4325
4326 /* If paging IO, check we don't try to extend the file */
4327 if (PagingIo)
4328 {
4329 if (ByteOffset.QuadPart >= FileSize)
4330 {
4331 _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
4332 }
4333
4334 if (WriteLength > FileSize - ByteOffset.QuadPart)
4335 {
4336 WriteLength = FileSize - ByteOffset.QuadPart;
4337 }
4338 }
4339 }
4340
4341 /* Save our initial sizes for potential rollback */
4342 InitialFileSize = FileSize;
4343 InitialValidDataLength = ValidDataLength;
4344 /* If writing to EOF, update byte offset with file size */
4345 if (WriteToEof)
4346 {
4347 ByteOffset.QuadPart = FileSize;
4348 }
4349
4350 /* Check again whether we're allowed to write */
4351 if (!PagingIo)
4352 {
4353 if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp ))
4354 {
4355 _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
4356 }
4357
4358 /* Do we have to extend? */
4359 if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize))
4360 {
4361 DPRINT("Need to extend file\n");
4362 ExtendingFile = TRUE;
4363 SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE);
4364 }
4365 }
4366
4367 /* Let's start to extend */
4368 if (ExtendingFile)
4369 {
4370 /* If we're past allocating, inform mini-rdr */
4371 FileSize = ByteOffset.QuadPart + WriteLength;
4372 if (FileSize > Fcb->Header.AllocationSize.QuadPart)
4373 {
4374 LARGE_INTEGER NewAllocationSize;
4375
4376 DPRINT("Extending %p\n", RxContext);
4377
4378 if (NoCache)
4379 {
4380 C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4381 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache,
4382 (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4383 }
4384 else
4385 {
4386 C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
4387 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache,
4388 (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
4389 }
4390
4391 if (!NT_SUCCESS(Status))
4392 {
4393 _SEH2_TRY_RETURN(Status);
4394 }
4395
4396 if (FileSize > NewAllocationSize.QuadPart)
4397 {
4398 NewAllocationSize.QuadPart = FileSize;
4399 }
4400
4401 /* And update FCB */
4402 Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
4403 }
4404
4405 /* Set the new sizes */
4406 RxSetFileSizeWithLock(Fcb, &FileSize);
4407 RxAdjustAllocationSizeforCC(Fcb);
4408
4409 /* And inform Cc */
4410 if (CcIsFileCached(FileObject))
4411 {
4412 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
4413 }
4414 }
4415
4416 /* Do we have to extend VDL? */
4417 if (!CalledByLazyWriter && !RecursiveWriteThrough)
4418 {
4419 if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)
4420 {
4421 ExtendingValidData = TRUE;
4422 SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL);
4423 }
4424 }
4425
4426 /* If none cached write */
4427 if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
4428 {
4429 /* Switch back to async, if asked to */
4430 if (SwitchBackToAsync)
4431 {
4432 CanWait = FALSE;
4433 Sync = FALSE;
4434
4435 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
4436 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
4437 }
4438
4439 /* If not synchronous, keep track of writes to be finished */
4440 if (!Sync)
4441 {
4442 if (Fcb->NonPaged->OutstandingAsyncEvent == NULL)
4443 {
4444 Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent;
4445 KeInitializeEvent(Fcb->NonPaged->OutstandingAsyncEvent,
4446 NotificationEvent, FALSE);
4447 }
4448
4449 if (ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites,
4450 1,
4451 &RxStrucSupSpinLock) == 0)
4452 {
4453 KeResetEvent(Fcb->NonPaged->OutstandingAsyncEvent);
4454 }
4455
4456 UnwindOutstandingAsync = TRUE;
4457 LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
4458 }
4459
4460 /* Set our LOWIO_CONTEXT information */
4461 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
4462 LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
4463
4464 RxItsTheSameContext();
4465
4466 /* We have to be locked */
4467 ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
4468
4469 /* Update thread ID if we're in FSP */
4470 if (InFsp)
4471 {
4472 LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
4473
4474 if (RxContext->FcbResourceAcquired)
4475 {
4476 ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3));
4477 }
4478
4479 if (RxContext->FcbPagingIoResourceAcquired)
4480 {
4481 ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3));
4482 }
4483
4484 ResourceOwnerSet = TRUE;
4485 }
4486
4487 /* And perform the write */
4488 Status = RxLowIoWriteShell(RxContext);
4489
4490 RxItsTheSameContext();
4491
4492 /* Not outstanding write anymore */
4493 if (UnwindOutstandingAsync && Status == STATUS_PENDING)
4494 {
4495 UnwindOutstandingAsync = FALSE;
4496 }
4497 }
4498 /* Cached write */
4499 else
4500 {
4501 /* If cache wasn't enabled yet, do it */
4502 if (FileObject->PrivateCacheMap == NULL)
4503 {
4504 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
4505 {
4506 _SEH2_TRY_RETURN(Status = STATUS_FILE_CLOSED);
4507 }
4508
4509 RxAdjustAllocationSizeforCC(Fcb);
4510
4511 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4512 FALSE, &RxData.CacheManagerCallbacks, Fcb);
4513
4514 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
4515 }
4516
4517 /* If that's a MDL backed write */
4518 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
4519 {
4520 /* Shouldn't happen */
4521 ASSERT(FALSE);
4522 ASSERT(CanWait);
4523
4524 /* Perform it, though */
4525 CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength,
4526 &Irp->MdlAddress, &Irp->IoStatus);
4527
4528 Status = Irp->IoStatus.Status;
4529 }
4530 else
4531 {
4532 PVOID SystemBuffer;
4533 ULONG BreakpointsSave;
4534
4535 /* Map the user buffer */
4536 SystemBuffer = RxNewMapUserBuffer(RxContext);
4537 if (SystemBuffer == NULL)
4538 {
4539 _SEH2_TRY_RETURN(Status = STATUS_INSUFFICIENT_RESOURCES);
4540 }
4541
4542 RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4543
4544 RxItsTheSameContext();
4545
4546 /* And deal with Cc */
4547 if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait,
4548 SystemBuffer))
4549 {
4550 RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4551
4552 RxItsTheSameContext();
4553
4554 DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
4555 FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4556
4557 PostIrp = TRUE;
4558 }
4559 else
4560 {
4561 Irp->IoStatus.Status = STATUS_SUCCESS;
4562 Irp->IoStatus.Information = WriteLength;
4563
4564 RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
4565
4566 RxItsTheSameContext();
4567
4568 DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
4569 FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
4570 }
4571 }
4572 }
4573
4574 try_exit: NOTHING;
4575
4576 /* If we've to post the IRP */
4577 if (PostIrp)
4578 {
4579 /* Reset the file size if required */
4580 if (ExtendingFile && !IsPipe)
4581 {
4582 ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen));
4583 ASSERT(Fcb->Header.PagingIoResource != NULL);
4584
4585 RxAcquirePagingIoResource(RxContext, Fcb);
4586 RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4587 RxReleasePagingIoResource(RxContext, Fcb);
4588
4589 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4590 {
4591 *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4592 }
4593 }
4594
4595 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
4596 ContextReferenced = TRUE;
4597
4598 /* Release locks */
4599 ASSERT(!ResourceOwnerSet);
4600 RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4601
4602 #ifdef RDBSS_TRACKER
4603 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
4604 #endif
4605
4606 /* And post the request */
4607 Status = RxFsdPostRequest(RxContext);
4608 }
4609 else
4610 {
4611 if (!IsPipe)
4612 {
4613 /* Update FILE_OBJECT if synchronous write succeed */
4614 if (!PagingIo)
4615 {
4616 if (NT_SUCCESS(Status) && BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4617 {
4618 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
4619 }
4620 }
4621
4622 /* If write succeed, ,also update FILE_OBJECT flags */
4623 if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
4624 {
4625 /* File was modified */
4626 if (!PagingIo)
4627 {
4628 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
4629 }
4630
4631 /* If was even extended */
4632 if (ExtendingFile)
4633 {
4634 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
4635 }
4636
4637 /* If VDL was extended, update FCB and inform Cc */
4638 if (ExtendingValidData)
4639 {
4640 LONGLONG LastOffset;
4641
4642 LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information;
4643 if (FileSize < LastOffset)
4644 {
4645 LastOffset = FileSize;
4646 }
4647
4648 Fcb->Header.ValidDataLength.QuadPart = LastOffset;
4649
4650 if (NoCache && CcIsFileCached(FileObject))
4651 {
4652 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
4653 }
4654 }
4655 }
4656 }
4657 }
4658 }
4659 _SEH2_FINALLY
4660 {
4661 /* Finally, if we failed while extension was required */
4662 if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData))
4663 {
4664 /* Rollback! */
4665 if (!IsPipe)
4666 {
4667 ASSERT(Fcb->Header.PagingIoResource != NULL);
4668
4669 RxAcquirePagingIoResource(RxContext, Fcb);
4670 RxSetFileSizeWithLock(Fcb, &InitialFileSize);
4671 Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
4672 RxReleasePagingIoResource(RxContext, Fcb);
4673
4674 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
4675 {
4676 *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4677 }
4678 }
4679 }
4680
4681 /* One async write less */
4682 if (UnwindOutstandingAsync)
4683 {
4684 ASSERT(!IsPipe);
4685
4686 ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock);
4687 KeSetEvent(Fcb->NonPaged->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
4688 }
4689
4690 /* And now, cleanup everything */
4691 if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp)
4692 {
4693 /* If we didn't post, release every lock (for posting, it's already done) */
4694 if (!PostIrp)
4695 {
4696 RxWriteReleaseResources(RxContext, ResourceOwnerSet);
4697 }
4698
4699 /* If the context was referenced - posting, dereference it */
4700 if (ContextReferenced)
4701 {
4702 RxDereferenceAndDeleteRxContext(RxContext);
4703 }
4704
4705 /* If that's a pipe operation, resume any blocked one */
4706 if (!PostIrp)
4707 {
4708 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
4709 {
4710 RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
4711 }
4712 }
4713
4714 /* Sanity check for write */
4715 if (Status == STATUS_SUCCESS)
4716 {
4717 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
4718 }
4719 }
4720 /* Just dereference our context */
4721 else
4722 {
4723 ASSERT(!Sync);
4724 RxDereferenceAndDeleteRxContext(RxContext);
4725 }
4726 }
4727 _SEH2_END;
4728
4729 #undef _SEH2_TRY_RETURN
4730
4731 return Status;
4732 }
4733
4734 /*
4735 * @implemented
4736 */
4737 NTSTATUS
4738 NTAPI
4739 RxCompleteMdl(
4740 IN PRX_CONTEXT RxContext)
4741 {
4742 PIRP Irp;
4743 PFILE_OBJECT FileObject;
4744 PIO_STACK_LOCATION Stack;
4745
4746 #define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
4747
4748 PAGED_CODE();
4749
4750 Irp = RxContext->CurrentIrp;
4751 Stack = RxContext->CurrentIrpSp;
4752 FileObject = Stack->FileObject;
4753
4754 /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
4755 switch (RxContext->MajorFunction)
4756 {
4757 /* Call the Cc function */
4758 case IRP_MJ_READ:
4759 CcMdlReadComplete(FileObject, Irp->MdlAddress);
4760 break;
4761
4762 case IRP_MJ_WRITE:
4763 /* If here, we can wait */
4764 ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
4765
4766 /* Call the Cc function */
4767 CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
4768
4769 Irp->IoStatus.Status = STATUS_SUCCESS;
4770 break;
4771
4772 default:
4773 DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction);
4774 RxBugCheck(RxContext->MajorFunction, 0, 0);
4775 break;
4776 }
4777
4778 /* MDL was freed */
4779 Irp->MdlAddress = NULL;
4780
4781 /* And complete the IRP */
4782 RxCompleteRequest(RxContext, STATUS_SUCCESS);
4783
4784 #undef BugCheckFileId
4785
4786 return STATUS_SUCCESS;
4787 }
4788
4789 /*
4790 * @implemented
4791 */
4792 VOID
4793 RxCopyCreateParameters(
4794 IN PRX_CONTEXT RxContext)
4795 {
4796 PIRP Irp;
4797 PVOID DfsContext;
4798 PFILE_OBJECT FileObject;
4799 PIO_STACK_LOCATION Stack;
4800 PDFS_NAME_CONTEXT DfsNameContext;
4801 PIO_SECURITY_CONTEXT SecurityContext;
4802
4803 Irp = RxContext->CurrentIrp;
4804 Stack = RxContext->CurrentIrpSp;
4805 FileObject = Stack->FileObject;
4806 SecurityContext = Stack->Parameters.Create.SecurityContext;
4807
4808 RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext;
4809 if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL)
4810 {
4811 RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor);
4812 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext,
4813 RxContext->Create.SdLength);
4814 }
4815 if (SecurityContext->SecurityQos != NULL)
4816 {
4817 RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel;
4818 }
4819 else
4820 {
4821 RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation;
4822 }
4823 RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
4824
4825 RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart;
4826 RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
4827 RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
4828 RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
4829 RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
4830
4831 DfsContext = FileObject->FsContext2;
4832 DfsNameContext = FileObject->FsContext;
4833 RxContext->Create.NtCreateParameters.DfsContext = DfsContext;
4834 RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext;
4835 ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) ||
4836 DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) ||
4837 DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) ||
4838 DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT));
4839 ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT ||
4840 DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT ||
4841 DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT ||
4842 DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT);
4843 FileObject->FsContext2 = NULL;
4844 FileObject->FsContext = NULL;
4845
4846 RxContext->pFcb = NULL;
4847 RxContext->Create.ReturnedCreateInformation = 0;
4848
4849 /* if we stripped last \, it has to be a directory! */
4850 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
4851 {
4852 SetFlag(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DIRECTORY_FILE);
4853 }
4854
4855 RxContext->Create.EaLength = Stack->Parameters.Create.EaLength;
4856 if (RxContext->Create.EaLength == 0)
4857 {
4858 RxContext->Create.EaBuffer = NULL;
4859 }
4860 else
4861 {
4862 RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer;
4863 DPRINT("EA Buffer: %p, Length: %lx\n", Irp->AssociatedIrp.SystemBuffer, RxContext->Create.EaLength);
4864 }
4865 }
4866
4867 NTSTATUS
4868 RxCreateFromNetRoot(
4869 PRX_CONTEXT Context,
4870 PUNICODE_STRING NetRootName)
4871 {
4872 PFCB Fcb;
4873 NTSTATUS Status;
4874 PNET_ROOT NetRoot;
4875 PFILE_OBJECT FileObject;
4876 PIO_STACK_LOCATION Stack;
4877 ACCESS_MASK DesiredAccess;
4878 USHORT DesiredShareAccess;
4879
4880 PAGED_CODE();
4881
4882 /* Validate that the context is consistent */
4883 if (Context->Create.pNetRoot == NULL)
4884 {
4885 return STATUS_BAD_NETWORK_PATH;
4886 }
4887
4888 NetRoot = (PNET_ROOT)Context->Create.pNetRoot;
4889 if (Context->RxDeviceObject != NetRoot->pSrvCall->RxDeviceObject)
4890 {
4891 return STATUS_BAD_NETWORK_PATH;
4892 }
4893
4894 if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) &&
4895 !BooleanFlagOn(NetRoot->pSrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER))
4896 {
4897 return STATUS_DFS_UNAVAILABLE;
4898 }
4899
4900 if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
4901 BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT))
4902 {
4903 return STATUS_OBJECT_TYPE_MISMATCH;
4904 }
4905
4906 Stack = Context->CurrentIrpSp;
4907 DesiredShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
4908 if (NetRoot->Type == NET_ROOT_PRINT)
4909 {
4910 DesiredShareAccess = FILE_SHARE_VALID_FLAGS;
4911 }
4912
4913 DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
4914
4915 /* Get file object */
4916 FileObject = Stack->FileObject;
4917
4918 /* Do we have to open target directory for renaming? */
4919 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
4920 {
4921 DPRINT("Opening target directory\n");
4922
4923 /* If we have been asked for delete, try to purge first */
4924 if (BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, DELETE))
4925 {
4926 RxPurgeRelatedFobxs((PNET_ROOT)Context->Create.pVNetRoot->pNetRoot, Context,
4927 ATTEMPT_FINALIZE_ON_PURGE, NULL);
4928 }
4929
4930 /* Create the FCB */
4931 Fcb = RxCreateNetFcb(Context, (PV_NET_ROOT)Context->Create.pVNetRoot, NetRootName);
4932 if (Fcb == NULL)
4933 {
4934 return STATUS_INSUFFICIENT_RESOURCES;
4935 }
4936
4937 /* Fake it: it will be used only renaming */
4938 NodeType(Fcb) = RDBSS_NTC_OPENTARGETDIR_FCB;
4939 Context->Create.FcbAcquired = FALSE;
4940 Context->Create.NetNamePrefixEntry = NULL;
4941
4942 /* Assign it to the FO */
4943 FileObject->FsContext = Fcb;
4944
4945 /* If we have a FOBX already, check whether it's for DFS opening */
4946 if (Context->pFobx != NULL)
4947 {
4948 /* If so, reflect this in the FOBX */
4949 if (FileObject->FsContext2 == UIntToPtr(DFS_OPEN_CONTEXT))
4950 {
4951 SetFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
4952 }
4953 else
4954 {
4955 ClearFlag(Context->pFobx->Flags, FOBX_FLAG_DFS_OPEN);
4956 }
4957 }
4958
4959 /* Acquire the FCB */
4960 Status = RxAcquireExclusiveFcb(Context, Fcb);
4961 if (Status != STATUS_SUCCESS)
4962 {
4963 return Status;
4964 }
4965
4966 /* Reference the FCB and release */
4967 RxReferenceNetFcb(Fcb);
4968 RxReleaseFcb(Context, Fcb);
4969
4970 /* We're done! */
4971 return STATUS_SUCCESS;
4972 }
4973
4974 /* Try to find (or create) the FCB for the file */
4975 Status = RxFindOrCreateFcb(Context, NetRootName);
4976 Fcb = (PFCB)Context->pFcb;
4977 if (Fcb == NULL)
4978 {
4979 ASSERT(!NT_SUCCESS(Status));
4980 }
4981 if (!NT_SUCCESS(Status) || Fcb == NULL)
4982 {
4983 return Status;
4984 }
4985
4986 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
4987 {
4988 Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT;
4989 }
4990 else
4991 {
4992 Status = STATUS_MORE_PROCESSING_REQUIRED;
4993 }
4994
4995 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
4996 if (NT_SUCCESS(Status))
4997 {
4998 RxTransitionNetFcb(Fcb, Condition_Good);
4999 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb, Fcb->Condition);
5000 ++Fcb->OpenCount;
5001 RxSetupNetFileObject(Context);
5002 return STATUS_SUCCESS;
5003 }
5004
5005 /* Not mailslot! */
5006 /* Check SA for conflict */
5007 if (Fcb->OpenCount > 0)
5008 {
5009 Status = RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
5010 &Fcb->ShareAccess, FALSE, "early check per useropens", "EarlyPerUO");
5011 if (!NT_SUCCESS(Status))
5012 {
5013 RxDereferenceNetFcb(Fcb);
5014 return Status;
5015 }
5016 }
5017
5018 if (BooleanFlagOn(Context->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE) &&
5019 !BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, ~SYNCHRONIZE))
5020 {
5021 UNIMPLEMENTED;
5022 }
5023
5024 _SEH2_TRY
5025 {
5026 /* Find a SRV_OPEN that suits the opening */
5027 Status = RxCollapseOrCreateSrvOpen(Context);
5028 if (Status == STATUS_SUCCESS)
5029 {
5030 PFOBX Fobx;
5031 PSRV_OPEN SrvOpen;
5032
5033 SrvOpen = (PSRV_OPEN)Context->pRelevantSrvOpen;
5034 Fobx = (PFOBX)Context->pFobx;
5035 /* There are already opens, check for conflict */
5036 if (Fcb->OpenCount != 0)
5037 {
5038 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess, DesiredShareAccess,
5039 FileObject, &Fcb->ShareAccess,
5040 FALSE, "second check per useropens",
5041 "2ndAccPerUO")))
5042 {
5043 ++SrvOpen->UncleanFobxCount;
5044 RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
5045
5046 _SEH2_LEAVE;
5047 }
5048 }
5049 else
5050 {
5051 if (NetRoot->Type != NET_ROOT_PIPE)
5052 {
5053 RxSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
5054 &Fcb->ShareAccess, "initial shareaccess setup", "InitShrAcc");
5055 }
5056 }
5057
5058 RxSetupNetFileObject(Context);
5059
5060 /* No conflict? Set up SA */
5061 if (Fcb->OpenCount != 0 && NetRoot->Type != NET_ROOT_PIPE)
5062 {
5063 RxUpdateShareAccess(FileObject, &Fcb->ShareAccess, "update share access", "UpdShrAcc");
5064 }
5065
5066 ++Fcb->UncleanCount;
5067 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
5068 {
5069 ++Fcb->UncachedUncleanCount;
5070 }
5071
5072 if (SrvOpen->UncleanFobxCount == 0 && Fcb->UncleanCount == 1 &&
5073 !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE))
5074 {
5075 RxChangeBufferingState(SrvOpen, NULL, FALSE);
5076 }
5077
5078 /* No pending close, we're active */
5079 ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
5080
5081 ++Fcb->OpenCount;
5082 ++SrvOpen->UncleanFobxCount;
5083 ++SrvOpen->OpenCount;
5084 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
5085
5086 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
5087 {
5088 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING);
5089 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
5090
5091 ClearFlag(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED);
5092 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
5093
5094 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
5095 }
5096
5097 /* Now, update SA for the SRV_OPEN */
5098 RxUpdateShareAccessPerSrvOpens(SrvOpen);
5099
5100 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
5101 {
5102 SetFlag(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE);
5103 }
5104
5105 /* Update the FOBX info */
5106 if (Fobx != NULL)
5107 {
5108 if (Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
5109 {
5110 SetFlag(FileObject->Flags, FO_NAMED_PIPE);
5111 }
5112
5113 if (Context->Create.pNetRoot->Type == NET_ROOT_PRINT ||
5114 Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
5115 {
5116 Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
5117
5118 Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0;
5119 Fobx->Specific.NamedPipe.CollectDataSize = Context->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
5120
5121 Fobx->Specific.NamedPipe.PipeHandleInformation.TypeOfPipe = Context->Create.PipeType;
5122 Fobx->Specific.NamedPipe.PipeHandleInformation.ReadMode = Context->Create.PipeReadMode;
5123 Fobx->Specific.NamedPipe.PipeHandleInformation.CompletionMode = Context->Create.PipeCompletionMode;
5124
5125 InitializeListHead(&Fobx->Specific.NamedPipe.ReadSerializationQueue);
5126 InitializeListHead(&Fobx->Specific.NamedPipe.WriteSerializationQueue);
5127 }
5128 }
5129
5130 Status = STATUS_SUCCESS;
5131 }
5132 }
5133 _SEH2_FINALLY
5134 {
5135 if (Fcb->OpenCount == 0)
5136 {
5137 if (Context->Create.FcbAcquired)
5138 {
5139 Context->Create.FcbAcquired = (RxDereferenceAndFinalizeNetFcb(Fcb,
5140 Context,
5141 FALSE,
5142 FALSE) == 0);
5143 if (!Context->Create.FcbAcquired)
5144 {
5145 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
5146 }
5147 }
5148 }
5149 else
5150 {
5151 RxDereferenceNetFcb(Fcb);
5152 }
5153 }
5154 _SEH2_END;
5155
5156 return Status;
5157 }
5158
5159 /*
5160 * @implemented
5161 */
5162 NTSTATUS
5163 RxCreateTreeConnect(
5164 IN PRX_CONTEXT RxContext)
5165 {
5166 NTSTATUS Status;
5167 PV_NET_ROOT VNetRoot;
5168 PFILE_OBJECT FileObject;
5169 PIO_STACK_LOCATION Stack;
5170 NET_ROOT_TYPE NetRootType;
5171 UNICODE_STRING CanonicalName, RemainingName;
5172
5173 PAGED_CODE();
5174
5175 Stack = RxContext->CurrentIrpSp;
5176 FileObject = Stack->FileObject;
5177
5178 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
5179 /* As long as we don't know connection type, mark it wild */
5180 NetRootType = NET_ROOT_WILD;
5181 /* Get the type by parsing the name */
5182 Status = RxFirstCanonicalize(RxContext, &FileObject->FileName, &CanonicalName, &NetRootType);
5183 if (!NT_SUCCESS(Status))
5184 {
5185 return Status;
5186 }
5187
5188 RxContext->Create.ThisIsATreeConnectOpen = TRUE;
5189 RxContext->Create.TreeConnectOpenDeferred = FALSE;
5190 RtlInitEmptyUnicodeString(&RxContext->Create.TransportName, NULL, 0);
5191 RtlInitEmptyUnicodeString(&RxContext->Create.UserName, NULL, 0);
5192 RtlInitEmptyUnicodeString(&RxContext->Create.Password, NULL, 0);
5193 RtlInitEmptyUnicodeString(&RxContext->Create.UserDomainName, NULL, 0);
5194
5195 /* We don't handle EA - they come from DFS, don't care */
5196 if (Stack->Parameters.Create.EaLength > 0)
5197 {
5198 UNIMPLEMENTED;
5199 }
5200
5201 /* Mount if required */
5202 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
5203 if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT)
5204 {
5205 RxScavengeVNetRoots(RxContext->RxDeviceObject);
5206 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
5207 }
5208
5209 if (!NT_SUCCESS(Status))
5210 {
5211 return Status;
5212 }
5213
5214 /* Validate the rest of the name with mini-rdr */
5215 if (RemainingName.Length > 0)
5216 {
5217 MINIRDR_CALL(Status, RxContext,
5218 RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
5219 MRxIsValidDirectory, (RxContext, &RemainingName));
5220 }
5221
5222 if (!NT_SUCCESS(Status))
5223 {
5224 return Status;
5225 }
5226
5227 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
5228 RxReferenceVNetRoot(VNetRoot);
5229 if (InterlockedCompareExchange(&VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0)
5230 {
5231 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
5232 }
5233
5234 FileObject->FsContext = &RxDeviceFCB;
5235 FileObject->FsContext2 = VNetRoot;
5236
5237 VNetRoot->ConstructionStatus = STATUS_SUCCESS;
5238 ++VNetRoot->NumberOfOpens;
5239
5240 /* Create is over - clear context */
5241 RxContext->Create.pSrvCall = NULL;
5242 RxContext->Create.pNetRoot = NULL;
5243 RxContext->Create.pVNetRoot = NULL;
5244
5245 return Status;
5246 }
5247
5248 VOID
5249 NTAPI
5250 RxDebugControlCommand(
5251 _In_ PSTR ControlString)
5252 {
5253 UNIMPLEMENTED;
5254 }
5255
5256 NTSTATUS
5257 NTAPI
5258 RxDriverEntry(
5259 IN PDRIVER_OBJECT DriverObject,
5260 IN PUNICODE_STRING RegistryPath)
5261 {
5262 NTSTATUS Status;
5263 USHORT i, State = 0;
5264
5265 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject, RegistryPath);
5266
5267 _SEH2_TRY
5268 {
5269 RxCheckFcbStructuresForAlignment();
5270
5271 RtlZeroMemory(&RxData, sizeof(RxData));
5272 RxData.NodeTypeCode = RDBSS_NTC_DATA_HEADER;
5273 RxData.NodeByteSize = sizeof(RxData);
5274 RxData.DriverObject = DriverObject;
5275
5276 RtlZeroMemory(&RxDeviceFCB, sizeof(RxDeviceFCB));
5277 RxDeviceFCB.spacer.NodeTypeCode = RDBSS_NTC_DEVICE_FCB;
5278 RxDeviceFCB.spacer.NodeByteSize = sizeof(RxDeviceFCB);
5279
5280 KeInitializeSpinLock(&RxStrucSupSpinLock);
5281 RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
5282
5283 RxInitializeDebugSupport();
5284
5285 RxFileSystemDeviceObject = (PRDBSS_DEVICE_OBJECT)&RxSpaceForTheWrappersDeviceObject;
5286 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject, sizeof(RxSpaceForTheWrappersDeviceObject));
5287
5288 RxInitializeLog();
5289 State = 2;
5290
5291 RxGetRegistryParameters(RegistryPath);
5292 RxReadRegistryParameters();
5293
5294 Status = RxInitializeRegistrationStructures();
5295 if (!NT_SUCCESS(Status))
5296 {
5297 _SEH2_LEAVE;
5298 }
5299 State = 1;
5300
5301 RxInitializeDispatcher();
5302
5303 ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
5304
5305 InitializeListHead(&RxIrpsList);
5306 KeInitializeSpinLock(&RxIrpsListSpinLock);
5307
5308 InitializeListHead(&RxActiveContexts);
5309 InitializeListHead(&RxSrvCalldownList);
5310
5311 ExInitializeFastMutex(&RxContextPerFileSerializationMutex);
5312 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex);
5313 KeInitializeMutex(&RxScavengerMutex, 1);
5314 KeInitializeMutex(&RxSerializationMutex, 1);
5315
5316 for (i = 0; i < RxMaximumWorkQueue; ++i)
5317 {
5318 RxFileSystemDeviceObject->PostedRequestCount[i] = 0;
5319 RxFileSystemDeviceObject->OverflowQueueCount[i] = 0;
5320 InitializeListHead(&RxFileSystemDeviceObject->OverflowQueue[i]);
5321 }
5322
5323 KeInitializeSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock);
5324
5325 RxInitializeDispatchVectors(DriverObject);
5326
5327 ExInitializeResourceLite(&RxData.Resource);
5328 RxData.OurProcess = IoGetCurrentProcess();
5329
5330 RxInitializeRxTimer();
5331 }
5332 _SEH2_FINALLY
5333 {
5334 if (!NT_SUCCESS(Status))
5335 {
5336 RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BC4, Status);
5337 RxInitUnwind(DriverObject, State);
5338 }
5339 } _SEH2_END;
5340
5341 /* There are still bits to init - be consider it's fine for now */
5342 #if 0
5343 UNIMPLEMENTED;
5344 return STATUS_NOT_IMPLEMENTED;
5345 #else
5346 return STATUS_SUCCESS;
5347 #endif
5348 }
5349
5350 #if DBG
5351 /*
5352 * @implemented
5353 */
5354 VOID
5355 RxDumpCurrentAccess(
5356 _In_ PSZ where1,
5357 _In_ PSZ where2,
5358 _In_ PSZ wherelogtag,
5359 _In_ PSHARE_ACCESS ShareAccess)
5360 {
5361 PAGED_CODE();
5362 }
5363
5364 /*
5365 * @implemented
5366 */
5367 VOID
5368 RxDumpWantedAccess(
5369 _In_ PSZ where1,
5370 _In_ PSZ where2,
5371 _In_ PSZ wherelogtag,
5372 _In_ ACCESS_MASK DesiredAccess,
5373 _In_ ULONG DesiredShareAccess)
5374 {
5375 PAGED_CODE();
5376 }
5377 #endif
5378
5379 /*
5380 * @implemented
5381 */
5382 BOOLEAN
5383 NTAPI
5384 RxFastIoCheckIfPossible(
5385 PFILE_OBJECT FileObject,
5386 PLARGE_INTEGER FileOffset,
5387 ULONG Length, BOOLEAN Wait,
5388 ULONG LockKey, BOOLEAN CheckForReadOperation,
5389 PIO_STATUS_BLOCK IoStatus,
5390 PDEVICE_OBJECT DeviceObject)
5391 {
5392 PFCB Fcb;
5393 PSRV_OPEN SrvOpen;
5394 LARGE_INTEGER LargeLength;
5395
5396 PAGED_CODE();
5397
5398 /* Get the FCB to validate it */
5399 Fcb = FileObject->FsContext;
5400 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
5401 {
5402 DPRINT1("Not a file, FastIO not possible!\n");
5403 return FALSE;
5404 }
5405
5406 if (FileObject->DeletePending)
5407 {
5408 DPRINT1("File delete pending\n");
5409 return FALSE;
5410 }
5411
5412 /* If there's a pending write operation, deny fast operation */
5413 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
5414 {
5415 DPRINT1("Write operations to be completed\n");
5416 return FALSE;
5417 }
5418
5419 /* Deny read on orphaned node */
5420 SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
5421 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
5422 {
5423 DPRINT1("SRV_OPEN orphaned\n");
5424 return FALSE;
5425 }
5426
5427 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
5428 {
5429 DPRINT1("FCB orphaned\n");
5430 return FALSE;
5431 }
5432
5433 /* If there's a buffering state change pending, deny fast operation (it might change
5434 * cache status)
5435 */
5436 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
5437 {
5438 DPRINT1("Buffering change pending\n");
5439 return FALSE;
5440 }
5441
5442 /* File got renamed/deleted, deny operation */
5443 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
5444 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
5445 {
5446 DPRINT1("File renamed/deleted\n");
5447 return FALSE;
5448 }
5449
5450 /* Process pending change buffering state operations */
5451 FsRtlEnterFileSystem();
5452 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
5453 FsRtlExitFileSystem();
5454
5455 LargeLength.QuadPart = Length;
5456
5457 /* If operation to come is a read operation */
5458 if (CheckForReadOperation)
5459 {
5460 /* Check that read cache is enabled */
5461 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
5462 {
5463 DPRINT1("Read caching disabled\n");
5464 return FALSE;
5465 }
5466
5467 /* Check whether there's a lock conflict */
5468 if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
5469 FileOffset,
5470 &LargeLength,
5471 LockKey,
5472 FileObject,
5473 PsGetCurrentProcess()))
5474 {
5475 DPRINT1("FsRtlFastCheckLockForRead failed\n");
5476 return FALSE;
5477 }
5478
5479 return TRUE;
5480 }
5481
5482 /* Check that write cache is enabled */
5483 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED))
5484 {
5485 DPRINT1("Write caching disabled\n");
5486 return FALSE;
5487 }
5488
5489 /* Check whether there's a lock conflict */
5490 if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock,
5491 FileOffset,
5492 &LargeLength,
5493 LockKey,
5494 FileObject,
5495 PsGetCurrentProcess()))
5496 {
5497 DPRINT1("FsRtlFastCheckLockForWrite failed\n");
5498 return FALSE;
5499 }
5500
5501 return TRUE;
5502 }
5503
5504 BOOLEAN
5505 NTAPI
5506 RxFastIoDeviceControl(
5507 PFILE_OBJECT FileObject,
5508 BOOLEAN Wait,
5509 PVOID InputBuffer OPTIONAL,
5510 ULONG InputBufferLength,
5511 PVOID OutputBuffer OPTIONAL,
5512 ULONG OutputBufferLength,
5513 ULONG IoControlCode,
5514 PIO_STATUS_BLOCK IoStatus,
5515 PDEVICE_OBJECT DeviceObject)
5516 {
5517 /* Only supported IOCTL */
5518 if (IoControlCode == IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
5519 {
5520 UNIMPLEMENTED;
5521 return FALSE;
5522 }
5523 else
5524 {
5525 return FALSE;
5526 }
5527 }
5528
5529 /*
5530 * @implemented
5531 */
5532 BOOLEAN
5533 NTAPI
5534 RxFastIoRead(
5535 PFILE_OBJECT FileObject,
5536 PLARGE_INTEGER FileOffset,
5537 ULONG Length,
5538 BOOLEAN Wait,
5539 ULONG LockKey,
5540 PVOID Buffer,
5541 PIO_STATUS_BLOCK IoStatus,
5542 PDEVICE_OBJECT DeviceObject)
5543 {
5544 BOOLEAN Ret;
5545 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5546
5547 PAGED_CODE();
5548
5549 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
5550 FileObject->FsContext2);
5551 DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
5552
5553 /* Prepare a TLI context */
5554 ASSERT(RxIsThisTheTopLevelIrp(NULL));
5555 RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
5556 (PRDBSS_DEVICE_OBJECT)DeviceObject);
5557
5558 Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
5559 IoStatus, DeviceObject, &TopLevelContext);
5560 if (Ret)
5561 {
5562 DPRINT("Read OK\n");
5563 }
5564 else
5565 {
5566 DPRINT1("Read failed!\n");
5567 }
5568
5569 return Ret;
5570 }
5571
5572 /*
5573 * @implemented
5574 */
5575 BOOLEAN
5576 NTAPI
5577 RxFastIoWrite(
5578 PFILE_OBJECT FileObject,
5579 PLARGE_INTEGER FileOffset,
5580 ULONG Length,
5581 BOOLEAN Wait,
5582 ULONG LockKey,
5583 PVOID Buffer,
5584 PIO_STATUS_BLOCK IoStatus,
5585 PDEVICE_OBJECT DeviceObject)
5586 {
5587 PFOBX Fobx;
5588 BOOLEAN Ret;
5589 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5590
5591 PAGED_CODE();
5592
5593 Fobx = (PFOBX)FileObject->FsContext2;
5594 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE))
5595 {
5596 return FALSE;
5597 }
5598
5599 DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext,
5600 FileObject->FsContext2);
5601 DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
5602
5603 /* Prepare a TLI context */
5604 ASSERT(RxIsThisTheTopLevelIrp(NULL));
5605 RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
5606 (PRDBSS_DEVICE_OBJECT)DeviceObject);
5607
5608 Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
5609 IoStatus, DeviceObject, &TopLevelContext);
5610 if (Ret)
5611 {
5612 DPRINT("Write OK\n");
5613 }
5614 else
5615 {
5616 DPRINT1("Write failed!\n");
5617 }
5618
5619 return Ret;
5620 }
5621
5622 NTSTATUS
5623 RxFindOrCreateFcb(
5624 PRX_CONTEXT RxContext,
5625 PUNICODE_STRING NetRootName)
5626 {
5627 PFCB Fcb;
5628 ULONG Version;
5629 NTSTATUS Status;
5630 PNET_ROOT NetRoot;
5631 PV_NET_ROOT VNetRoot;
5632 BOOLEAN TableAcquired, AcquiredExclusive;
5633
5634 PAGED_CODE();
5635
5636 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
5637 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
5638 ASSERT(NetRoot == VNetRoot->NetRoot);
5639
5640 Status = STATUS_SUCCESS;
5641 AcquiredExclusive = FALSE;
5642
5643 RxAcquireFcbTableLockShared(&NetRoot->FcbTable, TRUE);
5644 TableAcquired = TRUE;
5645 Version = NetRoot->FcbTable.Version;
5646
5647 /* Look for a cached FCB */
5648 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5649 if (Fcb == NULL)
5650 {
5651 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName);
5652 }
5653 else
5654 {
5655 DPRINT("FCB found for %wZ\n", &Fcb->FcbTableEntry.Path);
5656 /* If FCB was to be orphaned, consider it as not suitable */
5657 if (Fcb->fShouldBeOrphaned)
5658 {
5659 RxDereferenceNetFcb(Fcb);
5660 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5661
5662 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5663 TableAcquired = TRUE;
5664 AcquiredExclusive = TRUE;
5665
5666 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5667 if (Fcb != NULL && Fcb->fShouldBeOrphaned)
5668 {
5669 RxOrphanThisFcb(Fcb);
5670 RxDereferenceNetFcb(Fcb);
5671 Fcb = NULL;
5672 }
5673 }
5674 }
5675
5676 /* If FCB was not found or is not covering full path, prepare for more work */
5677 if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
5678 {
5679 if (Fcb != NULL)
5680 {
5681 DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb->FcbTableEntry.Path, NetRootName);
5682 }
5683
5684 if (!AcquiredExclusive)
5685 {
5686 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5687 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5688 TableAcquired = TRUE;
5689 }
5690
5691 /* If FCB table was updated in between, re-attempt a lookup */
5692 if (NetRoot->FcbTable.Version != Version)
5693 {
5694 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5695 if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
5696 {
5697 Fcb = NULL;
5698 }
5699 }
5700 }
5701
5702 /* Allocate the FCB */
5703 _SEH2_TRY
5704 {
5705 if (Fcb == NULL)
5706 {
5707 Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName);
5708 if (Fcb == NULL)
5709 {
5710 Status = STATUS_INSUFFICIENT_RESOURCES;
5711 }
5712 else
5713 {
5714 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5715 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5716 }
5717 }
5718 }
5719 _SEH2_FINALLY
5720 {
5721 if (_SEH2_AbnormalTermination())
5722 {
5723 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5724 TableAcquired = FALSE;
5725
5726 if (Fcb != NULL)
5727 {
5728 RxTransitionNetFcb(Fcb, Condition_Bad);
5729
5730 ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
5731 if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0)
5732 {
5733 ExReleaseResourceLite(Fcb->Header.Resource);
5734 }
5735 }
5736 }
5737 }
5738 _SEH2_END;
5739
5740 if (TableAcquired)
5741 {
5742 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5743 }
5744
5745 if (!NT_SUCCESS(Status))
5746 {
5747 return Status;
5748 }
5749
5750 RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
5751 DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
5752
5753 if (!RxContext->Create.FcbAcquired)
5754 {
5755 RxWaitForStableNetFcb(Fcb, RxContext);
5756 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5757 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5758 }
5759
5760 return Status;
5761 }
5762
5763 NTSTATUS
5764 RxFirstCanonicalize(
5765 PRX_CONTEXT RxContext,
5766 PUNICODE_STRING FileName,
5767 PUNICODE_STRING CanonicalName,
5768 PNET_ROOT_TYPE NetRootType)
5769 {
5770 NTSTATUS Status;
5771 NET_ROOT_TYPE Type;
5772 BOOLEAN UncName, PrependString, IsSpecial;
5773 USHORT CanonicalLength;
5774 UNICODE_STRING SessionIdString;
5775 WCHAR SessionIdBuffer[16];
5776
5777 PAGED_CODE();
5778
5779 Type = NET_ROOT_WILD;
5780 PrependString = FALSE;
5781 IsSpecial = FALSE;
5782 UncName = FALSE;
5783 Status = STATUS_SUCCESS;
5784
5785 /* Name has to contain at least \\ */
5786 if (FileName->Length < 2 * sizeof(WCHAR))
5787 {
5788 return STATUS_OBJECT_NAME_INVALID;
5789 }
5790
5791 /* First easy check, is that a path with a name? */
5792 CanonicalLength = FileName->Length;
5793 if (FileName->Length > 5 * sizeof(WCHAR))
5794 {
5795 if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';')
5796 {
5797 if (FileName->Buffer[3] == ':')
5798 {
5799 Type = NET_ROOT_DISK;
5800 }
5801 else
5802 {
5803 Type = NET_ROOT_PRINT;
5804 }
5805 }
5806 }
5807
5808 /* Nope, attempt deeper parsing */
5809 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';')
5810 {
5811 ULONG SessionId;
5812 PWSTR FirstSlash, EndOfString;
5813
5814 SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME);
5815 UncName = TRUE;
5816
5817 /* The lack of drive letter will be replaced by session ID */
5818 SessionId = RxGetSessionId(RxContext->CurrentIrpSp);
5819 RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer));
5820 RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
5821
5822 EndOfString = Add2Ptr(FileName->Buffer, FileName->Length);
5823 for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash)
5824 {
5825 if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR)
5826 {
5827 break;
5828 }
5829 }
5830
5831 if (EndOfString - FirstSlash <= sizeof(WCHAR))
5832 {
5833 Status = STATUS_OBJECT_NAME_INVALID;
5834 }
5835 else
5836 {
5837 UNIMPLEMENTED;
5838 DPRINT1("WARNING: Assuming not special + disk!\n");
5839 Type = NET_ROOT_DISK;
5840 Status = STATUS_SUCCESS;
5841 //Status = STATUS_NOT_IMPLEMENTED;
5842 /* Should be check against IPC, mailslot, and so on */
5843 }
5844 }
5845
5846 /* Update net root type with our deduced one */
5847 *NetRootType = Type;
5848 DPRINT("Returning type: %x\n", Type);
5849
5850 if (!NT_SUCCESS(Status))
5851 {
5852 return Status;
5853 }
5854
5855 /* Do we have to prepend session ID? */
5856 if (UncName)
5857 {
5858 if (!IsSpecial)
5859 {
5860 PrependString = TRUE;
5861 CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR);
5862 }
5863 }
5864
5865 /* If not UNC path, we should preprend stuff */
5866 if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\')
5867 {
5868 return STATUS_OBJECT_PATH_INVALID;
5869 }
5870
5871 /* Allocate the buffer */
5872 Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength);
5873 if (!NT_SUCCESS(Status))
5874 {
5875 return Status;
5876 }
5877
5878 /* We don't support that case, we always return disk */
5879 if (IsSpecial)
5880 {
5881 ASSERT(CanonicalName->Length == CanonicalLength);
5882 UNIMPLEMENTED;
5883 Status = STATUS_NOT_IMPLEMENTED;
5884 }
5885 else
5886 {
5887 /* If we have to prepend, go ahead */
5888 if (PrependString)
5889 {
5890 CanonicalName->Buffer[0] = '\\';
5891 CanonicalName->Buffer[1] = ';';
5892 CanonicalName->Buffer[2] = ':';
5893 CanonicalName->Length = 3 * sizeof(WCHAR);
5894 RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString);
5895 RtlAppendUnicodeStringToString(CanonicalName, FileName);
5896
5897 DPRINT1("CanonicalName: %wZ\n", CanonicalName);
5898 }
5899 /* Otherwise, that's a simple copy */
5900 else
5901 {
5902 RtlCopyUnicodeString(CanonicalName, FileName);
5903 }
5904 }
5905
5906 return Status;
5907 }
5908
5909 /*
5910 * @implemented
5911 */
5912 VOID
5913 RxFreeCanonicalNameBuffer(
5914 PRX_CONTEXT Context)
5915 {
5916 /* These two buffers are always the same */
5917 ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
5918
5919 if (Context->Create.CanonicalNameBuffer != NULL)
5920 {
5921 RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
5922 Context->Create.CanonicalNameBuffer = NULL;
5923 Context->AlsoCanonicalNameBuffer = NULL;
5924 }
5925
5926 ASSERT(Context->AlsoCanonicalNameBuffer == NULL);
5927 }
5928
5929 NTSTATUS
5930 RxFsdCommonDispatch(
5931 PRX_FSD_DISPATCH_VECTOR DispatchVector,
5932 UCHAR MajorFunction,
5933 PIO_STACK_LOCATION Stack,
5934 PFILE_OBJECT FileObject,
5935 PIRP Irp,
5936 PRDBSS_DEVICE_OBJECT RxDeviceObject)
5937 {
5938 KIRQL OldIrql;
5939 NTSTATUS Status;
5940 PRX_CONTEXT Context;
5941 UCHAR MinorFunction;
5942 PFILE_OBJECT StackFileObject;
5943 PRX_FSD_DISPATCH DispatchFunc;
5944 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5945 BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
5946
5947 Status = STATUS_SUCCESS;
5948
5949 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
5950
5951 FsRtlEnterFileSystem();
5952
5953 TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
5954
5955 _SEH2_TRY
5956 {
5957 CanWait = TRUE;
5958 Closing = FALSE;
5959 PostRequest = FALSE;
5960 SetCancelRoutine = TRUE;
5961 MinorFunction = Stack->MinorFunction;
5962 /* Can we wait? */
5963 switch (MajorFunction)
5964 {
5965 case IRP_MJ_FILE_SYSTEM_CONTROL:
5966 if (FileObject != NULL)
5967 {
5968 CanWait = IoIsOperationSynchronous(Irp);
5969 }
5970 else
5971 {
5972 CanWait = TRUE;
5973 }
5974 break;
5975
5976 case IRP_MJ_READ:
5977 case IRP_MJ_WRITE:
5978 case IRP_MJ_QUERY_INFORMATION:
5979 case IRP_MJ_SET_INFORMATION:
5980 case IRP_MJ_QUERY_EA:
5981 case IRP_MJ_SET_EA:
5982 case IRP_MJ_FLUSH_BUFFERS:
5983 case IRP_MJ_QUERY_VOLUME_INFORMATION:
5984 case IRP_MJ_SET_VOLUME_INFORMATION:
5985 case IRP_MJ_DIRECTORY_CONTROL:
5986 case IRP_MJ_DEVICE_CONTROL:
5987 case IRP_MJ_LOCK_CONTROL:
5988 case IRP_MJ_QUERY_SECURITY:
5989 case IRP_MJ_SET_SECURITY:
5990 CanWait = IoIsOperationSynchronous(Irp);
5991 break;
5992
5993 case IRP_MJ_CLOSE:
5994 case IRP_MJ_CLEANUP:
5995 Closing = TRUE;
5996 SetCancelRoutine = FALSE;
5997 break;
5998
5999 default:
6000 break;
6001 }
6002
6003 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
6004 /* Should we stop it right now, or mini-rdr deserves to know? */
6005 PassToDriver = TRUE;
6006 if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE)
6007 {
6008 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing)
6009 {
6010 PassToDriver = FALSE;
6011 Status = STATUS_REDIRECTOR_NOT_STARTED;
6012 DPRINT1("Not started!\n");
6013 }
6014 }
6015 else
6016 {
6017 if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL))
6018 {
6019 PassToDriver = FALSE;
6020 Status = STATUS_REDIRECTOR_NOT_STARTED;
6021 DPRINT1("Not started!\n");
6022 }
6023 }
6024 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
6025
6026 StackFileObject = Stack->FileObject;
6027 /* Make sure we don't deal with orphaned stuff */
6028 if (StackFileObject != NULL && StackFileObject->FsContext != NULL)
6029 {
6030 if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) &&
6031 StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
6032 StackFileObject->FsContext != &RxDeviceFCB)
6033 {
6034 PFCB Fcb;
6035 PFOBX Fobx;
6036
6037 Fcb = StackFileObject->FsContext;
6038 Fobx = StackFileObject->FsContext2;
6039
6040 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) ||
6041 ((Fobx != NULL) && BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED)))
6042 {
6043 if (Closing)
6044 {
6045 PassToDriver = TRUE;
6046 }
6047 else
6048 {
6049 PassToDriver = FALSE;
6050 Status = STATUS_UNEXPECTED_NETWORK_ERROR;
6051 DPRINT1("Operation on orphaned FCB: %p\n", Fcb);
6052 }
6053 }
6054 }
6055 }
6056
6057 /* Did we receive a close request whereas we're stopping? */
6058 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing)
6059 {
6060 PFCB Fcb;
6061
6062 Fcb = StackFileObject->FsContext;
6063
6064 DPRINT1("Close received after stop\n");
6065 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6066 Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
6067
6068 if (Fcb != NULL && Fcb != &RxDeviceFCB &&
6069 NodeTypeIsFcb(Fcb))
6070 {
6071 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6072 Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path);
6073 }
6074 }
6075
6076 /* Should we stop the whole thing now? */
6077 if (!PassToDriver)
6078 {
6079 if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE)
6080 {
6081 IoMarkIrpPending(Irp);
6082 Irp->IoStatus.Status = Status;
6083 Irp->IoStatus.Information = 0;
6084 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6085 Status = STATUS_PENDING;
6086 }
6087 else
6088 {
6089 Irp->IoStatus.Status = Status;
6090 Irp->IoStatus.Information = 0;
6091 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6092 }
6093
6094 _SEH2_LEAVE;
6095 }
6096
6097 /* No? Allocate a context to deal with the mini-rdr */
6098 Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0));
6099 if (Context == NULL)
6100 {
6101 Status = STATUS_INSUFFICIENT_RESOURCES;
6102 RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES);
6103 _SEH2_LEAVE;
6104 }
6105
6106 /* Set cancel routine if required */
6107 if (SetCancelRoutine)
6108 {
6109 IoAcquireCancelSpinLock(&OldIrql);
6110 IoSetCancelRoutine(Irp, RxCancelRoutine);
6111 }
6112 else
6113 {
6114 IoAcquireCancelSpinLock(&OldIrql);
6115 IoSetCancelRoutine(Irp, NULL);
6116 }
6117 IoReleaseCancelSpinLock(OldIrql);
6118
6119 ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6120
6121 Irp->IoStatus.Status = STATUS_SUCCESS;
6122 Irp->IoStatus.Information = 0;
6123 /* Get the dispatch routine */
6124 DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
6125
6126 if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE)
6127 {
6128 /* Handle the complete MDL case */
6129 if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE))
6130 {
6131 DispatchFunc = RxCompleteMdl;
6132 }
6133 else
6134 {
6135 /* Do we have to post request? */
6136 if (BooleanFlagOn(MinorFunction, IRP_MN_DPC))
6137 {
6138 PostRequest = TRUE;
6139 }
6140 else
6141 {
6142 /* Our read function needs stack, make sure we won't overflow,
6143 * otherwise, post the request
6144 */
6145 if (MajorFunction == IRP_MJ_READ)
6146 {
6147 if (IoGetRemainingStackSize() < 0xE00)
6148 {
6149 Context->PendingReturned = TRUE;
6150 Status = RxPostStackOverflowRead(Context);
6151 if (Status != STATUS_PENDING)
6152 {
6153 Context->PendingReturned = FALSE;
6154 RxCompleteAsynchronousRequest(Context, Status);
6155 }
6156
6157 _SEH2_LEAVE;
6158 }
6159 }
6160 }
6161 }
6162 }
6163
6164 Context->ResumeRoutine = DispatchFunc;
6165 /* There's a dispatch routine? Time to dispatch! */
6166 if (DispatchFunc != NULL)
6167 {
6168 Context->PendingReturned = TRUE;
6169 if (PostRequest)
6170 {
6171 Status = RxFsdPostRequest(Context);
6172 }
6173 else
6174 {
6175 /* Retry as long as we have */
6176 do
6177 {
6178 Status = DispatchFunc(Context);
6179 }
6180 while (Status == STATUS_RETRY);
6181
6182 if (Status == STATUS_PENDING)
6183 {
6184 _SEH2_LEAVE;
6185 }
6186
6187 /* Sanity check: did someone mess with our context? */
6188 if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack ||
6189 Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction)
6190 {
6191 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context);
6192 DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp);
6193 DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack);
6194 DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction);
6195 DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction);
6196 }
6197 Context->PendingReturned = FALSE;
6198 Status = RxCompleteAsynchronousRequest(Context, Status);
6199 }
6200 }
6201 else
6202 {
6203 Status = STATUS_NOT_IMPLEMENTED;
6204 }
6205 }
6206 _SEH2_FINALLY
6207 {
6208 if (TopLevel)
6209 {
6210 RxUnwindTopLevelIrp(&TopLevelContext);
6211 }
6212
6213 FsRtlExitFileSystem();
6214 }
6215 _SEH2_END;
6216
6217 DPRINT("RxFsdDispatch, Status: %lx\n", Status);
6218 return Status;
6219 }
6220
6221 /*
6222 * @implemented
6223 */
6224 NTSTATUS
6225 NTAPI
6226 RxFsdDispatch(
6227 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
6228 IN PIRP Irp)
6229 {
6230 PFCB Fcb;
6231 PIO_STACK_LOCATION Stack;
6232 PRX_FSD_DISPATCH_VECTOR DispatchVector;
6233
6234 PAGED_CODE();
6235
6236 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
6237
6238 Stack = IoGetCurrentIrpStackLocation(Irp);
6239
6240 /* Dispatch easy case */
6241 if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
6242 {
6243 return RxSystemControl(RxDeviceObject, Irp);
6244 }
6245
6246 /* Bail out broken cases */
6247 if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ||
6248 Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE)
6249 {
6250 IoMarkIrpPending(Irp);
6251 Irp->IoStatus.Information = 0;
6252 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
6253 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6254 return STATUS_PENDING;
6255 }
6256
6257 /* Immediately handle create */
6258 if (Stack->MajorFunction == IRP_MJ_CREATE)
6259 {
6260 return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6261 }
6262
6263 /* If not a creation, we must have at least a FO with a FCB */
6264 if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL)
6265 {
6266 IoMarkIrpPending(Irp);
6267 Irp->IoStatus.Information = 0;
6268 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6269 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6270 return STATUS_PENDING;
6271 }
6272
6273 /* Set the dispatch vector if required */
6274 Fcb = Stack->FileObject->FsContext;
6275 if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL)
6276 {
6277 DispatchVector = &RxFsdDispatchVector[0];
6278 }
6279 else
6280 {
6281 DispatchVector = Fcb->PrivateDispatchVector;
6282 }
6283
6284 /* Device cannot accept such requests */
6285 if (RxDeviceObject == RxFileSystemDeviceObject)
6286 {
6287 IoMarkIrpPending(Irp);
6288 Irp->IoStatus.Information = 0;
6289 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6290 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6291 return STATUS_PENDING;
6292 }
6293
6294 /* Dispatch for real! */
6295 return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6296 }
6297
6298 /*
6299 * @implemented
6300 */
6301 NTSTATUS
6302 RxFsdPostRequest(
6303 IN PRX_CONTEXT RxContext)
6304 {
6305 /* Initialize posting if required */
6306 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
6307 {
6308 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
6309 }
6310
6311 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6312 RxContext->MinorFunction, RxContext,
6313 RxContext->CurrentIrp, RxContext->LastExecutionThread,
6314 RxContext->SerialNumber);
6315
6316 RxAddToWorkque(RxContext, RxContext->CurrentIrp);
6317 return STATUS_PENDING;
6318 }
6319
6320 /*
6321 * @implemented
6322 */
6323 VOID
6324 NTAPI
6325 RxFspDispatch(
6326 IN PVOID Context)
6327 {
6328 KIRQL EntryIrql;
6329 WORK_QUEUE_TYPE Queue;
6330 PRDBSS_DEVICE_OBJECT VolumeDO;
6331 PRX_CONTEXT RxContext, EntryContext;
6332
6333 PAGED_CODE();
6334
6335 RxContext = Context;
6336 EntryContext = Context;
6337 /* Save IRQL at entry for later checking */
6338 EntryIrql = KeGetCurrentIrql();
6339
6340 /* No FO, deal with device */
6341 if (RxContext->CurrentIrpSp->FileObject != NULL)
6342 {
6343 VolumeDO = RxFileSystemDeviceObject;
6344 }
6345 else
6346 {
6347 VolumeDO = NULL;
6348 }
6349
6350 /* Which queue to used for delayed? */
6351 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE))
6352 {
6353 Queue = DelayedWorkQueue;
6354 }
6355 else
6356 {
6357 ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
6358 Queue = CriticalWorkQueue;
6359 }
6360
6361 do
6362 {
6363 PIRP Irp;
6364 NTSTATUS Status;
6365 BOOLEAN RecursiveCall;
6366 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
6367
6368 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6369 ASSERT(!RxContext->PostRequest);
6370
6371 RxContext->LastExecutionThread = PsGetCurrentThread();
6372 SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
6373
6374 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext->MinorFunction,
6375 RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
6376 RxContext->SerialNumber);
6377
6378 Irp = RxContext->CurrentIrp;
6379
6380 FsRtlEnterFileSystem();
6381
6382 RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
6383 RxTryToBecomeTheTopLevelIrp(&TopLevelContext,
6384 (RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp),
6385 RxContext->RxDeviceObject, TRUE);
6386
6387 ASSERT(RxContext->ResumeRoutine != NULL);
6388
6389 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL)
6390 {
6391 ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ));
6392 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
6393 }
6394
6395 /* Call the resume routine */
6396 do
6397 {
6398 BOOLEAN NoComplete;
6399
6400 NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
6401
6402 Status = RxContext->ResumeRoutine(RxContext);
6403 if (!NoComplete && Status != STATUS_PENDING)
6404 {
6405 if (Status != STATUS_RETRY)
6406 {
6407 Status = RxCompleteRequest(RxContext, Status);
6408 }
6409 }
6410 }
6411 while (Status == STATUS_RETRY);
6412
6413 RxUnwindTopLevelIrp(&TopLevelContext);
6414 FsRtlExitFileSystem();
6415
6416 if (VolumeDO != NULL)
6417 {
6418 RxContext = RxRemoveOverflowEntry(VolumeDO, Queue);
6419 }
6420 else
6421 {
6422 RxContext = NULL;
6423 }
6424 } while (RxContext != NULL);
6425
6426 /* Did we mess with IRQL? */
6427 if (KeGetCurrentIrql() >= APC_LEVEL)
6428 {
6429 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql);
6430 }
6431 }
6432
6433 /*
6434 * @implemented
6435 */
6436 ULONG
6437 RxGetNetworkProviderPriority(
6438 PUNICODE_STRING DeviceName)
6439 {
6440 PAGED_CODE();
6441 return 1;
6442 }
6443
6444 /*
6445 * @implemented
6446 */
6447 VOID
6448 NTAPI
6449 RxGetRegistryParameters(
6450 IN PUNICODE_STRING RegistryPath)
6451 {
6452 USHORT i;
6453 NTSTATUS Status;
6454 UCHAR Buffer[0x400];
6455 HANDLE DriverHandle, KeyHandle;
6456 UNICODE_STRING KeyName, OutString;
6457 OBJECT_ATTRIBUTES ObjectAttributes;
6458
6459 PAGED_CODE();
6460
6461 InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
6462 Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6463 if (!NT_SUCCESS(Status))
6464 {
6465 return;
6466 }
6467
6468 RtlInitUnicodeString(&KeyName, L"Parameters");
6469 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE);
6470 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6471 if (NT_SUCCESS(Status))
6472 {
6473 /* The only parameter we deal with is InitialDebugString */
6474 RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0);
6475 if (OutString.Length != 0 && OutString.Length < 0x140)
6476 {
6477 PWSTR Read;
6478 PSTR Write;
6479
6480 Read = OutString.Buffer;
6481 Write = (PSTR)OutString.Buffer;
6482 for (i = 0; i < OutString.Length; ++i)
6483 {
6484 *Read = *Write;
6485 ++Write;
6486 *Write = ANSI_NULL;
6487 ++Read;
6488 }
6489
6490 /* Which is a string we'll just write out */
6491 DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer);
6492 RxDebugControlCommand((PSTR)OutString.Buffer);
6493 }
6494
6495 ZwClose(KeyHandle);
6496 }
6497
6498 ZwClose(DriverHandle);
6499 }
6500
6501 /*
6502 * @implemented
6503 */
6504 ULONG
6505 RxGetSessionId(
6506 IN PIO_STACK_LOCATION IrpSp)
6507 {
6508 ULONG SessionId;
6509 PACCESS_TOKEN Token;
6510 PIO_SECURITY_CONTEXT SecurityContext;
6511
6512 PAGED_CODE();
6513
6514 /* If that's not a prefix claim, not an open request, session id will be 0 */
6515 if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH)
6516 {
6517 if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL)
6518 {
6519 return 0;
6520 }
6521
6522 SecurityContext = IrpSp->Parameters.Create.SecurityContext;
6523 }
6524 else
6525 {
6526 SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext;
6527 }
6528
6529 /* Query the session id */
6530 Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext);
6531 SeQuerySessionIdToken(Token, &SessionId);
6532
6533 return SessionId;
6534 }
6535
6536 /*
6537 * @implemented
6538 */
6539 NTSTATUS
6540 NTAPI
6541 RxGetStringRegistryParameter(
6542 IN HANDLE KeyHandle,
6543 IN PCWSTR KeyName,
6544 OUT PUNICODE_STRING OutString,
6545 IN PUCHAR Buffer,
6546 IN ULONG BufferLength,
6547 IN BOOLEAN LogFailure)
6548 {
6549 NTSTATUS Status;
6550 ULONG ResultLength;
6551 UNICODE_STRING KeyString;
6552
6553 PAGED_CODE();
6554
6555 RtlInitUnicodeString(&KeyString, KeyName);
6556 Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength);
6557 OutString->Length = 0;
6558 OutString->Buffer = 0;
6559 if (!NT_SUCCESS(Status))
6560 {
6561 if (LogFailure)
6562 {
6563 RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status);
6564 }
6565
6566 return Status;
6567 }
6568
6569 OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
6570 OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL);
6571 OutString->MaximumLength = OutString->Length;
6572
6573 return STATUS_SUCCESS;
6574 }
6575
6576 /*
6577 * @implemented
6578 */
6579 PRDBSS_DEVICE_OBJECT
6580 RxGetTopDeviceObjectIfRdbssIrp(
6581 VOID)
6582 {
6583 PIRP TopLevelIrp;
6584 PRDBSS_DEVICE_OBJECT TopDevice = NULL;
6585
6586 TopLevelIrp = IoGetTopLevelIrp();
6587 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6588 {
6589 TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject;
6590 }
6591
6592 return TopDevice;
6593 }
6594
6595 /*
6596 * @implemented
6597 */
6598 PIRP
6599 RxGetTopIrpIfRdbssIrp(
6600 VOID)
6601 {
6602 PIRP Irp = NULL;
6603 PRX_TOPLEVELIRP_CONTEXT TopLevel;
6604
6605 TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
6606 if (RxIsThisAnRdbssTopLevelContext(TopLevel))
6607 {
6608 Irp = TopLevel->Irp;
6609 }
6610
6611 return Irp;
6612 }
6613
6614 /*
6615 * @implemented
6616 */
6617 LUID
6618 RxGetUid(
6619 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
6620 {
6621 LUID Luid;
6622 PACCESS_TOKEN Token;
6623
6624 PAGED_CODE();
6625
6626 Token = SeQuerySubjectContextToken(SubjectSecurityContext);
6627 SeQueryAuthenticationIdToken(Token, &Luid);
6628
6629 return Luid;
6630 }
6631
6632 VOID
6633 NTAPI
6634 RxIndicateChangeOfBufferingStateForSrvOpen(
6635 PMRX_SRV_CALL SrvCall,
6636 PMRX_SRV_OPEN SrvOpen,
6637 PVOID SrvOpenKey,
6638 PVOID Context)
6639 {
6640 UNIMPLEMENTED;
6641 }
6642
6643 VOID
6644 NTAPI
6645 RxInitializeDebugSupport(
6646 VOID)
6647 {
6648 UNIMPLEMENTED;
6649 }
6650
6651 /*
6652 * @implemented
6653 */
6654 VOID
6655 NTAPI
6656 RxInitializeDispatchVectors(
6657 PDRIVER_OBJECT DriverObject)
6658 {
6659 USHORT i;
6660
6661 PAGED_CODE();
6662
6663 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
6664 {
6665 DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
6666 }
6667
6668 RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector;
6669 ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6670 ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6671
6672 DriverObject->FastIoDispatch = &RxFastIoDispatch;
6673 RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch);
6674 RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
6675 RxFastIoDispatch.FastIoRead = RxFastIoRead;
6676 RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
6677 RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
6678 RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
6679 RxFastIoDispatch.FastIoLock = NULL;
6680 RxFastIoDispatch.FastIoUnlockSingle = NULL;
6681 RxFastIoDispatch.FastIoUnlockAll = NULL;
6682 RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
6683 RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
6684 RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
6685 RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
6686 RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
6687 RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
6688
6689 RxInitializeTopLevelIrpPackage();
6690
6691 RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite;
6692 RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite;
6693 RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead;
6694 RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
6695
6696 RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire;
6697 RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease;
6698 RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire;
6699 RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;
6700 }
6701
6702 NTSTATUS
6703 NTAPI
6704 RxInitializeLog(
6705 VOID)
6706 {
6707 UNIMPLEMENTED;
6708 return STATUS_NOT_IMPLEMENTED;
6709 }
6710
6711 /*
6712 * @implemented
6713 */
6714 VOID
6715 RxInitializeMinirdrDispatchTable(
6716 IN PDRIVER_OBJECT DriverObject)
6717 {
6718 PAGED_CODE();
6719 }
6720
6721 /*
6722 * @implemented
6723 */
6724 NTSTATUS
6725 NTAPI
6726 RxInitializeRegistrationStructures(
6727 VOID)
6728 {
6729 PAGED_CODE();
6730
6731 ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
6732 RxData.NumberOfMinirdrsRegistered = 0;
6733 RxData.NumberOfMinirdrsStarted = 0;
6734 InitializeListHead(&RxData.RegisteredMiniRdrs);
6735
6736 return STATUS_SUCCESS;
6737 }
6738
6739 /*
6740 * @implemented
6741 */
6742 VOID
6743 NTAPI
6744 RxInitializeTopLevelIrpPackage(
6745 VOID)
6746 {
6747 KeInitializeSpinLock(&TopLevelIrpSpinLock);
6748 InitializeListHead(&TopLevelIrpAllocatedContextsList);
6749 }
6750
6751 VOID
6752 NTAPI
6753 RxInitUnwind(
6754 PDRIVER_OBJECT DriverObject,
6755 USHORT State)
6756 {
6757 UNIMPLEMENTED;
6758 }
6759
6760 /*
6761 * @implemented
6762 */
6763 BOOLEAN
6764 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6765 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6766 {
6767 KIRQL OldIrql;
6768 PLIST_ENTRY NextEntry;
6769 BOOLEAN Found = FALSE;
6770 PRX_TOPLEVELIRP_CONTEXT ListContext;
6771
6772 /* Browse all the allocated TLC to find ours */
6773 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
6774 for (NextEntry = TopLevelIrpAllocatedContextsList.Flink;
6775 NextEntry != &TopLevelIrpAllocatedContextsList;
6776 NextEntry = NextEntry->Flink)
6777 {
6778 ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry);
6779 ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6780 ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6781
6782 /* Found! */
6783 if (ListContext == TopLevelContext)
6784 {
6785 Found = TRUE;
6786 break;
6787 }
6788 }
6789 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
6790
6791 return Found;
6792 }
6793
6794 /*
6795 * @implemented
6796 */
6797 BOOLEAN
6798 RxIsOkToPurgeFcb(
6799 PFCB Fcb)
6800 {
6801 PLIST_ENTRY Entry;
6802
6803 /* No associated SRV_OPEN, it's OK to purge */
6804 if (IsListEmpty(&Fcb->SrvOpenList))
6805 {
6806 return TRUE;
6807 }
6808
6809 /* Only allow to purge if all the associated SRV_OPEN
6810 * - have no outstanding opens ongoing
6811 * - have only read attribute set
6812 */
6813 for (Entry = Fcb->SrvOpenList.Flink;
6814 Entry != &Fcb->SrvOpenList;
6815 Entry = Entry->Flink)
6816 {
6817 PSRV_OPEN SrvOpen;
6818
6819 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
6820
6821 /* Failing previous needs, don't allow purge */
6822 if (SrvOpen->UncleanFobxCount != 0 ||
6823 (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
6824 {
6825 return FALSE;
6826 }
6827 }
6828
6829 /* All correct, allow purge */
6830 return TRUE;
6831 }
6832
6833 /*
6834 * @implemented
6835 */
6836 BOOLEAN
6837 RxIsThisAnRdbssTopLevelContext(
6838 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6839 {
6840 ULONG_PTR StackTop, StackBottom;
6841
6842 /* Bail out for flags */
6843 if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP)
6844 {
6845 return FALSE;
6846 }
6847
6848 /* Is our provided TLC allocated on stack? */
6849 IoGetStackLimits(&StackTop, &StackBottom);
6850 if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) &&
6851 (ULONG_PTR)TopLevelContext >= StackTop)
6852 {
6853 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6854 if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)
6855 {
6856 return TRUE;
6857 }
6858
6859 return FALSE;
6860 }
6861
6862 /* No, use the helper function */
6863 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);
6864 }
6865
6866 /*
6867 * @implemented
6868 */
6869 BOOLEAN
6870 RxIsThisTheTopLevelIrp(
6871 IN PIRP Irp)
6872 {
6873 PIRP TopLevelIrp;
6874
6875 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6876 TopLevelIrp = IoGetTopLevelIrp();
6877 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6878 {
6879 TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp;
6880 }
6881
6882 return (TopLevelIrp == Irp);
6883 }
6884
6885 NTSTATUS
6886 NTAPI
6887 RxLockOperationCompletion(
6888 IN PVOID Context,
6889 IN PIRP Irp)
6890 {
6891 UNIMPLEMENTED;
6892 return STATUS_NOT_IMPLEMENTED;
6893 }
6894
6895 /*
6896 * @implemented
6897 */
6898 VOID
6899 NTAPI
6900 RxLogEventDirect(
6901 IN PRDBSS_DEVICE_OBJECT DeviceObject,
6902 IN PUNICODE_STRING OriginatorId,
6903 IN ULONG EventId,
6904 IN NTSTATUS Status,
6905 IN ULONG Line)
6906 {
6907 PUNICODE_STRING Originator = OriginatorId;
6908 LARGE_INTEGER LargeLine;
6909
6910 /* Set optional parameters */
6911 LargeLine.QuadPart = Line;
6912 if (OriginatorId == NULL || OriginatorId->Length == 0)
6913 {
6914 Originator = (PUNICODE_STRING)&unknownId;
6915 }
6916
6917 /* And log */
6918 RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);
6919 }
6920
6921 VOID
6922 NTAPI
6923 RxLogEventWithAnnotation(
6924 IN PRDBSS_DEVICE_OBJECT DeviceObject,
6925 IN ULONG EventId,
6926 IN NTSTATUS Status,
6927 IN PVOID DataBuffer,
6928 IN USHORT DataBufferLength,
6929 IN PUNICODE_STRING Annotation,
6930 IN ULONG AnnotationCount)
6931 {
6932 UNIMPLEMENTED;
6933 }
6934
6935 NTSTATUS
6936 NTAPI
6937 RxLowIoCompletion(
6938 PRX_CONTEXT RxContext)
6939 {
6940 UNIMPLEMENTED;
6941 return STATUS_NOT_IMPLEMENTED;
6942 }
6943
6944 /*
6945 * @implemented
6946 */
6947 NTSTATUS
6948 NTAPI
6949 RxLowIoIoCtlShellCompletion(
6950 PRX_CONTEXT RxContext)
6951 {
6952 PIRP Irp;
6953 NTSTATUS Status;
6954
6955 PAGED_CODE();
6956
6957 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
6958
6959 Irp = RxContext->CurrentIrp;
6960 Status = RxContext->IoStatusBlock.Status;
6961
6962 /* Set information and status */
6963 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
6964 {
6965 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
6966 }
6967
6968 Irp->IoStatus.Status = Status;
6969
6970 return Status;
6971 }
6972
6973 NTSTATUS
6974 RxLowIoLockControlShell(
6975 IN PRX_CONTEXT RxContext)
6976 {
6977 UNIMPLEMENTED;
6978 return STATUS_NOT_IMPLEMENTED;
6979 }
6980
6981 /*
6982 * @implemented
6983 */
6984 NTSTATUS
6985 NTAPI
6986 RxLowIoNotifyChangeDirectoryCompletion(
6987 PRX_CONTEXT RxContext)
6988 {
6989 PAGED_CODE();
6990
6991 DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
6992
6993 /* Just copy back the IO_STATUS to the IRP */
6994 RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status);
6995 RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
6996
6997 return RxContext->IoStatusBlock.Status;
6998 }
6999
7000 /*
7001 * @implemented
7002 */
7003 NTSTATUS
7004 RxLowIoReadShell(
7005 PRX_CONTEXT RxContext)
7006 {
7007 PFCB Fcb;
7008 NTSTATUS Status;
7009
7010 PAGED_CODE();
7011
7012 DPRINT("RxLowIoReadShell(%p)\n", RxContext);
7013
7014 Fcb = (PFCB)RxContext->pFcb;
7015 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
7016 {
7017 return STATUS_MORE_PROCESSING_REQUIRED;
7018 }
7019
7020 /* Always update stats for disks */
7021 if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7022 {
7023 ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7024 }
7025
7026 /* And forward the read to the mini-rdr */
7027 Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion);
7028 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
7029
7030 return Status;
7031 }
7032
7033 NTSTATUS
7034 NTAPI
7035 RxLowIoReadShellCompletion(
7036 PRX_CONTEXT RxContext)
7037 {
7038 PIRP Irp;
7039 PFCB Fcb;
7040 NTSTATUS Status;
7041 BOOLEAN PagingIo, IsPipe;
7042 PIO_STACK_LOCATION Stack;
7043 PLOWIO_CONTEXT LowIoContext;
7044
7045 PAGED_CODE();
7046
7047 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
7048
7049 Status = RxContext->IoStatusBlock.Status;
7050 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7051
7052 Irp = RxContext->CurrentIrp;
7053 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7054
7055 /* Set IRP information from the RX_CONTEXT status block */
7056 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7057
7058 /* Fixup status for paging file if nothing was read */
7059 if (PagingIo)
7060 {
7061 if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0)
7062 {
7063 Status = STATUS_END_OF_FILE;
7064 }
7065 }
7066
7067 LowIoContext = &RxContext->LowIoContext;
7068 ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7069
7070 /* Check broken cases that should never happen */
7071 Fcb = (PFCB)RxContext->pFcb;
7072 if (Status == STATUS_FILE_LOCK_CONFLICT)
7073 {
7074 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED))
7075 {
7076 ASSERT(FALSE);
7077 return STATUS_RETRY;
7078 }
7079 }
7080 else if (Status == STATUS_SUCCESS)
7081 {
7082 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
7083 {
7084 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) ||
7085 BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED))
7086 {
7087 ASSERT(FALSE);
7088 }
7089 }
7090
7091 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
7092 {
7093 ASSERT(FALSE);
7094 }
7095 }
7096
7097 /* Readahead should go through Cc and not finish here */
7098 ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
7099
7100 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7101 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7102 {
7103 return Status;
7104 }
7105
7106 Stack = RxContext->CurrentIrpSp;
7107 IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
7108 /* Release lock if required */
7109 if (PagingIo)
7110 {
7111 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7112 }
7113 else
7114 {
7115 /* Set FastIo if read was a success */
7116 if (NT_SUCCESS(Status) && !IsPipe)
7117 {
7118 SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ);
7119 }
7120
7121 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7122 {
7123 RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue);
7124 }
7125 else
7126 {
7127 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7128 }
7129 }
7130
7131 if (IsPipe)
7132 {
7133 UNIMPLEMENTED;
7134 }
7135
7136 /* Final sanity checks */
7137 ASSERT(Status != STATUS_RETRY);
7138 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
7139 ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
7140
7141 return Status;
7142 }
7143
7144 /*
7145 * @implemented
7146 */
7147 NTSTATUS
7148 RxLowIoWriteShell(
7149 IN PRX_CONTEXT RxContext)
7150 {
7151 PFCB Fcb;
7152 NTSTATUS Status;
7153
7154 PAGED_CODE();
7155
7156 DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
7157
7158 Fcb = (PFCB)RxContext->pFcb;
7159
7160 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7161 !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7162
7163 /* Always update stats for disks */
7164 if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7165 {
7166 ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7167 }
7168
7169 /* And forward the write to the mini-rdr */
7170 Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion);
7171 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
7172
7173 return Status;
7174 }
7175
7176 NTSTATUS
7177 NTAPI
7178 RxLowIoWriteShellCompletion(
7179 PRX_CONTEXT RxContext)
7180 {
7181 PIRP Irp;
7182 PFCB Fcb;
7183 NTSTATUS Status;
7184 BOOLEAN PagingIo;
7185 PLOWIO_CONTEXT LowIoContext;
7186
7187 PAGED_CODE();
7188
7189 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
7190
7191 Status = RxContext->IoStatusBlock.Status;
7192 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7193
7194 Irp = RxContext->CurrentIrp;
7195
7196 /* Set IRP information from the RX_CONTEXT status block */
7197 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7198
7199 LowIoContext = &RxContext->LowIoContext;
7200 ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7201
7202 /* Perform a few sanity checks */
7203 Fcb = (PFCB)RxContext->pFcb;
7204 if (Status == STATUS_SUCCESS)
7205 {
7206 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED))
7207 {
7208 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7209 !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7210 }
7211
7212 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED));
7213 }
7214
7215 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7216 if (Status != STATUS_SUCCESS && PagingIo)
7217 {
7218 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status);
7219 }
7220
7221 /* In case of async call, perform last bits not done in RxCommonWrite */
7222 if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7223 {
7224 PFILE_OBJECT FileObject;
7225 PIO_STACK_LOCATION Stack;
7226
7227 /* We only succeed if we wrote what was asked for */
7228 if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7229 {
7230 ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount);
7231 }
7232
7233 /* If write succeed, ,also update FILE_OBJECT flags */
7234 Stack = RxContext->CurrentIrpSp;
7235 FileObject = Stack->FileObject;
7236 if (!PagingIo)
7237 {
7238 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
7239 }
7240
7241 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE))
7242 {
7243 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
7244 }
7245
7246 /* If VDL was extended, fix attributes */
7247 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL))
7248 {
7249 LONGLONG LastOffset, FileSize;
7250
7251 LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset +
7252 Irp->IoStatus.Information;
7253 RxGetFileSizeWithLock(Fcb, &FileSize);
7254
7255 if (FileSize < LastOffset)
7256 {
7257 LastOffset = FileSize;
7258 }
7259
7260 Fcb->Header.ValidDataLength.QuadPart = LastOffset;
7261 }
7262
7263 /* One less outstanding write */
7264 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7265 {
7266 PNON_PAGED_FCB NonPagedFcb;
7267
7268 NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
7269 if (NonPagedFcb != NULL)
7270 {
7271 if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites,
7272 -1, &RxStrucSupSpinLock) == 1)
7273 {
7274 KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
7275 }
7276 }
7277 }
7278
7279 /* Release paging resource if acquired */
7280 if (RxContext->FcbPagingIoResourceAcquired)
7281 {
7282 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7283 }
7284
7285 /* Resume blocked operations for pipes */
7286 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7287 {
7288 RxResumeBlockedOperations_Serially(RxContext,
7289 &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue);
7290 }
7291 else
7292 {
7293 /* And release FCB only for files */
7294 if (RxContext->FcbResourceAcquired)
7295 {
7296 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7297 }
7298 }
7299
7300 /* Final sanity checks */
7301 ASSERT(Status != STATUS_RETRY);
7302 ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length));
7303 ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
7304
7305 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7306 {
7307 UNIMPLEMENTED;
7308 }
7309 }
7310
7311 return Status;
7312 }
7313
7314 /*
7315 * @implemented
7316 */
7317 NTSTATUS
7318 RxNotifyChangeDirectory(
7319 PRX_CONTEXT RxContext)
7320 {
7321 PIRP Irp;
7322 NTSTATUS Status;
7323 PIO_STACK_LOCATION Stack;
7324
7325 PAGED_CODE();
7326
7327 /* The IRP can abviously wait */
7328 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
7329
7330 /* Initialize its lowio */
7331 RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
7332
7333 _SEH2_TRY
7334 {
7335 /* Lock user buffer */
7336 Stack = RxContext->CurrentIrpSp;
7337 RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
7338
7339 /* Copy parameters from IO_STACK */
7340 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE);
7341 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter;
7342 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
7343
7344 /* If we have an associated MDL */
7345 Irp = RxContext->CurrentIrp;
7346 if (Irp->MdlAddress != NULL)
7347 {
7348 /* Then, call mini-rdr */
7349 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
7350 if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL)
7351 {
7352 Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion);
7353 }
7354 else
7355 {
7356 Status = STATUS_INSUFFICIENT_RESOURCES;
7357 }
7358 }
7359 else
7360 {
7361 Status = STATUS_INVALID_PARAMETER;
7362 }
7363 }
7364 _SEH2_FINALLY
7365 {
7366 /* All correct */
7367 }
7368 _SEH2_END;
7369
7370 return Status;
7371 }
7372
7373 NTSTATUS
7374 RxPostStackOverflowRead (
7375 IN PRX_CONTEXT RxContext)
7376 {
7377 PAGED_CODE();
7378
7379 UNIMPLEMENTED;
7380 return STATUS_NOT_IMPLEMENTED;
7381 }
7382
7383 /*
7384 * @implemented
7385 */
7386 VOID
7387 RxpPrepareCreateContextForReuse(
7388 PRX_CONTEXT RxContext)
7389 {
7390 /* Reuse can only happen for open operations (STATUS_RETRY) */
7391 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7392
7393 /* Release the FCB if it was acquired */
7394 if (RxContext->Create.FcbAcquired)
7395 {
7396 RxReleaseFcb(RxContext, RxContext->pFcb);
7397 RxContext->Create.FcbAcquired = FALSE;
7398 }
7399
7400 /* Free the canonical name */
7401 RxFreeCanonicalNameBuffer(RxContext);
7402
7403 /* If we have a VNetRoot associated */
7404 if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL)
7405 {
7406 /* Remove our link and thus, dereference the VNetRoot */
7407 RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE);
7408 if (RxContext->Create.pVNetRoot != NULL)
7409 {
7410 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE);
7411 RxContext->Create.pVNetRoot = NULL;
7412 }
7413 RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
7414 }
7415
7416 DPRINT("RxContext: %p prepared for reuse\n", RxContext);
7417 }
7418
7419 /*
7420 * @implemented
7421 */
7422 NTSTATUS
7423 RxpQueryInfoMiniRdr(
7424 PRX_CONTEXT RxContext,
7425 FILE_INFORMATION_CLASS FileInfoClass,
7426 PVOID Buffer)
7427 {
7428 PFCB Fcb;
7429 NTSTATUS Status;
7430
7431 Fcb = (PFCB)RxContext->pFcb;
7432
7433 /* Set the RX_CONTEXT */
7434 RxContext->Info.FileInformationClass = FileInfoClass;
7435 RxContext->Info.Buffer = Buffer;
7436
7437 /* Pass down */
7438 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
7439
7440 return Status;
7441 }
7442
7443 /*
7444 * @implemented
7445 */
7446 NTSTATUS
7447 RxPrefixClaim(
7448 IN PRX_CONTEXT RxContext)
7449 {
7450 PIRP Irp;
7451 NTSTATUS Status;
7452 NET_ROOT_TYPE NetRootType;
7453 UNICODE_STRING CanonicalName, FileName, NetRootName;
7454
7455 PAGED_CODE();
7456
7457 Irp = RxContext->CurrentIrp;
7458
7459 /* This has to come from MUP */
7460 if (Irp->RequestorMode == UserMode)
7461 {
7462 return STATUS_INVALID_DEVICE_REQUEST;
7463 }
7464
7465 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL)
7466 {
7467 PQUERY_PATH_REQUEST QueryRequest;
7468
7469 /* Get parameters */
7470 QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7471
7472 /* Don't overflow allocation */
7473 if (QueryRequest->PathNameLength >= MAXUSHORT - 1)
7474 {
7475 return STATUS_INVALID_DEVICE_REQUEST;
7476 }
7477
7478 /* Forcefully rewrite IRP MJ */
7479 RxContext->MajorFunction = IRP_MJ_CREATE;
7480
7481 /* Fake canon name */
7482 RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
7483 if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
7484 {
7485 Status = STATUS_INSUFFICIENT_RESOURCES;
7486 goto Leave;
7487 }
7488
7489 /* Copy the prefix to look for */
7490 RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength);
7491 RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength;
7492 RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
7493
7494 /* Zero the create parameters */
7495 RtlZeroMemory(&RxContext->Create.NtCreateParameters,
7496 FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters));
7497 RxContext->Create.ThisIsATreeConnectOpen = TRUE;
7498 RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext;
7499 }
7500 else
7501 {
7502 /* If not devcontrol, it comes from open, name was already copied */
7503 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7504 ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL);
7505 }
7506
7507 /* Canonilize name */
7508 NetRootType = NET_ROOT_WILD;
7509 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
7510 FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7511 FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7512 FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7513 NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7514 NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7515 NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7516 Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType);
7517 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7518 if (NT_SUCCESS(Status))
7519 {
7520 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName);
7521 }
7522 if (Status == STATUS_PENDING)
7523 {
7524 return Status;
7525 }
7526 /* Reply to MUP */
7527 if (NT_SUCCESS(Status))
7528 {
7529 PQUERY_PATH_RESPONSE QueryResponse;
7530
7531 /* We accept the length that was canon (minus netroot) */
7532 QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7533 QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length;
7534 }
7535
7536 Leave:
7537 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7538 if (RxContext->MajorFunction == IRP_MJ_CREATE)
7539 {
7540 if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
7541 {
7542 RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
7543 }
7544
7545 RxpPrepareCreateContextForReuse(RxContext);
7546
7547 RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
7548 }
7549
7550 return Status;
7551 }
7552
7553 /*
7554 * @implemented
7555 */
7556 NTSTATUS
7557 NTAPI
7558 RxPrepareToReparseSymbolicLink(
7559 PRX_CONTEXT RxContext,
7560 BOOLEAN SymbolicLinkEmbeddedInOldPath,
7561 PUNICODE_STRING NewPath,
7562 BOOLEAN NewPathIsAbsolute,
7563 PBOOLEAN ReparseRequired)
7564 {
7565 PWSTR NewBuffer;
7566 USHORT NewLength;
7567 PFILE_OBJECT FileObject;
7568
7569 /* Assume no reparse is required first */
7570 *ReparseRequired = FALSE;
7571
7572 /* Only supported for IRP_MJ_CREATE */
7573 if (RxContext->MajorFunction != IRP_MJ_CREATE)
7574 {
7575 return STATUS_INVALID_PARAMETER;
7576 }
7577
7578 /* If symbolic link is not embedded, and DELETE is specified, fail */
7579 if (!SymbolicLinkEmbeddedInOldPath)
7580 {
7581 /* Excepted if DELETE is the only flag specified, then, open has to succeed
7582 * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
7583 */
7584 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, DELETE) &&
7585 BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, ~DELETE))
7586 {
7587 return STATUS_ACCESS_DENIED;
7588 }
7589 }
7590
7591 /* At that point, assume reparse will be required */
7592 *ReparseRequired = TRUE;
7593
7594 /* If new path isn't absolute, it's up to us to make it absolute */
7595 if (!NewPathIsAbsolute)
7596 {
7597 /* The prefix will be \Device\Mup */
7598 NewLength = NewPath->Length + (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL));
7599 NewBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, NewLength,
7600 RX_MISC_POOLTAG);
7601 if (NewBuffer == NULL)
7602 {
7603 return STATUS_INSUFFICIENT_RESOURCES;
7604 }
7605
7606 /* Copy data for the new path */
7607 RtlMoveMemory(NewBuffer, L"\\Device\\Mup", (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL)));
7608 RtlMoveMemory(Add2Ptr(NewBuffer, (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))),
7609 NewPath->Buffer, NewPath->Length);
7610 }
7611 /* Otherwise, use caller path as it */
7612 else
7613 {
7614 NewLength = NewPath->Length;
7615 NewBuffer = NewPath->Buffer;
7616 }
7617
7618 /* Get the FILE_OBJECT we'll modify */
7619 FileObject = RxContext->CurrentIrpSp->FileObject;
7620
7621 /* Free old path first */
7622 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
7623 /* And setup new one */
7624 FileObject->FileName.Length = NewLength;
7625 FileObject->FileName.MaximumLength = NewLength;
7626 FileObject->FileName.Buffer = NewBuffer;
7627
7628 /* And set reparse flag */
7629 SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE);
7630
7631 /* Done! */
7632 return STATUS_SUCCESS;
7633 }
7634
7635 /*
7636 * @implemented
7637 */
7638 VOID
7639 RxPrePostIrp(
7640 IN PVOID Context,
7641 IN PIRP Irp)
7642 {
7643 LOCK_OPERATION Lock;
7644 PIO_STACK_LOCATION Stack;
7645 PRX_CONTEXT RxContext = Context;
7646
7647 /* NULL IRP is no option */
7648 if (Irp == NULL)
7649 {
7650 return;
7651 }
7652
7653 /* Check whether preparation was really needed */
7654 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
7655 {
7656 return;
7657 }
7658 /* Mark the context as prepared */
7659 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
7660
7661 /* Just lock the user buffer, with the correct length, depending on the MJ */
7662 Lock = IoReadAccess;
7663 Stack = RxContext->CurrentIrpSp;
7664 if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
7665 {
7666 if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
7667 {
7668 if (RxContext->MajorFunction == IRP_MJ_READ)
7669 {
7670 Lock = IoWriteAccess;
7671 }
7672 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length);
7673 }
7674 }
7675 else
7676 {
7677 if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) ||
7678 RxContext->MajorFunction == IRP_MJ_QUERY_EA)
7679 {
7680 Lock = IoWriteAccess;
7681 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length);
7682 }
7683 else if (RxContext->MajorFunction == IRP_MJ_SET_EA)
7684 {
7685 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length);
7686 }
7687 }
7688
7689 /* As it will be posted (async), mark the IRP pending */
7690 IoMarkIrpPending(Irp);
7691 }
7692
7693 /*
7694 * @implemented
7695 */
7696 NTSTATUS
7697 RxpSetInfoMiniRdr(
7698 PRX_CONTEXT RxContext,
7699 FILE_INFORMATION_CLASS Class)
7700 {
7701 PFCB Fcb;
7702 NTSTATUS Status;
7703
7704 /* Initialize parameters in RX_CONTEXT */
7705 RxContext->Info.FileInformationClass = Class;
7706 RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
7707 RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
7708
7709 /* And call mini-rdr */
7710 Fcb = (PFCB)RxContext->pFcb;
7711 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
7712
7713 return Status;
7714 }
7715
7716 VOID
7717 NTAPI
7718 RxpUnregisterMinirdr(
7719 IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
7720 {
7721 UNIMPLEMENTED;
7722 }
7723
7724 /*
7725 * @implemented
7726 */
7727 VOID
7728 RxPurgeNetFcb(
7729 PFCB Fcb,
7730 PRX_CONTEXT LocalContext)
7731 {
7732 NTSTATUS Status;
7733
7734 PAGED_CODE();
7735
7736 /* First, flush */
7737 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
7738
7739 /* And force close */
7740 RxReleaseFcb(NULL, Fcb);
7741 MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
7742 Status = RxAcquireExclusiveFcb(NULL, Fcb);
7743 ASSERT(Status == STATUS_SUCCESS);
7744 }
7745
7746 NTSTATUS
7747 RxQueryAlternateNameInfo(
7748 PRX_CONTEXT RxContext,
7749 PFILE_NAME_INFORMATION AltNameInfo)
7750 {
7751 UNIMPLEMENTED;
7752 return STATUS_NOT_IMPLEMENTED;
7753 }
7754
7755 /*
7756 * @implemented
7757 */
7758 NTSTATUS
7759 RxQueryBasicInfo(
7760 PRX_CONTEXT RxContext,
7761 PFILE_BASIC_INFORMATION BasicInfo)
7762 {
7763 PAGED_CODE();
7764
7765 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
7766
7767 /* Simply zero and forward to mini-rdr */
7768 RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION));
7769 return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);
7770 }
7771
7772 NTSTATUS
7773 RxQueryCompressedInfo(
7774 PRX_CONTEXT RxContext,
7775 PFILE_COMPRESSION_INFORMATION CompressionInfo)
7776 {
7777 UNIMPLEMENTED;
7778 return STATUS_NOT_IMPLEMENTED;
7779 }
7780
7781 /*
7782 * @implemented
7783 */
7784 NTSTATUS
7785 RxQueryDirectory(
7786 PRX_CONTEXT RxContext)
7787 {
7788 PIRP Irp;
7789 PFCB Fcb;
7790 PFOBX Fobx;
7791 UCHAR Flags;
7792 NTSTATUS Status;
7793 BOOLEAN LockNotGranted;
7794 ULONG Length, FileIndex;
7795 PUNICODE_STRING FileName;
7796 PIO_STACK_LOCATION Stack;
7797 FILE_INFORMATION_CLASS FileInfoClass;
7798
7799 PAGED_CODE();
7800
7801 DPRINT("RxQueryDirectory(%p)\n", RxContext);
7802
7803 /* Get parameters */
7804 Stack = RxContext->CurrentIrpSp;
7805 Length = Stack->Parameters.QueryDirectory.Length;
7806 FileName = Stack->Parameters.QueryDirectory.FileName;
7807 FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass;
7808 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7809 FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length,
7810 FileName, FileInfoClass);
7811
7812 Irp = RxContext->CurrentIrp;
7813 Flags = Stack->Flags;
7814 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
7815 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
7816
7817 if (FileName != NULL)
7818 {
7819 DPRINT("FileName: %wZ\n", FileName);
7820 }
7821
7822 /* No FOBX: not a standard file/directory */
7823 Fobx = (PFOBX)RxContext->pFobx;
7824 if (Fobx == NULL)
7825 {
7826 return STATUS_OBJECT_NAME_INVALID;
7827 }
7828
7829 /* We can only deal with a disk */
7830 Fcb = (PFCB)RxContext->pFcb;
7831 if (Fcb->pNetRoot->Type != NET_ROOT_DISK)
7832 {
7833 DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type);
7834 return STATUS_INVALID_DEVICE_REQUEST;
7835 }
7836
7837 /* Setup RX_CONTEXT related fields */
7838 RxContext->QueryDirectory.FileIndex = FileIndex;
7839 RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN);
7840 RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY);
7841 RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED);
7842 RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7843
7844 /* We don't support (yet?) a specific index being set */
7845 if (RxContext->QueryDirectory.IndexSpecified)
7846 {
7847 return STATUS_NOT_IMPLEMENTED;
7848 }
7849
7850 /* Try to lock FCB */
7851 LockNotGranted = TRUE;
7852 if (RxContext->QueryDirectory.InitialQuery)
7853 {
7854 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7855 if (Status != STATUS_LOCK_NOT_GRANTED)
7856 {
7857 if (!NT_SUCCESS(Status))
7858 {
7859 return Status;
7860 }
7861
7862 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7863 {
7864 RxContext->QueryDirectory.InitialQuery = FALSE;
7865 RxConvertToSharedFcb(RxContext, Fcb);
7866 }
7867
7868 LockNotGranted = FALSE;
7869 }
7870 }
7871 else
7872 {
7873 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7874 if (Status != STATUS_LOCK_NOT_GRANTED)
7875 {
7876 if (!NT_SUCCESS(Status))
7877 {
7878 return Status;
7879 }
7880
7881 LockNotGranted = FALSE;
7882 }
7883 }
7884
7885 /* If it failed, post request */
7886 if (LockNotGranted)
7887 {
7888 return RxFsdPostRequest(RxContext);
7889 }
7890
7891 /* This cannot be done on a orphaned directory */
7892 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
7893 {
7894 RxReleaseFcb(RxContext, Fcb);
7895 return STATUS_FILE_CLOSED;
7896 }
7897
7898 _SEH2_TRY
7899 {
7900 /* Set index */
7901 if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan)
7902 {
7903 RxContext->QueryDirectory.FileIndex = 0;
7904 }
7905
7906 /* Assume success */
7907 Status = STATUS_SUCCESS;
7908 /* If initial query, prepare FOBX */
7909 if (RxContext->QueryDirectory.InitialQuery)
7910 {
7911 /* We cannot have a template already! */
7912 ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
7913
7914 /* If we have a file name and a correct one, duplicate it in the FOBX */
7915 if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL &&
7916 (FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') &&
7917 (FileName->Length != 12 * sizeof(WCHAR) ||
7918 RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR)))
7919 {
7920 Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
7921
7922 Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
7923 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7924 {
7925 /* UNICODE_STRING; length has to be even */
7926 if ((FileName->Length & 1) != 0)
7927 {
7928 Status = STATUS_INVALID_PARAMETER;
7929 RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
7930 }
7931 else
7932 {
7933 Fobx->UnicodeQueryTemplate.Length = FileName->Length;
7934 Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
7935 RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
7936
7937 SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE);
7938 }
7939 }
7940 else
7941 {
7942 Status = STATUS_INSUFFICIENT_RESOURCES;
7943 }
7944 }
7945 /* No name specified, or a match all wildcard? Match everything */
7946 else
7947 {
7948 Fobx->ContainsWildCards = TRUE;
7949
7950 Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate;
7951 Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
7952 Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
7953
7954 SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7955 }
7956
7957 /* No need for exclusive any longer */
7958 if (NT_SUCCESS(Status))
7959 {
7960 RxConvertToSharedFcb(RxContext, Fcb);
7961 }
7962 }
7963
7964 /* Lock user buffer and forward to mini-rdr */
7965 if (NT_SUCCESS(Status))
7966 {
7967 RxLockUserBuffer(RxContext, IoModifyAccess, Length);
7968 RxContext->Info.FileInformationClass = FileInfoClass;
7969 RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext);
7970 RxContext->Info.Length = Length;
7971
7972 if (RxContext->Info.Buffer != NULL)
7973 {
7974 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext));
7975 }
7976
7977 /* Post if mini-rdr asks to */
7978 if (RxContext->PostRequest)
7979 {
7980 RxFsdPostRequest(RxContext);
7981 }
7982 else
7983 {
7984 Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining;
7985 }
7986 }
7987 }
7988 _SEH2_FINALLY
7989 {
7990 RxReleaseFcb(RxContext, Fcb);
7991 }
7992 _SEH2_END;
7993
7994 return Status;
7995 }
7996
7997 NTSTATUS
7998 RxQueryEaInfo(
7999 PRX_CONTEXT RxContext,
8000 PFILE_EA_INFORMATION EaInfo)
8001 {
8002 UNIMPLEMENTED;
8003 return STATUS_NOT_IMPLEMENTED;
8004 }
8005
8006 NTSTATUS
8007 RxQueryInternalInfo(
8008 PRX_CONTEXT RxContext,
8009 PFILE_INTERNAL_INFORMATION InternalInfo)
8010 {
8011 UNIMPLEMENTED;
8012 return STATUS_NOT_IMPLEMENTED;
8013 }
8014
8015 NTSTATUS
8016 RxQueryNameInfo(
8017 PRX_CONTEXT RxContext,
8018 PFILE_NAME_INFORMATION NameInfo)
8019 {
8020 UNIMPLEMENTED;
8021 return STATUS_NOT_IMPLEMENTED;
8022 }
8023
8024 NTSTATUS
8025 RxQueryPipeInfo(
8026 PRX_CONTEXT RxContext,
8027 PFILE_PIPE_INFORMATION PipeInfo)
8028 {
8029 UNIMPLEMENTED;
8030 return STATUS_NOT_IMPLEMENTED;
8031 }
8032
8033 NTSTATUS
8034 RxQueryPositionInfo(
8035 PRX_CONTEXT RxContext,
8036 PFILE_POSITION_INFORMATION PositionInfo)
8037 {
8038 UNIMPLEMENTED;
8039 return STATUS_NOT_IMPLEMENTED;
8040 }
8041
8042 /*
8043 * @implemented
8044 */
8045 NTSTATUS
8046 RxQueryStandardInfo(
8047 PRX_CONTEXT RxContext,
8048 PFILE_STANDARD_INFORMATION StandardInfo)
8049 {
8050 PFCB Fcb;
8051 PFOBX Fobx;
8052 NTSTATUS Status;
8053
8054 PAGED_CODE();
8055
8056 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
8057
8058 /* Zero output buffer */
8059 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
8060
8061 Fcb = (PFCB)RxContext->pFcb;
8062 Fobx = (PFOBX)RxContext->pFobx;
8063 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
8064 if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
8065 BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
8066 {
8067 return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
8068 }
8069
8070 /* Otherwise, fill what we can already */
8071 Status = STATUS_SUCCESS;
8072 StandardInfo->NumberOfLinks = Fcb->NumberOfLinks;
8073 StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8074 StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
8075 if (StandardInfo->NumberOfLinks == 0)
8076 {
8077 StandardInfo->NumberOfLinks = 1;
8078 }
8079
8080 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
8081 {
8082 StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
8083 RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart);
8084 }
8085
8086 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8087 if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED))
8088 {
8089 Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
8090 }
8091 else
8092 {
8093 RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION);
8094 }
8095
8096 return Status;
8097 }
8098
8099 /*
8100 * @implemented
8101 */
8102 VOID
8103 NTAPI
8104 RxReadRegistryParameters(
8105 VOID)
8106 {
8107 NTSTATUS Status;
8108 HANDLE KeyHandle;
8109 ULONG ResultLength;
8110 UCHAR Buffer[0x40];
8111 UNICODE_STRING KeyName, ParamName;
8112 OBJECT_ATTRIBUTES ObjectAttributes;
8113 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
8114
8115 PAGED_CODE();
8116
8117 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8118 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
8119 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
8120 if (!NT_SUCCESS(Status))
8121 {
8122 return;
8123 }
8124
8125 PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
8126 RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles");
8127 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8128 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8129 {
8130 DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
8131 }
8132
8133 RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
8134 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8135 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8136 {
8137 ULONG Granularity = *(PULONG)PartialInfo->Data;
8138
8139 if (Granularity > 16)
8140 {
8141 Granularity = 16;
8142 }
8143
8144 ReadAheadGranularity = Granularity << PAGE_SHIFT;
8145 }
8146
8147 RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup");
8148 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8149 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8150 {
8151 DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
8152 }
8153
8154 ZwClose(KeyHandle);
8155 }
8156
8157 /*
8158 * @implemented
8159 */
8160 NTSTATUS
8161 NTAPI
8162 RxRegisterMinirdr(
8163 OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
8164 IN OUT PDRIVER_OBJECT DriverObject,
8165 IN PMINIRDR_DISPATCH MrdrDispatch,
8166 IN ULONG Controls,
8167 IN PUNICODE_STRING DeviceName,
8168 IN ULONG DeviceExtensionSize,
8169 IN DEVICE_TYPE DeviceType,
8170 IN ULONG DeviceCharacteristics)
8171 {
8172 NTSTATUS Status;
8173 PRDBSS_DEVICE_OBJECT RDBSSDevice;
8174
8175 PAGED_CODE();
8176
8177 if (!DeviceObject)
8178 {
8179 return STATUS_INVALID_PARAMETER;
8180 }
8181
8182 /* Create device object with provided parameters */
8183 Status = IoCreateDevice(DriverObject,
8184 DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT),
8185 DeviceName,
8186 DeviceType,
8187 DeviceCharacteristics,
8188 FALSE,
8189 (PDEVICE_OBJECT *)&RDBSSDevice);
8190 if (!NT_SUCCESS(Status))
8191 {
8192 return Status;
8193 }
8194
8195 if (!RxData.DriverObject)
8196 {
8197 return STATUS_UNSUCCESSFUL;
8198 }
8199
8200 /* Initialize our DO extension */
8201 RDBSSDevice->RDBSSDeviceObject = NULL;
8202 ++RxFileSystemDeviceObject->ReferenceCount;
8203 *DeviceObject = RDBSSDevice;
8204 RDBSSDevice->RdbssExports = &RxExports;
8205 RDBSSDevice->Dispatch = MrdrDispatch;
8206 RDBSSDevice->RegistrationControls = Controls;
8207 RDBSSDevice->DeviceName = *DeviceName;
8208 RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
8209 RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
8210 InitializeListHead(&RDBSSDevice->OverflowQueue[0]);
8211 InitializeListHead(&RDBSSDevice->OverflowQueue[1]);
8212 InitializeListHead(&RDBSSDevice->OverflowQueue[2]);
8213 KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock);
8214 RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
8215
8216 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
8217
8218 ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex);
8219 InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks);
8220 ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
8221
8222 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8223 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH))
8224 {
8225 RxInitializeMinirdrDispatchTable(DriverObject);
8226 }
8227
8228 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8229 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER))
8230 {
8231 LARGE_INTEGER ScavengerTimeLimit;
8232
8233 RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject;
8234 RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
8235 RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
8236 ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
8237 RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
8238 RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
8239 }
8240
8241 RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
8242
8243 return STATUS_SUCCESS;
8244 }
8245
8246 /*
8247 * @implemented
8248 */
8249 VOID
8250 RxRemoveFromTopLevelIrpAllocatedContextsList(
8251 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
8252 {
8253 KIRQL OldIrql;
8254
8255 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8256 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
8257 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
8258
8259 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
8260 RemoveEntryList(&TopLevelContext->ListEntry);
8261 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
8262 }
8263
8264 /*
8265 * @implemented
8266 */
8267 PRX_CONTEXT
8268 RxRemoveOverflowEntry(
8269 PRDBSS_DEVICE_OBJECT DeviceObject,
8270 WORK_QUEUE_TYPE Queue)
8271 {
8272 KIRQL OldIrql;
8273 PRX_CONTEXT Context;
8274
8275 KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql);
8276 if (DeviceObject->OverflowQueueCount[Queue] <= 0)
8277 {
8278 /* No entries left, nothing to return */
8279 InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]);
8280 Context = NULL;
8281 }
8282 else
8283 {
8284 PLIST_ENTRY Entry;
8285
8286 /* Decrement count */
8287 --DeviceObject->OverflowQueueCount[Queue];
8288
8289 /* Return head */
8290 Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]);
8291 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry);
8292 ClearFlag(Context->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
8293 Context->OverflowListEntry.Flink = NULL;
8294 }
8295 KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
8296
8297 return Context;
8298 }
8299
8300 #if DBG
8301 /*
8302 * @implemented
8303 */
8304 VOID
8305 RxRemoveShareAccess(
8306 _Inout_ PFILE_OBJECT FileObject,
8307 _Inout_ PSHARE_ACCESS ShareAccess,
8308 _In_ PSZ where,
8309 _In_ PSZ wherelogtag)
8310 {
8311 PAGED_CODE();
8312
8313 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8314 IoRemoveShareAccess(FileObject, ShareAccess);
8315 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8316 }
8317 #endif
8318
8319 /*
8320 * @implemented
8321 */
8322 VOID
8323 RxRemoveShareAccessPerSrvOpens(
8324 IN OUT PSRV_OPEN SrvOpen)
8325 {
8326 ACCESS_MASK DesiredAccess;
8327 BOOLEAN ReadAccess;
8328 BOOLEAN WriteAccess;
8329 BOOLEAN DeleteAccess;
8330
8331 PAGED_CODE();
8332
8333 /* Get access that were granted to SRV_OPEN */
8334 DesiredAccess = SrvOpen->DesiredAccess;
8335 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
8336 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
8337 DeleteAccess = (DesiredAccess & DELETE) != 0;
8338
8339 /* If any, drop them */
8340 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
8341 {
8342 BOOLEAN SharedRead;
8343 BOOLEAN SharedWrite;
8344 BOOLEAN SharedDelete;
8345 ULONG DesiredShareAccess;
8346 PSHARE_ACCESS ShareAccess;
8347
8348 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
8349 DesiredShareAccess = SrvOpen->ShareAccess;
8350
8351 ShareAccess->Readers -= ReadAccess;
8352 ShareAccess->Writers -= WriteAccess;
8353 ShareAccess->Deleters -= DeleteAccess;
8354
8355 ShareAccess->OpenCount--;
8356
8357 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
8358 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
8359 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
8360 ShareAccess->SharedRead -= SharedRead;
8361 ShareAccess->SharedWrite -= SharedWrite;
8362 ShareAccess->SharedDelete -= SharedDelete;
8363 }
8364 }
8365
8366 NTSTATUS
8367 RxSearchForCollapsibleOpen(
8368 PRX_CONTEXT RxContext,
8369 ACCESS_MASK DesiredAccess,
8370 ULONG ShareAccess)
8371 {
8372 PFCB Fcb;
8373 NTSTATUS Status;
8374 PLIST_ENTRY ListEntry;
8375 BOOLEAN ShouldTry, Purged, Scavenged;
8376
8377 PAGED_CODE();
8378
8379 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
8380
8381 Fcb = (PFCB)RxContext->pFcb;
8382
8383 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8384 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
8385 {
8386 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8387
8388 RxScavengeRelatedFobxs(Fcb);
8389 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8390
8391 return STATUS_NOT_FOUND;
8392 }
8393
8394 /* If basic open, ask the mini-rdr if we should try to collapse */
8395 if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN ||
8396 RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF)
8397 {
8398 ShouldTry = TRUE;
8399
8400 if (Fcb->MRxDispatch != NULL)
8401 {
8402 ASSERT(RxContext->pRelevantSrvOpen == NULL);
8403 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8404
8405 ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext));
8406 }
8407 }
8408 else
8409 {
8410 ShouldTry = FALSE;
8411 }
8412
8413 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE))
8414 {
8415 ShouldTry = FALSE;
8416 }
8417
8418 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8419 if (!ShouldTry)
8420 {
8421 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess)))
8422 {
8423 return STATUS_NOT_FOUND;
8424 }
8425
8426 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8427
8428 RxScavengeRelatedFobxs(Fcb);
8429 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8430
8431 return STATUS_NOT_FOUND;
8432 }
8433
8434 /* Only collapse for matching NET_ROOT & disks */
8435 if (Fcb->pNetRoot != RxContext->Create.pNetRoot ||
8436 Fcb->pNetRoot->Type != NET_ROOT_DISK)
8437 {
8438 return STATUS_NOT_FOUND;
8439 }
8440
8441 Purged = FALSE;
8442 Scavenged = FALSE;
8443 Status = STATUS_NOT_FOUND;
8444 TryAgain:
8445 /* Browse all our SRV_OPEN to find the matching one */
8446 for (ListEntry = Fcb->SrvOpenList.Flink;
8447 ListEntry != &Fcb->SrvOpenList;
8448 ListEntry = ListEntry->Flink)
8449 {
8450 PSRV_OPEN SrvOpen;
8451
8452 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
8453 /* Not the same VNET_ROOT, move to the next one */
8454 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8455 {
8456 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8457 continue;
8458 }
8459
8460 /* Is there a sharing violation? */
8461 if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess ||
8462 BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED)))
8463 {
8464 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8465 {
8466 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8467 continue;
8468 }
8469
8470 /* Check against the SRV_OPEN */
8471 Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess);
8472 if (!NT_SUCCESS(Status))
8473 {
8474 break;
8475 }
8476 }
8477 else
8478 {
8479 /* Don't allow collaspse for reparse point opening */
8480 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT))
8481 {
8482 Purged = TRUE;
8483 Scavenged = TRUE;
8484 Status = STATUS_NOT_FOUND;
8485 break;
8486 }
8487
8488 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8489 if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY))
8490 {
8491 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
8492
8493 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8494 if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)))
8495 {
8496 /* Is close delayed - great reuse*/
8497 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
8498 {
8499 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen);
8500 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
8501 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
8502 }
8503
8504 return STATUS_SUCCESS;
8505 }
8506
8507 Status = STATUS_NOT_FOUND;
8508 break;
8509 }
8510 }
8511 }
8512 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8513 if (ListEntry == &Fcb->SrvOpenList)
8514 {
8515 Status = STATUS_NOT_FOUND;
8516 }
8517
8518 /* Only required access: read attributes? Don't reuse */
8519 if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES)
8520 {
8521 return STATUS_NOT_FOUND;
8522 }
8523
8524 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8525 if (!Scavenged)
8526 {
8527 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8528 Scavenged = TRUE;
8529 RxScavengeRelatedFobxs(Fcb);
8530 goto TryAgain;
8531 }
8532
8533 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8534 if (!Purged && RxIsOkToPurgeFcb(Fcb))
8535 {
8536 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8537 Purged = TRUE;
8538 goto TryAgain;
8539 }
8540
8541 /* If sharing violation, keep track of it */
8542 if (Status == STATUS_SHARING_VIOLATION)
8543 {
8544 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8545 }
8546
8547 DPRINT("Status: %x\n", Status);
8548 return Status;
8549 }
8550
8551 NTSTATUS
8552 RxSetAllocationInfo(
8553 PRX_CONTEXT RxContext)
8554 {
8555 UNIMPLEMENTED;
8556 return STATUS_NOT_IMPLEMENTED;
8557 }
8558
8559 /*
8560 * @implemented
8561 */
8562 NTSTATUS
8563 RxSetBasicInfo(
8564 PRX_CONTEXT RxContext)
8565 {
8566 NTSTATUS Status;
8567
8568 PAGED_CODE();
8569
8570 #define FILE_ATTRIBUTE_VOLUME 0x8
8571 #define VALID_FILE_ATTRIBUTES ( \
8572 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8573 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8574 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8575 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8576 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8577 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8578 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8579 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8580
8581 /* First of all, call the mini-rdr */
8582 Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation);
8583 /* If it succeed, perform last bits */
8584 if (NT_SUCCESS(Status))
8585 {
8586 PIRP Irp;
8587 PFCB Fcb;
8588 PFOBX Fobx;
8589 PFILE_OBJECT FileObject;
8590 ULONG Attributes, CleanAttr;
8591 PFILE_BASIC_INFORMATION BasicInfo;
8592
8593 Fcb = (PFCB)RxContext->pFcb;
8594 Fobx = (PFOBX)RxContext->pFobx;
8595 Irp = RxContext->CurrentIrp;
8596 BasicInfo = Irp->AssociatedIrp.SystemBuffer;
8597 FileObject = RxContext->CurrentIrpSp->FileObject;
8598
8599 /* If caller provided flags, handle the change */
8600 Attributes = BasicInfo->FileAttributes;
8601 if (Attributes != 0)
8602 {
8603 /* Clean our flags first, with only stuff we support */
8604 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
8605 {
8606 CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY;
8607 }
8608 else
8609 {
8610 CleanAttr = Attributes & VALID_FILE_ATTRIBUTES;
8611 }
8612
8613 /* Handle the temporary mark (set/unset depending on caller) */
8614 if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY))
8615 {
8616 SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8617 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8618 }
8619 else
8620 {
8621 ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8622 ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8623 }
8624
8625 /* And set new attributes */
8626 Fcb->Attributes = CleanAttr;
8627 }
8628
8629 /* If caller provided a creation time, set it */
8630 if (BasicInfo->CreationTime.QuadPart != 0LL)
8631 {
8632 Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
8633 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION);
8634 }
8635
8636 /* If caller provided a last access time, set it */
8637 if (BasicInfo->LastAccessTime.QuadPart != 0LL)
8638 {
8639 Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
8640 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS);
8641 }
8642
8643 /* If caller provided a last write time, set it */
8644 if (BasicInfo->LastWriteTime.QuadPart != 0LL)
8645 {
8646 Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
8647 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
8648 }
8649
8650 /* If caller provided a last change time, set it */
8651 if (BasicInfo->ChangeTime.QuadPart != 0LL)
8652 {
8653 Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
8654 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
8655 }
8656 }
8657
8658 /* Done */
8659 return Status;
8660 }
8661
8662 /*
8663 * @implemented
8664 */
8665 NTSTATUS
8666 RxSetDispositionInfo(
8667 PRX_CONTEXT RxContext)
8668 {
8669 NTSTATUS Status;
8670
8671 PAGED_CODE();
8672
8673 /* First, make the mini-rdr work! */
8674 Status = RxpSetInfoMiniRdr(RxContext, FileDispositionInformation);
8675 /* If it succeed, we'll keep track of the change */
8676 if (NT_SUCCESS(Status))
8677 {
8678 PFCB Fcb;
8679 PFILE_OBJECT FileObject;
8680 PFILE_DISPOSITION_INFORMATION FileDispo;
8681
8682 Fcb = (PFCB)RxContext->pFcb;
8683 FileObject = RxContext->CurrentIrpSp->FileObject;
8684 FileDispo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
8685 /* Caller asks for deletion: mark as delete on close */
8686 if (FileDispo->DeleteFile)
8687 {
8688 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8689 FileObject->DeletePending = TRUE;
8690 }
8691 /* Otherwise, clear it */
8692 else
8693 {
8694 ClearFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
8695 FileObject->DeletePending = FALSE;
8696 }
8697
8698 /* Sanitize output */
8699 Status = STATUS_SUCCESS;
8700 }
8701
8702 return Status;
8703 }
8704
8705 NTSTATUS
8706 RxSetEndOfFileInfo(
8707 PRX_CONTEXT RxContext)
8708 {
8709 UNIMPLEMENTED;
8710 return STATUS_NOT_IMPLEMENTED;
8711 }
8712
8713 NTSTATUS
8714 RxSetPipeInfo(
8715 PRX_CONTEXT RxContext)
8716 {
8717 UNIMPLEMENTED;
8718 return STATUS_NOT_IMPLEMENTED;
8719 }
8720
8721 NTSTATUS
8722 RxSetPositionInfo(
8723 PRX_CONTEXT RxContext)
8724 {
8725 UNIMPLEMENTED;
8726 return STATUS_NOT_IMPLEMENTED;
8727 }
8728
8729 /*
8730 * @implemented
8731 */
8732 NTSTATUS
8733 RxSetRenameInfo(
8734 PRX_CONTEXT RxContext)
8735 {
8736 ULONG Length;
8737 NTSTATUS Status;
8738 PFCB RenameFcb, Fcb;
8739 PIO_STACK_LOCATION Stack;
8740 PFILE_RENAME_INFORMATION RenameInfo, UserInfo;
8741
8742 PAGED_CODE();
8743
8744 DPRINT("RxSetRenameInfo(%p)\n", RxContext);
8745
8746 Stack = RxContext->CurrentIrpSp;
8747 DPRINT("FO: %p, Replace: %d\n", Stack->Parameters.SetFile.FileObject, Stack->Parameters.SetFile.ReplaceIfExists);
8748
8749 /* If there's no FO, we won't do extra operation, so directly pass to mini-rdr and quit */
8750 RxContext->Info.ReplaceIfExists = Stack->Parameters.SetFile.ReplaceIfExists;
8751 if (Stack->Parameters.SetFile.FileObject == NULL)
8752 {
8753 return RxpSetInfoMiniRdr(RxContext, Stack->Parameters.SetFile.FileInformationClass);
8754 }
8755
8756 Fcb = (PFCB)RxContext->pFcb;
8757 RenameFcb = Stack->Parameters.SetFile.FileObject->FsContext;
8758 /* First, validate the received file object */
8759 ASSERT(NodeType(RenameFcb) == RDBSS_NTC_OPENTARGETDIR_FCB);
8760 if (Fcb->pNetRoot != RenameFcb->pNetRoot)
8761 {
8762 DPRINT1("Not the same device: %p:%p (%wZ) - %p:%p (%wZ)\n", Fcb, Fcb->pNetRoot, Fcb->pNetRoot->pNetRootName, RenameFcb, RenameFcb->pNetRoot, RenameFcb->pNetRoot->pNetRootName);
8763 return STATUS_NOT_SAME_DEVICE;
8764 }
8765
8766 /* We'll reallocate a safe buffer */
8767 Length = Fcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize + RenameFcb->FcbTableEntry.Path.Length + FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName);
8768 RenameInfo = RxAllocatePoolWithTag(PagedPool, Length, '??xR');
8769 if (RenameInfo == NULL)
8770 {
8771 return STATUS_INSUFFICIENT_RESOURCES;
8772 }
8773
8774 _SEH2_TRY
8775 {
8776 /* Copy the data */
8777 UserInfo = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
8778 RenameInfo->ReplaceIfExists = UserInfo->ReplaceIfExists;
8779 RenameInfo->RootDirectory = UserInfo->RootDirectory;
8780 RenameInfo->FileNameLength = RenameFcb->FcbTableEntry.Path.Length;
8781 RtlMoveMemory(&RenameInfo->FileName[0], RenameFcb->FcbTableEntry.Path.Buffer, RenameFcb->FcbTableEntry.Path.Length);
8782
8783 /* Set them in the RX_CONTEXT */
8784 RxContext->Info.FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
8785 RxContext->Info.Buffer = RenameInfo;
8786 RxContext->Info.Length = Length;
8787
8788 /* And call the mini-rdr */
8789 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
8790 }
8791 _SEH2_FINALLY
8792 {
8793 /* Free */
8794 RxFreePoolWithTag(RenameInfo, '??xR');
8795 }
8796 _SEH2_END;
8797
8798 /* Done! */
8799 return Status;
8800 }
8801
8802 #if DBG
8803 /*
8804 * @implemented
8805 */
8806 VOID
8807 RxSetShareAccess(
8808 _In_ ACCESS_MASK DesiredAccess,
8809 _In_ ULONG DesiredShareAccess,
8810 _Inout_ PFILE_OBJECT FileObject,
8811 _Out_ PSHARE_ACCESS ShareAccess,
8812 _In_ PSZ where,
8813 _In_ PSZ wherelogtag)
8814 {
8815 PAGED_CODE();
8816
8817 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8818 IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
8819 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8820 }
8821 #endif
8822
8823 NTSTATUS
8824 RxSetSimpleInfo(
8825 PRX_CONTEXT RxContext)
8826 {
8827 UNIMPLEMENTED;
8828 return STATUS_NOT_IMPLEMENTED;
8829 }
8830
8831 /*
8832 * @implemented
8833 */
8834 VOID
8835 RxSetupNetFileObject(
8836 PRX_CONTEXT RxContext)
8837 {
8838 PFCB Fcb;
8839 PFOBX Fobx;
8840 PFILE_OBJECT FileObject;
8841 PIO_STACK_LOCATION Stack;
8842
8843 PAGED_CODE();
8844
8845 /* Assert FOBX is FOBX or NULL */
8846 Fobx = (PFOBX)RxContext->pFobx;
8847 ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
8848
8849 Fcb = (PFCB)RxContext->pFcb;
8850 Stack = RxContext->CurrentIrpSp;
8851 FileObject = Stack->FileObject;
8852 /* If it's temporary mark FO as such */
8853 if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB &&
8854 BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY))
8855 {
8856 if (FileObject == NULL)
8857 {
8858 return;
8859 }
8860
8861 FileObject->Flags |= FO_TEMPORARY_FILE;
8862 }
8863
8864 /* No FO, nothing to setup */
8865 if (FileObject == NULL)
8866 {
8867 return;
8868 }
8869
8870 /* Assign FCB & CCB (FOBX) to FO */
8871 FileObject->FsContext = Fcb;
8872 FileObject->FsContext2 = Fobx;
8873 if (Fobx != NULL)
8874 {
8875 ULONG_PTR StackTop, StackBottom;
8876
8877 /* If FO is allocated on pool, keep track of it */
8878 IoGetStackLimits(&StackTop, &StackBottom);
8879 if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop)
8880 {
8881 Fobx->AssociatedFileObject = FileObject;
8882 }
8883 else
8884 {
8885 Fobx->AssociatedFileObject = NULL;
8886 }
8887
8888 /* Make sure to mark FOBX if it's a DFS open */
8889 if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))
8890 {
8891 SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8892 }
8893 else
8894 {
8895 ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8896 }
8897 }
8898
8899 /* Set Cc pointers */
8900 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
8901
8902 /* Update access state */
8903 if (Stack->Parameters.Create.SecurityContext != NULL)
8904 {
8905 PACCESS_STATE AccessState;
8906
8907 AccessState = Stack->Parameters.Create.SecurityContext->AccessState;
8908 AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess;
8909 AccessState->RemainingDesiredAccess = 0;
8910 }
8911 }
8912
8913 /*
8914 * @implemented
8915 */
8916 NTSTATUS
8917 NTAPI
8918 RxStartMinirdr(
8919 IN PRX_CONTEXT RxContext,
8920 OUT PBOOLEAN PostToFsp)
8921 {
8922 NTSTATUS Status;
8923 BOOLEAN Wait, AlreadyStarted;
8924 PRDBSS_DEVICE_OBJECT DeviceObject;
8925
8926 /* If we've not been post, then, do it */
8927 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
8928 {
8929 SECURITY_SUBJECT_CONTEXT SubjectContext;
8930
8931 SeCaptureSubjectContext(&SubjectContext);
8932 RxContext->FsdUid = RxGetUid(&SubjectContext);
8933 SeReleaseSubjectContext(&SubjectContext);
8934
8935 *PostToFsp = TRUE;
8936 return STATUS_PENDING;
8937 }
8938
8939 /* Acquire all the required locks */
8940 Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
8941 if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait))
8942 {
8943 *PostToFsp = TRUE;
8944 return STATUS_PENDING;
8945 }
8946
8947 if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait))
8948 {
8949 ExReleaseResourceLite(&RxData.Resource);
8950 *PostToFsp = TRUE;
8951 return STATUS_PENDING;
8952 }
8953
8954 AlreadyStarted = FALSE;
8955 DeviceObject = RxContext->RxDeviceObject;
8956 _SEH2_TRY
8957 {
8958 /* MUP handle set, means already registered */
8959 if (DeviceObject->MupHandle != NULL)
8960 {
8961 AlreadyStarted = TRUE;
8962 Status = STATUS_REDIRECTOR_STARTED;
8963 _SEH2_LEAVE;
8964 }
8965
8966 /* If we're asked to register to MUP, then do it */
8967 Status = STATUS_SUCCESS;
8968 if (DeviceObject->RegisterUncProvider)
8969 {
8970 Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle,
8971 &DeviceObject->DeviceName,
8972 DeviceObject->RegisterMailSlotProvider);
8973 }
8974 if (!NT_SUCCESS(Status))
8975 {
8976 DeviceObject->MupHandle = NULL;
8977 _SEH2_LEAVE;
8978 }
8979
8980 /* Register as file system */
8981 IoRegisterFileSystem(&DeviceObject->DeviceObject);
8982 DeviceObject->RegisteredAsFileSystem = TRUE;
8983
8984 /* Inform mini-rdr it has to start */
8985 MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject));
8986 if (NT_SUCCESS(Status))
8987 {
8988 ++DeviceObject->StartStopContext.Version;
8989 RxSetRdbssState(DeviceObject, RDBSS_STARTED);
8990 InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
8991
8992 Status = RxInitializeMRxDispatcher(DeviceObject);
8993 }
8994 }
8995 _SEH2_FINALLY
8996 {
8997 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status))
8998 {
8999 if (!AlreadyStarted)
9000 {
9001 RxUnstart(RxContext, DeviceObject);
9002 }
9003 }
9004
9005 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
9006 ExReleaseResourceLite(&RxData.Resource);
9007 }
9008 _SEH2_END;
9009
9010 return Status;
9011 }
9012
9013 NTSTATUS
9014 NTAPI
9015 RxStopMinirdr(
9016 IN PRX_CONTEXT RxContext,
9017 OUT PBOOLEAN PostToFsp)
9018 {
9019 UNIMPLEMENTED;
9020 return STATUS_NOT_IMPLEMENTED;
9021 }
9022
9023 NTSTATUS
9024 RxSystemControl(
9025 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
9026 IN PIRP Irp)
9027 {
9028 UNIMPLEMENTED;
9029 return STATUS_NOT_IMPLEMENTED;
9030 }
9031
9032 /*
9033 * @implemented
9034 */
9035 BOOLEAN
9036 RxTryToBecomeTheTopLevelIrp(
9037 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
9038 IN PIRP Irp,
9039 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
9040 IN BOOLEAN ForceTopLevel
9041 )
9042 {
9043 BOOLEAN FromPool = FALSE;
9044
9045 PAGED_CODE();
9046
9047 /* If not top level, and not have to be, quit */
9048 if (IoGetTopLevelIrp() && !ForceTopLevel)
9049 {
9050 return FALSE;
9051 }
9052
9053 /* If not TLC provider, allocate one */
9054 if (TopLevelContext == NULL)
9055 {
9056 TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
9057 if (TopLevelContext == NULL)
9058 {
9059 return FALSE;
9060 }
9061
9062 FromPool = TRUE;
9063 }
9064
9065 /* Init it */
9066 __RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
9067
9068 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
9069 if (FromPool)
9070 {
9071 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
9072 }
9073
9074 /* Make it top level IRP */
9075 IoSetTopLevelIrp((PIRP)TopLevelContext);
9076 return TRUE;
9077 }
9078
9079 #if DBG
9080 /*
9081 * @implemented
9082 */
9083 VOID
9084 RxUpdateShareAccess(
9085 _Inout_ PFILE_OBJECT FileObject,
9086 _Inout_ PSHARE_ACCESS ShareAccess,
9087 _In_ PSZ where,
9088 _In_ PSZ wherelogtag)
9089 {
9090 PAGED_CODE();
9091
9092 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
9093 IoUpdateShareAccess(FileObject, ShareAccess);
9094 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
9095 }
9096 #endif
9097
9098 /*
9099 * @implemented
9100 */
9101 VOID
9102 RxUninitializeCacheMap(
9103 PRX_CONTEXT RxContext,
9104 PFILE_OBJECT FileObject,
9105 PLARGE_INTEGER TruncateSize)
9106 {
9107 PFCB Fcb;
9108 NTSTATUS Status;
9109 CACHE_UNINITIALIZE_EVENT UninitEvent;
9110
9111 PAGED_CODE();
9112
9113 Fcb = FileObject->FsContext;
9114 ASSERT(NodeTypeIsFcb(Fcb));
9115 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
9116
9117 KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE);
9118 CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
9119
9120 /* Always release the FCB before waiting for the uninit event */
9121 RxReleaseFcb(RxContext, Fcb);
9122
9123 KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
9124
9125 /* Re-acquire it afterwards */
9126 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
9127 ASSERT(NT_SUCCESS(Status));
9128 }
9129
9130 VOID
9131 NTAPI
9132 RxUnload(
9133 IN PDRIVER_OBJECT DriverObject)
9134 {
9135 UNIMPLEMENTED;
9136 }
9137
9138 VOID
9139 NTAPI
9140 RxUnlockOperation(
9141 IN PVOID Context,
9142 IN PFILE_LOCK_INFO LockInfo)
9143 {
9144 UNIMPLEMENTED;
9145 }
9146
9147 VOID
9148 RxUnstart(
9149 PRX_CONTEXT Context,
9150 PRDBSS_DEVICE_OBJECT DeviceObject)
9151 {
9152 UNIMPLEMENTED;
9153 }
9154
9155 /*
9156 * @implemented
9157 */
9158 VOID
9159 RxUnwindTopLevelIrp(
9160 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
9161 {
9162 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
9163
9164 /* No TLC provided? Ask the system for ours! */
9165 if (TopLevelContext == NULL)
9166 {
9167 TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
9168 if (TopLevelContext == NULL)
9169 {
9170 return;
9171 }
9172
9173 /* In that case, just assert it's really ours */
9174 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext));
9175 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
9176 }
9177
9178 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
9179 ASSERT(TopLevelContext->Thread == PsGetCurrentThread());
9180 /* Restore the previous top level IRP */
9181 IoSetTopLevelIrp(TopLevelContext->Previous);
9182 /* If TLC was allocated from pool, remove it from list and release it */
9183 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
9184 {
9185 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
9186 RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
9187 }
9188 }
9189
9190 /*
9191 * @implemented
9192 */
9193 VOID
9194 RxUpdateShareAccessPerSrvOpens(
9195 IN PSRV_OPEN SrvOpen)
9196 {
9197 ACCESS_MASK DesiredAccess;
9198 BOOLEAN ReadAccess;
9199 BOOLEAN WriteAccess;
9200 BOOLEAN DeleteAccess;
9201
9202 PAGED_CODE();
9203
9204 /* If already updated, no need to continue */
9205 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED))
9206 {
9207 return;
9208 }
9209
9210 /* Check if any access wanted */
9211 DesiredAccess = SrvOpen->DesiredAccess;
9212 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
9213 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
9214 DeleteAccess = (DesiredAccess & DELETE) != 0;
9215
9216 /* In that case, update it */
9217 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
9218 {
9219 BOOLEAN SharedRead;
9220 BOOLEAN SharedWrite;
9221 BOOLEAN SharedDelete;
9222 ULONG DesiredShareAccess;
9223 PSHARE_ACCESS ShareAccess;
9224
9225 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
9226 DesiredShareAccess = SrvOpen->ShareAccess;
9227
9228 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
9229 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
9230 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
9231
9232 ShareAccess->OpenCount++;
9233
9234 ShareAccess->Readers += ReadAccess;
9235 ShareAccess->Writers += WriteAccess;
9236 ShareAccess->Deleters += DeleteAccess;
9237 ShareAccess->SharedRead += SharedRead;
9238 ShareAccess->SharedWrite += SharedWrite;
9239 ShareAccess->SharedDelete += SharedDelete;
9240 }
9241
9242 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);
9243 }
9244
9245 /*
9246 * @implemented
9247 */
9248 NTSTATUS
9249 RxXXXControlFileCallthru(
9250 PRX_CONTEXT Context)
9251 {
9252 NTSTATUS Status;
9253
9254 PAGED_CODE();
9255
9256 DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
9257
9258 /* No dispatch table? Nothing to dispatch */
9259 if (Context->RxDeviceObject->Dispatch == NULL)
9260 {
9261 Context->pFobx = NULL;
9262 return STATUS_INVALID_DEVICE_REQUEST;
9263 }
9264
9265 /* Init the lowio context */
9266 Status = RxLowIoPopulateFsctlInfo(Context);
9267 if (!NT_SUCCESS(Status))
9268 {
9269 return Status;
9270 }
9271
9272 /* Check whether we're consistent: a length means a buffer */
9273 if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) ||
9274 (Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL))
9275 {
9276 return STATUS_INVALID_PARAMETER;
9277 }
9278
9279 /* Forward the call to the mini-rdr */
9280 DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile);
9281 Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context);
9282 if (Status != STATUS_PENDING)
9283 {
9284 Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn;
9285 }
9286
9287 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information);
9288 return Status;
9289 }