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