[RDBSS]
[reactos.git] / reactos / sdk / lib / drivers / rdbsslib / rdbss.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rdbsslib/rdbss.c
23 * PURPOSE: RDBSS library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <limits.h>
32 #include <dfs.h>
33 #include <copysup.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
39
40 typedef
41 NTSTATUS
42 (NTAPI *PRX_FSD_DISPATCH) (
43 PRX_CONTEXT Context);
44
45 typedef struct _RX_FSD_DISPATCH_VECTOR
46 {
47 PRX_FSD_DISPATCH CommonRoutine;
48 } RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
49
50 VOID
51 NTAPI
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject);
54
55 NTSTATUS
56 NTAPI
57 RxAcquireForCcFlush(
58 PFILE_OBJECT FileObject,
59 PDEVICE_OBJECT DeviceObject);
60
61 VOID
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64
65 VOID
66 RxAssert(
67 PVOID Assert,
68 PVOID File,
69 ULONG Line,
70 PVOID Message);
71
72 NTSTATUS
73 NTAPI
74 RxCommonCleanup(
75 PRX_CONTEXT Context);
76
77 NTSTATUS
78 NTAPI
79 RxCommonClose(
80 PRX_CONTEXT Context);
81
82 NTSTATUS
83 NTAPI
84 RxCommonCreate(
85 PRX_CONTEXT Context);
86
87 NTSTATUS
88 NTAPI
89 RxCommonDevFCBCleanup(
90 PRX_CONTEXT Context);
91
92 NTSTATUS
93 NTAPI
94 RxCommonDevFCBClose(
95 PRX_CONTEXT Context);
96
97 NTSTATUS
98 NTAPI
99 RxCommonDevFCBFsCtl(
100 PRX_CONTEXT Context);
101
102 NTSTATUS
103 NTAPI
104 RxCommonDevFCBIoCtl(
105 PRX_CONTEXT Context);
106
107 NTSTATUS
108 NTAPI
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context);
111
112 NTSTATUS
113 NTAPI
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context);
116
117 NTSTATUS
118 NTAPI
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context);
121
122 NTSTATUS
123 NTAPI
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context);
126
127 NTSTATUS
128 NTAPI
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context);
131
132 NTSTATUS
133 NTAPI
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context);
136
137 NTSTATUS
138 NTAPI
139 RxCommonLockControl(
140 PRX_CONTEXT Context);
141
142 NTSTATUS
143 NTAPI
144 RxCommonQueryEa(
145 PRX_CONTEXT Context);
146
147 NTSTATUS
148 NTAPI
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context);
151
152 NTSTATUS
153 NTAPI
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context);
156
157 NTSTATUS
158 NTAPI
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context);
161
162 NTSTATUS
163 NTAPI
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context);
166
167 NTSTATUS
168 NTAPI
169 RxCommonRead(
170 PRX_CONTEXT Context);
171
172 NTSTATUS
173 NTAPI
174 RxCommonSetEa(
175 PRX_CONTEXT Context);
176
177 NTSTATUS
178 NTAPI
179 RxCommonSetInformation(
180 PRX_CONTEXT Context);
181
182 NTSTATUS
183 NTAPI
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context);
186
187 NTSTATUS
188 NTAPI
189 RxCommonSetSecurity(
190 PRX_CONTEXT Context);
191
192 NTSTATUS
193 NTAPI
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context);
196
197 NTSTATUS
198 NTAPI
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context);
201
202 NTSTATUS
203 NTAPI
204 RxCommonWrite(
205 PRX_CONTEXT Context);
206
207 VOID
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext);
210
211 NTSTATUS
212 RxCreateFromNetRoot(
213 PRX_CONTEXT Context,
214 PUNICODE_STRING NetRootName);
215
216 NTSTATUS
217 RxCreateTreeConnect(
218 IN PRX_CONTEXT RxContext);
219
220 BOOLEAN
221 NTAPI
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject,
224 PLARGE_INTEGER FileOffset,
225 ULONG Length, BOOLEAN Wait,
226 ULONG LockKey, BOOLEAN CheckForReadOperation,
227 PIO_STATUS_BLOCK IoStatus,
228 PDEVICE_OBJECT DeviceObject);
229
230 BOOLEAN
231 NTAPI
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject,
234 BOOLEAN Wait,
235 PVOID InputBuffer OPTIONAL,
236 ULONG InputBufferLength,
237 PVOID OutputBuffer OPTIONAL,
238 ULONG OutputBufferLength,
239 ULONG IoControlCode,
240 PIO_STATUS_BLOCK IoStatus,
241 PDEVICE_OBJECT DeviceObject);
242
243 BOOLEAN
244 NTAPI
245 RxFastIoRead(
246 PFILE_OBJECT FileObject,
247 PLARGE_INTEGER FileOffset,
248 ULONG Length,
249 BOOLEAN Wait,
250 ULONG LockKey,
251 PVOID Buffer,
252 PIO_STATUS_BLOCK IoStatus,
253 PDEVICE_OBJECT DeviceObject);
254
255 BOOLEAN
256 NTAPI
257 RxFastIoWrite(
258 PFILE_OBJECT FileObject,
259 PLARGE_INTEGER FileOffset,
260 ULONG Length,
261 BOOLEAN Wait,
262 ULONG LockKey,
263 PVOID Buffer,
264 PIO_STATUS_BLOCK IoStatus,
265 PDEVICE_OBJECT DeviceObject);
266
267 NTSTATUS
268 RxFindOrCreateFcb(
269 PRX_CONTEXT RxContext,
270 PUNICODE_STRING NetRootName);
271
272 NTSTATUS
273 RxFirstCanonicalize(
274 PRX_CONTEXT RxContext,
275 PUNICODE_STRING FileName,
276 PUNICODE_STRING CanonicalName,
277 PNET_ROOT_TYPE NetRootType);
278
279 VOID
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context);
282
283 VOID
284 NTAPI
285 RxFspDispatch(
286 IN PVOID Context);
287
288 VOID
289 NTAPI
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath);
292
293 NTSTATUS
294 NTAPI
295 RxGetStringRegistryParameter(
296 IN HANDLE KeyHandle,
297 IN PCWSTR KeyName,
298 OUT PUNICODE_STRING OutString,
299 IN PUCHAR Buffer,
300 IN ULONG BufferLength,
301 IN BOOLEAN LogFailure);
302
303 VOID
304 NTAPI
305 RxInitializeDebugSupport(
306 VOID);
307
308 VOID
309 NTAPI
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject);
312
313 NTSTATUS
314 NTAPI
315 RxInitializeRegistrationStructures(
316 VOID);
317
318 VOID
319 NTAPI
320 RxInitializeTopLevelIrpPackage(
321 VOID);
322
323 VOID
324 NTAPI
325 RxInitUnwind(
326 PDRIVER_OBJECT DriverObject,
327 USHORT State);
328
329 BOOLEAN
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332
333 NTSTATUS
334 NTAPI
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext);
337
338 NTSTATUS
339 RxLowIoReadShell(
340 PRX_CONTEXT RxContext);
341
342 NTSTATUS
343 NTAPI
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext);
346
347 PVOID
348 RxNewMapUserBuffer(
349 PRX_CONTEXT RxContext);
350
351 NTSTATUS
352 RxNotifyChangeDirectory(
353 PRX_CONTEXT RxContext);
354
355 NTSTATUS
356 RxpQueryInfoMiniRdr(
357 PRX_CONTEXT RxContext,
358 FILE_INFORMATION_CLASS FileInfoClass,
359 PVOID Buffer);
360
361 VOID
362 RxPurgeNetFcb(
363 PFCB Fcb,
364 PRX_CONTEXT LocalContext);
365
366 NTSTATUS
367 RxQueryAlternateNameInfo(
368 PRX_CONTEXT RxContext,
369 PFILE_NAME_INFORMATION AltNameInfo);
370
371 NTSTATUS
372 RxQueryBasicInfo(
373 PRX_CONTEXT RxContext,
374 PFILE_BASIC_INFORMATION BasicInfo);
375
376 NTSTATUS
377 RxQueryCompressedInfo(
378 PRX_CONTEXT RxContext,
379 PFILE_COMPRESSION_INFORMATION CompressionInfo);
380
381 NTSTATUS
382 RxQueryDirectory(
383 PRX_CONTEXT RxContext);
384
385 NTSTATUS
386 RxQueryEaInfo(
387 PRX_CONTEXT RxContext,
388 PFILE_EA_INFORMATION EaInfo);
389
390 NTSTATUS
391 RxQueryInternalInfo(
392 PRX_CONTEXT RxContext,
393 PFILE_INTERNAL_INFORMATION InternalInfo);
394
395 NTSTATUS
396 RxQueryNameInfo(
397 PRX_CONTEXT RxContext,
398 PFILE_NAME_INFORMATION NameInfo);
399
400 NTSTATUS
401 RxQueryPipeInfo(
402 PRX_CONTEXT RxContext,
403 PFILE_PIPE_INFORMATION PipeInfo);
404
405 NTSTATUS
406 RxQueryPositionInfo(
407 PRX_CONTEXT RxContext,
408 PFILE_POSITION_INFORMATION PositionInfo);
409
410 NTSTATUS
411 RxQueryStandardInfo(
412 PRX_CONTEXT RxContext,
413 PFILE_STANDARD_INFORMATION StandardInfo);
414
415 VOID
416 NTAPI
417 RxReadRegistryParameters(
418 VOID);
419
420 VOID
421 NTAPI
422 RxReleaseFileForNtCreateSection(
423 PFILE_OBJECT FileObject);
424
425 NTSTATUS
426 NTAPI
427 RxReleaseForCcFlush(
428 PFILE_OBJECT FileObject,
429 PDEVICE_OBJECT DeviceObject);
430
431 PRX_CONTEXT
432 RxRemoveOverflowEntry(
433 PRDBSS_DEVICE_OBJECT DeviceObject,
434 WORK_QUEUE_TYPE Queue);
435
436 NTSTATUS
437 RxSearchForCollapsibleOpen(
438 PRX_CONTEXT RxContext,
439 ACCESS_MASK DesiredAccess,
440 ULONG ShareAccess);
441
442 VOID
443 RxSetupNetFileObject(
444 PRX_CONTEXT RxContext);
445
446 NTSTATUS
447 RxSystemControl(
448 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
449 IN PIRP Irp);
450
451 VOID
452 RxUninitializeCacheMap(
453 PRX_CONTEXT RxContext,
454 PFILE_OBJECT FileObject,
455 PLARGE_INTEGER TruncateSize);
456
457 VOID
458 RxUnstart(
459 PRX_CONTEXT Context,
460 PRDBSS_DEVICE_OBJECT DeviceObject);
461
462 NTSTATUS
463 RxXXXControlFileCallthru(
464 PRX_CONTEXT Context);
465
466 PVOID
467 NTAPI
468 _RxAllocatePoolWithTag(
469 _In_ POOL_TYPE PoolType,
470 _In_ SIZE_T NumberOfBytes,
471 _In_ ULONG Tag);
472
473 VOID
474 NTAPI
475 _RxFreePool(
476 _In_ PVOID Buffer);
477
478 VOID
479 NTAPI
480 _RxFreePoolWithTag(
481 _In_ PVOID Buffer,
482 _In_ ULONG Tag);
483
484 WCHAR RxStarForTemplate = '*';
485 WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
486 BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
487 BOOLEAN DisableFlushOnCleanup = FALSE;
488 ULONG ReadAheadGranularity = 1 << PAGE_SHIFT;
489 LIST_ENTRY RxActiveContexts;
490 NPAGED_LOOKASIDE_LIST RxContextLookasideList;
491 FAST_MUTEX RxContextPerFileSerializationMutex;
492 RDBSS_DATA RxData;
493 FCB RxDeviceFCB;
494 BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
495 RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
496 {
497 { RxCommonDispatchProblem },
498 { RxCommonDispatchProblem },
499 { RxCommonDevFCBClose },
500 { RxCommonDispatchProblem },
501 { RxCommonDispatchProblem },
502 { RxCommonDispatchProblem },
503 { RxCommonDispatchProblem },
504 { RxCommonDispatchProblem },
505 { RxCommonDispatchProblem },
506 { RxCommonDispatchProblem },
507 { RxCommonDevFCBQueryVolInfo },
508 { RxCommonDispatchProblem },
509 { RxCommonDispatchProblem },
510 { RxCommonDevFCBFsCtl },
511 { RxCommonDevFCBIoCtl },
512 { RxCommonDevFCBIoCtl },
513 { RxCommonDispatchProblem },
514 { RxCommonDispatchProblem },
515 { RxCommonDevFCBCleanup },
516 { RxCommonDispatchProblem },
517 { RxCommonDispatchProblem },
518 { RxCommonDispatchProblem },
519 { RxCommonUnimplemented },
520 { RxCommonUnimplemented },
521 { RxCommonUnimplemented },
522 { RxCommonUnimplemented },
523 { RxCommonUnimplemented },
524 { RxCommonUnimplemented },
525 };
526 RDBSS_EXPORTS RxExports;
527 FAST_IO_DISPATCH RxFastIoDispatch;
528 PRDBSS_DEVICE_OBJECT RxFileSystemDeviceObject;
529 RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
530 {
531 { RxCommonCreate },
532 { RxCommonUnimplemented },
533 { RxCommonClose },
534 { RxCommonRead },
535 { RxCommonWrite },
536 { RxCommonQueryInformation },
537 { RxCommonSetInformation },
538 { RxCommonQueryEa },
539 { RxCommonSetEa },
540 { RxCommonFlushBuffers },
541 { RxCommonQueryVolumeInformation },
542 { RxCommonSetVolumeInformation },
543 { RxCommonDirectoryControl },
544 { RxCommonFileSystemControl },
545 { RxCommonDeviceControl },
546 { RxCommonDeviceControl },
547 { RxCommonUnimplemented },
548 { RxCommonLockControl },
549 { RxCommonCleanup },
550 { RxCommonUnimplemented },
551 { RxCommonQuerySecurity },
552 { RxCommonSetSecurity },
553 { RxCommonUnimplemented },
554 { RxCommonUnimplemented },
555 { RxCommonUnimplemented },
556 { RxCommonQueryQuotaInformation },
557 { RxCommonSetQuotaInformation },
558 { RxCommonUnimplemented },
559 };
560 ULONG RxFsdEntryCount;
561 LIST_ENTRY RxIrpsList;
562 KSPIN_LOCK RxIrpsListSpinLock;
563 KMUTEX RxScavengerMutex;
564 KMUTEX RxSerializationMutex;
565 UCHAR RxSpaceForTheWrappersDeviceObject[sizeof(*RxFileSystemDeviceObject)];
566 KSPIN_LOCK TopLevelIrpSpinLock;
567 LIST_ENTRY TopLevelIrpAllocatedContextsList;
568 BOOLEAN RxForceQFIPassThrough = FALSE;
569
570 DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
571
572 #if RDBSS_ASSERTS
573 #ifdef ASSERT
574 #undef ASSERT
575 #endif
576
577 #define ASSERT(exp) \
578 if (!(exp)) \
579 { \
580 RxAssert(#exp, __FILE__, __LINE__, NULL); \
581 }
582 #endif
583
584 #if RX_POOL_WRAPPER
585 #undef RxAllocatePool
586 #undef RxAllocatePoolWithTag
587 #undef RxFreePool
588
589 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
590 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
591 #define RxFreePool _RxFreePool
592 #define RxFreePoolWithTag _RxFreePoolWithTag
593 #endif
594
595 /* FUNCTIONS ****************************************************************/
596
597 /*
598 * @implemented
599 */
600 VOID
601 CheckForLoudOperations(
602 PRX_CONTEXT RxContext)
603 {
604 PAGED_CODE();
605
606 #define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
607
608 /* Are loud operations enabled? */
609 if (RxLoudLowIoOpsEnabled)
610 {
611 PFCB Fcb;
612
613 /* If so, the operation will be loud only if filename ends with all.scr */
614 Fcb = (PFCB)RxContext->pFcb;
615 if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
616 L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
617 {
618 SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
619 }
620 }
621 #undef ALLSCR_LENGTH
622 }
623
624 /*
625 * @implemented
626 */
627 VOID
628 __RxInitializeTopLevelIrpContext(
629 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
630 IN PIRP Irp,
631 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
632 IN ULONG Flags)
633 {
634 DPRINT("__RxInitializeTopLevelIrpContext(%p, %p, %p, %u)\n", TopLevelContext, Irp, RxDeviceObject, Flags);
635
636 RtlZeroMemory(TopLevelContext, sizeof(RX_TOPLEVELIRP_CONTEXT));
637 TopLevelContext->Irp = Irp;
638 TopLevelContext->Flags = (Flags ? RX_TOPLEVELCTX_FLAG_FROM_POOL : 0);
639 TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
640 TopLevelContext->RxDeviceObject = RxDeviceObject;
641 TopLevelContext->Previous = IoGetTopLevelIrp();
642 TopLevelContext->Thread = PsGetCurrentThread();
643
644 /* We cannot add to list something that'd come from stack */
645 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
646 {
647 RxAddToTopLevelIrpAllocatedContextsList(TopLevelContext);
648 }
649 }
650
651 NTSTATUS
652 NTAPI
653 RxAcquireExclusiveFcbResourceInMRx(
654 _Inout_ PMRX_FCB Fcb)
655 {
656 UNIMPLEMENTED;
657 return STATUS_NOT_IMPLEMENTED;
658 }
659
660 BOOLEAN
661 NTAPI
662 RxAcquireFcbForLazyWrite(
663 PVOID Context,
664 BOOLEAN Wait)
665 {
666 UNIMPLEMENTED;
667 return FALSE;
668 }
669
670 BOOLEAN
671 NTAPI
672 RxAcquireFcbForReadAhead(
673 PVOID Context,
674 BOOLEAN Wait)
675 {
676 UNIMPLEMENTED;
677 return FALSE;
678 }
679
680 VOID
681 NTAPI
682 RxAcquireFileForNtCreateSection(
683 PFILE_OBJECT FileObject)
684 {
685 UNIMPLEMENTED;
686 }
687
688 NTSTATUS
689 NTAPI
690 RxAcquireForCcFlush(
691 PFILE_OBJECT FileObject,
692 PDEVICE_OBJECT DeviceObject)
693 {
694 UNIMPLEMENTED;
695 return STATUS_NOT_IMPLEMENTED;
696 }
697
698 /*
699 * @implemented
700 */
701 VOID
702 RxAddToTopLevelIrpAllocatedContextsList(
703 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
704 {
705 KIRQL OldIrql;
706
707 DPRINT("RxAddToTopLevelIrpAllocatedContextsList(%p)\n", TopLevelContext);
708
709 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
710 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
711
712 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
713 InsertTailList(&TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry);
714 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
715 }
716
717 /*
718 * @implemented
719 */
720 VOID
721 RxAddToWorkque(
722 IN PRX_CONTEXT RxContext,
723 IN PIRP Irp)
724 {
725 ULONG Queued;
726 KIRQL OldIrql;
727 WORK_QUEUE_TYPE Queue;
728 PIO_STACK_LOCATION Stack;
729
730 Stack = RxContext->CurrentIrpSp;
731 RxContext->PostRequest = FALSE;
732
733 /* First of all, select the appropriate queue - delayed for prefix claim, critical for the rest */
734 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
735 Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
736 {
737 Queue = DelayedWorkQueue;
738 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE);
739 }
740 else
741 {
742 Queue = CriticalWorkQueue;
743 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE);
744 }
745
746 /* Check for overflow */
747 if (Stack->FileObject != NULL)
748 {
749 KeAcquireSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, &OldIrql);
750
751 Queued = InterlockedIncrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
752 /* In case of an overflow, add the new queued call to the overflow list */
753 if (Queued > 1)
754 {
755 InterlockedDecrement(&RxFileSystemDeviceObject->PostedRequestCount[Queue]);
756 InsertTailList(&RxFileSystemDeviceObject->OverflowQueue[Queue], &RxContext->OverflowListEntry);
757 ++RxFileSystemDeviceObject->OverflowQueueCount[Queue];
758
759 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
760 return;
761 }
762
763 KeReleaseSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock, OldIrql);
764 }
765
766 ExInitializeWorkItem(&RxContext->WorkQueueItem, RxFspDispatch, RxContext);
767 ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
768 }
769
770 /*
771 * @implemented
772 */
773 VOID
774 RxAdjustFileTimesAndSize(
775 PRX_CONTEXT Context)
776 {
777 PFCB Fcb;
778 PFOBX Fobx;
779 NTSTATUS Status;
780 PFILE_OBJECT FileObject;
781 LARGE_INTEGER CurrentTime;
782 FILE_BASIC_INFORMATION FileBasicInfo;
783 FILE_END_OF_FILE_INFORMATION FileEOFInfo;
784 BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
785
786 PAGED_CODE();
787
788 FileObject = Context->CurrentIrpSp->FileObject;
789 /* If Cc isn't initialized, the file was not read nor written, nothing to do */
790 if (FileObject->PrivateCacheMap == NULL)
791 {
792 return;
793 }
794
795 /* Get now */
796 KeQuerySystemTime(&CurrentTime);
797
798 Fobx = (PFOBX)Context->pFobx;
799 /* Was the file modified? */
800 FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
801 /* We'll set last write if it was modified and user didn't update yet */
802 SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
803 /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
804 SetLastAccess = SetLastWrite ||
805 (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
806 !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
807 /* We'll set last change if it was modified and user didn't update yet */
808 SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
809
810 /* Nothing to update? Job done */
811 if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
812 {
813 return;
814 }
815
816 Fcb = (PFCB)Context->pFcb;
817 /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
818 NeedUpdate = FALSE;
819 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
820
821 /* Update lastwrite time if required */
822 if (SetLastWrite)
823 {
824 NeedUpdate = TRUE;
825 Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
826 FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
827 }
828
829 /* Update lastaccess time if required */
830 if (SetLastAccess)
831 {
832 NeedUpdate = TRUE;
833 Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
834 FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
835 }
836
837 /* Update lastchange time if required */
838 if (SetLastChange)
839 {
840 NeedUpdate = TRUE;
841 Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
842 FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
843 }
844
845 /* If one of the date was modified, issue a call to mini-rdr */
846 if (NeedUpdate)
847 {
848 Context->Info.FileInformationClass = FileBasicInformation;
849 Context->Info.Buffer = &FileBasicInfo;
850 Context->Info.Length = sizeof(FileBasicInfo);
851
852 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
853 (void)Status;
854 }
855
856 /* If the file was modified, update its EOF */
857 if (FileModified)
858 {
859 FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
860
861 Context->Info.FileInformationClass = FileEndOfFileInformation;
862 Context->Info.Buffer = &FileEOFInfo;
863 Context->Info.Length = sizeof(FileEOFInfo);
864
865 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
866 (void)Status;
867 }
868 }
869
870 /*
871 * @implemented
872 */
873 NTSTATUS
874 RxAllocateCanonicalNameBuffer(
875 PRX_CONTEXT RxContext,
876 PUNICODE_STRING CanonicalName,
877 USHORT CanonicalLength)
878 {
879 PAGED_CODE();
880
881 DPRINT("RxContext: %p - CanonicalNameBuffer: %p\n", RxContext, RxContext->Create.CanonicalNameBuffer);
882
883 /* Context must be free of any already allocated name */
884 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
885
886 /* Validate string length */
887 if (CanonicalLength > USHRT_MAX - 1)
888 {
889 CanonicalName->Buffer = NULL;
890 return STATUS_OBJECT_PATH_INVALID;
891 }
892
893 CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
894 if (CanonicalName->Buffer == NULL)
895 {
896 return STATUS_INSUFFICIENT_RESOURCES;
897 }
898
899 CanonicalName->Length = 0;
900 CanonicalName->MaximumLength = CanonicalLength;
901
902 /* Set the two places - they must always be identical */
903 RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
904 RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
905
906 return STATUS_SUCCESS;
907 }
908
909 VOID
910 RxCancelNotifyChangeDirectoryRequestsForFobx(
911 PFOBX Fobx)
912 {
913 UNIMPLEMENTED;
914 }
915
916 NTSTATUS
917 RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
918 PV_NET_ROOT VNetRoot,
919 BOOLEAN ForceFilesClosed)
920 {
921 UNIMPLEMENTED;
922 return STATUS_NOT_IMPLEMENTED;
923 }
924
925 VOID
926 NTAPI
927 RxCancelRoutine(
928 PDEVICE_OBJECT DeviceObject,
929 PIRP Irp)
930 {
931 UNIMPLEMENTED;
932 }
933
934 /*
935 * @implemented
936 */
937 NTSTATUS
938 RxCanonicalizeFileNameByServerSpecs(
939 PRX_CONTEXT RxContext,
940 PUNICODE_STRING NetRootName)
941 {
942 USHORT NextChar, CurChar;
943 USHORT MaxChars;
944
945 PAGED_CODE();
946
947 /* Validate file name is not empty */
948 MaxChars = NetRootName->Length / sizeof(WCHAR);
949 if (MaxChars == 0)
950 {
951 return STATUS_MORE_PROCESSING_REQUIRED;
952 }
953
954 /* Validate name is correct */
955 for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
956 {
957 USHORT i;
958
959 for (i = NextChar + 1; i < MaxChars; ++i)
960 {
961 if (NetRootName->Buffer[i] == '\\' || NetRootName->Buffer[i] == ':')
962 {
963 break;
964 }
965 }
966
967 CurChar = i - 1;
968 if (CurChar == NextChar)
969 {
970 if (((NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':') || NextChar == (MaxChars - 1)) && NetRootName->Buffer[NextChar] != '.')
971 {
972 continue;
973 }
974
975 if (CurChar != 0)
976 {
977 if (CurChar >= MaxChars - 1)
978 {
979 continue;
980 }
981
982 if (NetRootName->Buffer[CurChar + 1] != ':')
983 {
984 return STATUS_OBJECT_PATH_SYNTAX_BAD;
985 }
986 }
987 else
988 {
989 if (NetRootName->Buffer[1] != ':')
990 {
991 return STATUS_OBJECT_PATH_SYNTAX_BAD;
992 }
993 }
994 }
995 else
996 {
997 if ((CurChar - NextChar) == 1)
998 {
999 if (NetRootName->Buffer[NextChar + 2] != '.')
1000 {
1001 continue;
1002 }
1003
1004 if (NetRootName->Buffer[NextChar] == '\\' || NetRootName->Buffer[NextChar] == ':' || NetRootName->Buffer[NextChar] == '.')
1005 {
1006 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1007 }
1008 }
1009 else
1010 {
1011 if ((CurChar - NextChar) != 2 || (NetRootName->Buffer[NextChar] != '\\' && NetRootName->Buffer[NextChar] != ':')
1012 || NetRootName->Buffer[NextChar + 1] != '.')
1013 {
1014 continue;
1015 }
1016
1017 if (NetRootName->Buffer[NextChar + 2] == '.')
1018 {
1019 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1020 }
1021 }
1022 }
1023 }
1024
1025 return STATUS_MORE_PROCESSING_REQUIRED;
1026 }
1027
1028 NTSTATUS
1029 RxCanonicalizeNameAndObtainNetRoot(
1030 PRX_CONTEXT RxContext,
1031 PUNICODE_STRING FileName,
1032 PUNICODE_STRING NetRootName)
1033 {
1034 NTSTATUS Status;
1035 NET_ROOT_TYPE NetRootType;
1036 UNICODE_STRING CanonicalName;
1037
1038 PAGED_CODE();
1039
1040 NetRootType = NET_ROOT_WILD;
1041
1042 RtlInitEmptyUnicodeString(NetRootName, NULL, 0);
1043 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
1044
1045 /* if not relative opening, just handle the passed name */
1046 if (RxContext->CurrentIrpSp->FileObject->RelatedFileObject == NULL)
1047 {
1048 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1049 if (!NT_SUCCESS(Status))
1050 {
1051 return Status;
1052 }
1053 }
1054 else
1055 {
1056 PFCB Fcb;
1057
1058 /* Make sure we have a valid FCB and a FOBX */
1059 Fcb = RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext;
1060 if (Fcb == NULL ||
1061 RxContext->CurrentIrpSp->FileObject->RelatedFileObject->FsContext2 == NULL)
1062 {
1063 return STATUS_INVALID_PARAMETER;
1064 }
1065
1066 if (!NodeTypeIsFcb(Fcb))
1067 {
1068 return STATUS_INVALID_PARAMETER;
1069 }
1070
1071 UNIMPLEMENTED;
1072 }
1073
1074 /* Get/Create the associated VNetRoot for opening */
1075 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1076 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING &&
1077 BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MAILSLOT_REPARSE))
1078 {
1079 ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
1080
1081 RxFreeCanonicalNameBuffer(RxContext);
1082 Status = RxFirstCanonicalize(RxContext, FileName, &CanonicalName, &NetRootType);
1083 if (NT_SUCCESS(Status))
1084 {
1085 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, NetRootName);
1086 }
1087 }
1088
1089 /* Filename cannot contain wildcards */
1090 if (FsRtlDoesNameContainWildCards(NetRootName))
1091 {
1092 Status = STATUS_OBJECT_NAME_INVALID;
1093 }
1094
1095 /* Make sure file name is correct */
1096 if (NT_SUCCESS(Status))
1097 {
1098 Status = RxCanonicalizeFileNameByServerSpecs(RxContext, NetRootName);
1099 }
1100
1101 /* Give the mini-redirector a chance to prepare the name */
1102 if (NT_SUCCESS(Status) || Status == STATUS_MORE_PROCESSING_REQUIRED)
1103 {
1104 if (RxContext->Create.pNetRoot != NULL)
1105 {
1106 NTSTATUS IgnoredStatus;
1107
1108 MINIRDR_CALL(IgnoredStatus, RxContext, RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
1109 MRxPreparseName, (RxContext, NetRootName));
1110 (void)IgnoredStatus;
1111 }
1112 }
1113
1114 return Status;
1115 }
1116
1117 VOID
1118 NTAPI
1119 RxCheckFcbStructuresForAlignment(
1120 VOID)
1121 {
1122 UNIMPLEMENTED;
1123 }
1124
1125 NTSTATUS
1126 RxCheckShareAccess(
1127 _In_ ACCESS_MASK DesiredAccess,
1128 _In_ ULONG DesiredShareAccess,
1129 _Inout_ PFILE_OBJECT FileObject,
1130 _Inout_ PSHARE_ACCESS ShareAccess,
1131 _In_ BOOLEAN Update,
1132 _In_ PSZ where,
1133 _In_ PSZ wherelogtag)
1134 {
1135 PAGED_CODE();
1136
1137 RxDumpWantedAccess(where, "", wherelogtag, DesiredAccess, DesiredShareAccess);
1138 RxDumpCurrentAccess(where, "", wherelogtag, ShareAccess);
1139
1140 return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
1141 }
1142
1143 /*
1144 * @implemented
1145 */
1146 NTSTATUS
1147 RxCheckShareAccessPerSrvOpens(
1148 IN PFCB Fcb,
1149 IN ACCESS_MASK DesiredAccess,
1150 IN ULONG DesiredShareAccess)
1151 {
1152 BOOLEAN ReadAccess;
1153 BOOLEAN WriteAccess;
1154 BOOLEAN DeleteAccess;
1155 PSHARE_ACCESS ShareAccess;
1156
1157 PAGED_CODE();
1158
1159 ShareAccess = &Fcb->ShareAccessPerSrvOpens;
1160
1161 RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", DesiredAccess, DesiredShareAccess);
1162 RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens", "", "RxCheckShareAccessPerSrvOpens", ShareAccess);
1163
1164 /* Check if any access wanted */
1165 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
1166 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
1167 DeleteAccess = (DesiredAccess & DELETE) != 0;
1168
1169 if (ReadAccess || WriteAccess || DeleteAccess)
1170 {
1171 BOOLEAN SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
1172 BOOLEAN SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
1173 BOOLEAN SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
1174
1175 /* Check whether there's a violation */
1176 if ((ReadAccess &&
1177 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
1178 (WriteAccess &&
1179 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
1180 (DeleteAccess &&
1181 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
1182 ((ShareAccess->Readers != 0) && !SharedRead) ||
1183 ((ShareAccess->Writers != 0) && !SharedWrite) ||
1184 ((ShareAccess->Deleters != 0) && !SharedDelete))
1185 {
1186 return STATUS_SHARING_VIOLATION;
1187 }
1188 }
1189
1190 return STATUS_SUCCESS;
1191 }
1192
1193 VOID
1194 RxCleanupPipeQueues(
1195 PRX_CONTEXT Context)
1196 {
1197 UNIMPLEMENTED;
1198 }
1199
1200 /*
1201 * @implemented
1202 */
1203 NTSTATUS
1204 RxCloseAssociatedSrvOpen(
1205 IN PFOBX Fobx,
1206 IN PRX_CONTEXT RxContext OPTIONAL)
1207 {
1208 PFCB Fcb;
1209 NTSTATUS Status;
1210 PSRV_OPEN SrvOpen;
1211 BOOLEAN CloseSrvOpen;
1212 PRX_CONTEXT LocalContext;
1213
1214 PAGED_CODE();
1215
1216 /* Assume SRV_OPEN is already closed */
1217 CloseSrvOpen = FALSE;
1218 /* If we have a FOBX, we'll have to close it */
1219 if (Fobx != NULL)
1220 {
1221 /* If the FOBX isn't closed yet */
1222 if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
1223 {
1224 SrvOpen = Fobx->SrvOpen;
1225 Fcb = (PFCB)SrvOpen->pFcb;
1226 /* Check whether we've to close SRV_OPEN first */
1227 if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1228 {
1229 CloseSrvOpen = TRUE;
1230 }
1231 else
1232 {
1233 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1234
1235 /* Not much to do */
1236 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1237
1238 if (SrvOpen->OpenCount > 0)
1239 {
1240 --SrvOpen->OpenCount;
1241 }
1242 }
1243 }
1244
1245 /* No need to close SRV_OPEN, so close FOBX */
1246 if (!CloseSrvOpen)
1247 {
1248 RxMarkFobxOnClose(Fobx);
1249
1250 return STATUS_SUCCESS;
1251 }
1252 }
1253 else
1254 {
1255 /* No FOBX? No RX_CONTEXT, ok, job done! */
1256 if (RxContext == NULL)
1257 {
1258 return STATUS_SUCCESS;
1259 }
1260
1261 /* Get the FCB from RX_CONTEXT */
1262 Fcb = (PFCB)RxContext->pFcb;
1263 SrvOpen = NULL;
1264 }
1265
1266 /* If we don't have RX_CONTEXT, allocte one, we'll need it */
1267 if (RxContext == NULL)
1268 {
1269 ASSERT(Fobx != NULL);
1270
1271 LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
1272 if (LocalContext == NULL)
1273 {
1274 return STATUS_INSUFFICIENT_RESOURCES;
1275 }
1276
1277 LocalContext->MajorFunction = 2;
1278 LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
1279 LocalContext->pFobx = (PMRX_FOBX)Fobx;
1280 LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
1281 }
1282 else
1283 {
1284 LocalContext = RxContext;
1285 }
1286
1287 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1288
1289 /* Now, close the FOBX */
1290 if (Fobx != NULL)
1291 {
1292 RxMarkFobxOnClose(Fobx);
1293 }
1294 else
1295 {
1296 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
1297 }
1298
1299 /* If not a "standard" file, SRV_OPEN can be null */
1300 if (SrvOpen == NULL)
1301 {
1302 ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
1303 RxDereferenceNetFcb(Fcb);
1304
1305 if (LocalContext != RxContext)
1306 {
1307 RxDereferenceAndDeleteRxContext(LocalContext);
1308 }
1309
1310 return STATUS_SUCCESS;
1311 }
1312
1313 /* If SRV_OPEN isn't in a good condition, nothing to close */
1314 if (SrvOpen->Condition != Condition_Good)
1315 {
1316 if (LocalContext != RxContext)
1317 {
1318 RxDereferenceAndDeleteRxContext(LocalContext);
1319 }
1320
1321 return STATUS_SUCCESS;
1322 }
1323
1324 /* Decrease open count */
1325 if (SrvOpen->OpenCount > 0)
1326 {
1327 --SrvOpen->OpenCount;
1328 }
1329
1330 /* If we're the only one left, is there a FOBX handled by Scavenger? */
1331 if (SrvOpen->OpenCount == 1)
1332 {
1333 if (!IsListEmpty(&SrvOpen->FobxList))
1334 {
1335 if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
1336 {
1337 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1338 }
1339 }
1340 }
1341
1342 /* Nothing left, purge FCB */
1343 if (SrvOpen->OpenCount == 0 && RxContext == NULL)
1344 {
1345 RxPurgeNetFcb(Fcb, LocalContext);
1346 }
1347
1348 /* Already closed? Job done! */
1349 SrvOpen = Fobx->SrvOpen;
1350 if (SrvOpen == NULL ||
1351 (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
1352 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
1353 {
1354 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1355 if (LocalContext != RxContext)
1356 {
1357 RxDereferenceAndDeleteRxContext(LocalContext);
1358 }
1359
1360 return STATUS_SUCCESS;
1361 }
1362
1363 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1364
1365 /* Inform mini-rdr about closing */
1366 MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
1367 DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
1368 Status, RxContext, Fobx, Fcb, SrvOpen);
1369
1370 /* And mark as such */
1371 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
1372 SrvOpen->Key = (PVOID)-1;
1373
1374 /* If we were delayed, we're not! */
1375 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
1376 {
1377 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
1378 }
1379
1380 /* Clear access */
1381 RxRemoveShareAccessPerSrvOpens(SrvOpen);
1382 RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
1383
1384 /* Dereference */
1385 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1386
1387 /* Mark the FOBX closed as well */
1388 SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
1389
1390 if (LocalContext != RxContext)
1391 {
1392 RxDereferenceAndDeleteRxContext(LocalContext);
1393 }
1394
1395 return Status;
1396 }
1397
1398 /*
1399 * @implemented
1400 */
1401 NTSTATUS
1402 RxCollapseOrCreateSrvOpen(
1403 PRX_CONTEXT RxContext)
1404 {
1405 PFCB Fcb;
1406 NTSTATUS Status;
1407 ULONG Disposition;
1408 PSRV_OPEN SrvOpen;
1409 USHORT ShareAccess;
1410 PIO_STACK_LOCATION Stack;
1411 ACCESS_MASK DesiredAccess;
1412 RX_BLOCK_CONDITION FcbCondition;
1413
1414 PAGED_CODE();
1415
1416 DPRINT("RxCollapseOrCreateSrvOpen(%p)\n", RxContext);
1417
1418 Fcb = (PFCB)RxContext->pFcb;
1419 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1420 ++Fcb->UncleanCount;
1421
1422 Stack = RxContext->CurrentIrpSp;
1423 DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
1424 ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
1425
1426 Disposition = RxContext->Create.NtCreateParameters.Disposition;
1427
1428 /* Try to find a reusable SRV_OPEN */
1429 Status = RxSearchForCollapsibleOpen(RxContext, DesiredAccess, ShareAccess);
1430 if (Status == STATUS_NOT_FOUND)
1431 {
1432 /* If none found, create one */
1433 SrvOpen = RxCreateSrvOpen((PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb);
1434 if (SrvOpen == NULL)
1435 {
1436 Status = STATUS_INSUFFICIENT_RESOURCES;
1437 }
1438 else
1439 {
1440 SrvOpen->DesiredAccess = DesiredAccess;
1441 SrvOpen->ShareAccess = ShareAccess;
1442 Status = STATUS_SUCCESS;
1443 }
1444
1445 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
1446
1447 if (Status != STATUS_SUCCESS)
1448 {
1449 FcbCondition = Condition_Bad;
1450 }
1451 else
1452 {
1453 RxInitiateSrvOpenKeyAssociation(SrvOpen);
1454
1455 /* Cookie to check the mini-rdr doesn't mess with RX_CONTEXT */
1456 RxContext->CurrentIrp->IoStatus.Information = 0xABCDEF;
1457 /* Inform the mini-rdr we're handling a create */
1458 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCreate, (RxContext));
1459 ASSERT(RxContext->CurrentIrp->IoStatus.Information == 0xABCDEF);
1460
1461 DPRINT("MRxCreate returned: %x\n", Status);
1462 if (Status == STATUS_SUCCESS)
1463 {
1464 /* In case of overwrite, reset file size */
1465 if (Disposition == FILE_OVERWRITE || Disposition == FILE_OVERWRITE_IF)
1466 {
1467 RxAcquirePagingIoResource(RxContext, Fcb);
1468 Fcb->Header.AllocationSize.QuadPart = 0LL;
1469 Fcb->Header.FileSize.QuadPart = 0LL;
1470 Fcb->Header.ValidDataLength.QuadPart = 0LL;
1471 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1472 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1473 RxReleasePagingIoResource(RxContext, Fcb);
1474 }
1475 else
1476 {
1477 /* Otherwise, adjust sizes */
1478 RxContext->CurrentIrpSp->FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
1479 if (CcIsFileCached(RxContext->CurrentIrpSp->FileObject))
1480 {
1481 RxAdjustAllocationSizeforCC(Fcb);
1482 }
1483 CcSetFileSizes(RxContext->CurrentIrpSp->FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1484 }
1485 }
1486
1487 /* Set the IoStatus with information returned by mini-rdr */
1488 RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
1489
1490 SrvOpen->OpenStatus = Status;
1491 /* Set SRV_OPEN state - good or bad - depending on whether create succeed */
1492 RxTransitionSrvOpen(SrvOpen, (Status == STATUS_SUCCESS ? Condition_Good : Condition_Bad));
1493
1494 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1495
1496 RxCompleteSrvOpenKeyAssociation(SrvOpen);
1497
1498 if (Status == STATUS_SUCCESS)
1499 {
1500 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
1501 {
1502 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
1503 }
1504 SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
1505 FcbCondition = Condition_Good;
1506 }
1507 else
1508 {
1509 FcbCondition = Condition_Bad;
1510 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1511 RxContext->pRelevantSrvOpen = NULL;
1512
1513 if (RxContext->pFobx != NULL)
1514 {
1515 RxDereferenceNetFobx(RxContext->pFobx, LHS_ExclusiveLockHeld);
1516 RxContext->pFobx = NULL;
1517 }
1518 }
1519 }
1520
1521 /* Set FCB state - good or bad - depending on whether create succeed */
1522 DPRINT("Transitioning FCB %p to condition %lx\n", Fcb, Fcb->Condition);
1523 RxTransitionNetFcb(Fcb, FcbCondition);
1524 }
1525 else if (Status == STATUS_SUCCESS)
1526 {
1527 BOOLEAN IsGood, ExtraOpen;
1528
1529 /* A reusable SRV_OPEN was found */
1530 RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
1531 ExtraOpen = FALSE;
1532
1533 SrvOpen = (PSRV_OPEN)RxContext->pRelevantSrvOpen;
1534
1535 IsGood = (SrvOpen->Condition == Condition_Good);
1536 /* If the SRV_OPEN isn't in a stable situation, wait for it to become stable */
1537 if (!StableCondition(SrvOpen->Condition))
1538 {
1539 RxReferenceSrvOpen(SrvOpen);
1540 ++SrvOpen->OpenCount;
1541 ExtraOpen = TRUE;
1542
1543 RxReleaseFcb(RxContext, Fcb);
1544 RxContext->Create.FcbAcquired = FALSE;
1545
1546 RxWaitForStableSrvOpen(SrvOpen, RxContext);
1547
1548 if (NT_SUCCESS(RxAcquireExclusiveFcb(RxContext, Fcb)))
1549 {
1550 RxContext->Create.FcbAcquired = TRUE;
1551 }
1552
1553 IsGood = (SrvOpen->Condition == Condition_Good);
1554 }
1555
1556 /* Inform the mini-rdr we do an opening with a reused SRV_OPEN */
1557 if (IsGood)
1558 {
1559 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext));
1560
1561 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1562 }
1563 else
1564 {
1565 Status = SrvOpen->OpenStatus;
1566 }
1567
1568 if (ExtraOpen)
1569 {
1570 --SrvOpen->OpenCount;
1571 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
1572 }
1573 }
1574
1575 --Fcb->UncleanCount;
1576
1577 DPRINT("Status: %x\n", Status);
1578 return Status;
1579 }
1580
1581 NTSTATUS
1582 NTAPI
1583 RxCommonCleanup(
1584 PRX_CONTEXT Context)
1585 {
1586 #define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
1587 PFCB Fcb;
1588 PFOBX Fobx;
1589 ULONG OpenCount;
1590 NTSTATUS Status;
1591 PNET_ROOT NetRoot;
1592 PFILE_OBJECT FileObject;
1593 LARGE_INTEGER TruncateSize;
1594 PLARGE_INTEGER TruncateSizePtr;
1595 BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
1596
1597 PAGED_CODE();
1598
1599 Fcb = (PFCB)Context->pFcb;
1600 Fobx = (PFOBX)Context->pFobx;
1601 DPRINT("RxCommonCleanup(%p); FOBX: %p, FCB: %p\n", Context, Fobx, Fcb);
1602
1603 /* File system closing, it's OK */
1604 if (Fobx == NULL)
1605 {
1606 if (Fcb->UncleanCount > 0)
1607 {
1608 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1609 }
1610
1611 return STATUS_SUCCESS;
1612 }
1613
1614 /* Check we have a correct FCB type */
1615 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
1616 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
1617 NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1618 NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
1619 {
1620 DPRINT1("Invalid Fcb type for %p\n", Fcb);
1621 RxBugCheck(Fcb->Header.NodeTypeCode, 0, 0);
1622 }
1623
1624 FileObject = Context->CurrentIrpSp->FileObject;
1625 ASSERT(!BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE));
1626
1627 RxMarkFobxOnCleanup(Fobx, &NeedPurge);
1628
1629 Status = RxAcquireExclusiveFcb(Context, Fcb);
1630 if (!NT_SUCCESS(Status))
1631 {
1632 return Status;
1633 }
1634
1635 FcbAcquired = TRUE;
1636
1637 Fobx->AssociatedFileObject = NULL;
1638
1639 /* In case SRV_OPEN used is part of FCB */
1640 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED))
1641 {
1642 ASSERT(Fcb->UncleanCount != 0);
1643 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1644
1645 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1646 {
1647 --Fcb->UncachedUncleanCount;
1648 }
1649
1650 /* Inform mini-rdr */
1651 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1652
1653 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1654 --Fobx->SrvOpen->UncleanFobxCount;
1655
1656 RxUninitializeCacheMap(Context, FileObject, NULL);
1657
1658 RxReleaseFcb(Context, Fcb);
1659
1660 return STATUS_SUCCESS;
1661 }
1662
1663 /* Report the fact that file could be set as delete on close */
1664 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1665 {
1666 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
1667 }
1668
1669 /* Cancel any pending notification */
1670 RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
1671
1672 /* Backup open count before we start playing with it */
1673 OpenCount = Fcb->ShareAccess.OpenCount;
1674
1675 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1676 FcbTableAcquired = FALSE;
1677 LeftForDelete = FALSE;
1678 OneLeft = (Fcb->UncleanCount == 1);
1679
1680 _SEH2_TRY
1681 {
1682 /* Unclean count and delete on close? Verify whether we're the one */
1683 if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
1684 {
1685 if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
1686 {
1687 FcbTableAcquired = TRUE;
1688 }
1689 else
1690 {
1691 RxReleaseFcb(Context, Fcb);
1692
1693 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
1694
1695 Status = RxAcquireExclusiveFcb(Context, Fcb);
1696 if (Status != STATUS_SUCCESS)
1697 {
1698 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1699 return Status;
1700 }
1701
1702 FcbTableAcquired = TRUE;
1703 }
1704
1705 /* That means we'll perform the delete on close! */
1706 if (Fcb->UncleanCount == 1)
1707 {
1708 LeftForDelete = TRUE;
1709 }
1710 else
1711 {
1712 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1713 FcbTableAcquired = FALSE;
1714 }
1715 }
1716
1717 IsFile = FALSE;
1718 TruncateSizePtr = NULL;
1719 /* Handle cleanup for pipes and printers */
1720 if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
1721 {
1722 RxCleanupPipeQueues(Context);
1723 }
1724 /* Handle cleanup for files */
1725 else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
1726 {
1727 Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
1728 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
1729 {
1730 /* First, unlock */
1731 FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
1732
1733 /* If there are still locks to release, proceed */
1734 if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
1735 {
1736 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
1737 Context->LowIoContext.ParamsFor.Locks.Flags = 0;
1738 Status = RxLowIoLockControlShell(Context);
1739 }
1740
1741 /* Fix times and size */
1742 RxAdjustFileTimesAndSize(Context);
1743
1744 /* If we're the only one left... */
1745 if (OneLeft)
1746 {
1747 /* And if we're supposed to delete on close */
1748 if (LeftForDelete)
1749 {
1750 /* Update the sizes */
1751 RxAcquirePagingIoResource(Context, Fcb);
1752 Fcb->Header.FileSize.QuadPart = 0;
1753 Fcb->Header.ValidDataLength.QuadPart = 0;
1754 RxReleasePagingIoResource(Context, Fcb);
1755 }
1756 /* Otherwise, call the mini-rdr to adjust sizes */
1757 else
1758 {
1759 /* File got grown up, fill with zeroes */
1760 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
1761 (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
1762 {
1763 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
1764 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1765 }
1766
1767 /* File was truncated, let mini-rdr proceed */
1768 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
1769 {
1770 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
1771 ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
1772
1773 /* Keep track of file change for Cc uninit */
1774 TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
1775 TruncateSizePtr = &TruncateSize;
1776 }
1777 }
1778 }
1779
1780 /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
1781 if (NeedPurge)
1782 {
1783 if (!OneLeft)
1784 {
1785 NeedPurge = FALSE;
1786 }
1787 }
1788 /* Otherwise, try to see whether we can purge */
1789 else
1790 {
1791 NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
1792 }
1793
1794 IsFile = TRUE;
1795 }
1796 }
1797
1798 /* We have to still be there! */
1799 ASSERT(Fcb->UncleanCount != 0);
1800 InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
1801
1802 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1803 {
1804 --Fcb->UncachedUncleanCount;
1805 }
1806
1807 /* Inform mini-rdr about ongoing cleanup */
1808 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
1809
1810 ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
1811 --Fobx->SrvOpen->UncleanFobxCount;
1812
1813 /* Flush cache */
1814 if (DisableFlushOnCleanup)
1815 {
1816 /* Only if we're the last standing */
1817 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
1818 Fcb->UncleanCount == Fcb->UncachedUncleanCount)
1819 {
1820 DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
1821 RxFlushFcbInSystemCache(Fcb, TRUE);
1822 }
1823 }
1824 else
1825 {
1826 /* Always */
1827 if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
1828 {
1829 DPRINT("Flushing %p on cleanup\n", Context);
1830 RxFlushFcbInSystemCache(Fcb, TRUE);
1831 }
1832 }
1833
1834 /* If only remaining uncached & unclean, then flush and purge */
1835 if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
1836 {
1837 if (Fcb->UncachedUncleanCount != 0)
1838 {
1839 if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
1840 Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
1841 {
1842 DPRINT("Flushing FCB in system cache for %p\n", Context);
1843 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
1844 }
1845 }
1846 }
1847
1848 /* If purge required, and not about to delete, flush */
1849 if (!LeftForDelete && NeedPurge)
1850 {
1851 DPRINT("Flushing FCB in system cache for %p\n", Context);
1852 RxFlushFcbInSystemCache(Fcb, TRUE);
1853 }
1854
1855 /* If it was a file, drop cache */
1856 if (IsFile)
1857 {
1858 DPRINT("Uninit cache map for file\n");
1859 RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
1860 }
1861
1862 /* If that's the one left for deletion, or if it needs purge, flush */
1863 if (LeftForDelete || NeedPurge)
1864 {
1865 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
1866 /* If that's for deletion, also remove from FCB table */
1867 if (LeftForDelete)
1868 {
1869 RxRemoveNameNetFcb(Fcb);
1870 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1871 FcbTableAcquired = FALSE;
1872 }
1873 }
1874
1875 /* Remove any share access */
1876 if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
1877 {
1878 RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
1879 }
1880
1881 /* In case there's caching, on a file, update file metadata */
1882 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, 0x20000000) &&
1883 BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED) && !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING))
1884 {
1885 UNIMPLEMENTED;
1886 }
1887
1888 /* We're clean! */
1889 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
1890
1891 FcbAcquired = FALSE;
1892 RxReleaseFcb(Context, Fcb);
1893 }
1894 _SEH2_FINALLY
1895 {
1896 if (FcbAcquired)
1897 {
1898 RxReleaseFcb(Context, Fcb);
1899 }
1900
1901 if (FcbTableAcquired)
1902 {
1903 RxReleaseFcbTableLock(&NetRoot->FcbTable);
1904 }
1905 }
1906 _SEH2_END;
1907
1908 return Status;
1909 #undef BugCheckFileId
1910 }
1911
1912 NTSTATUS
1913 NTAPI
1914 RxCommonClose(
1915 PRX_CONTEXT Context)
1916 {
1917 #define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
1918 PFCB Fcb;
1919 PFOBX Fobx;
1920 NTSTATUS Status;
1921 PFILE_OBJECT FileObject;
1922 BOOLEAN DereferenceFobx, AcquiredFcb;
1923
1924 PAGED_CODE();
1925
1926 Fcb = (PFCB)Context->pFcb;
1927 Fobx = (PFOBX)Context->pFobx;
1928 FileObject = Context->CurrentIrpSp->FileObject;
1929 DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
1930
1931 Status = RxAcquireExclusiveFcb(Context, Fcb);
1932 if (!NT_SUCCESS(Status))
1933 {
1934 return Status;
1935 }
1936
1937 AcquiredFcb = TRUE;
1938 _SEH2_TRY
1939 {
1940 BOOLEAN Freed;
1941
1942 /* Check our FCB type is expected */
1943 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
1944 (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
1945 (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
1946 {
1947 RxBugCheck(NodeType(Fcb), 0, 0);
1948 }
1949
1950 RxReferenceNetFcb(Fcb);
1951
1952 DereferenceFobx = FALSE;
1953 /* If we're not closing FS */
1954 if (Fobx != NULL)
1955 {
1956 PSRV_OPEN SrvOpen;
1957 PSRV_CALL SrvCall;
1958
1959 SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
1960 SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
1961 /* Handle delayed close */
1962 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
1963 {
1964 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
1965 {
1966 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
1967 {
1968 DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
1969
1970 if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
1971 {
1972 if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
1973 {
1974 InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
1975 }
1976 else
1977 {
1978 DereferenceFobx = TRUE;
1979 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
1980 }
1981 }
1982 }
1983 }
1984 }
1985
1986 /* If we reach maximum of delayed close/or if there are no delayed close */
1987 if (!DereferenceFobx)
1988 {
1989 PNET_ROOT NetRoot;
1990
1991 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
1992 if (NetRoot->Type != NET_ROOT_PRINT)
1993 {
1994 /* Delete if asked */
1995 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
1996 {
1997 RxScavengeRelatedFobxs(Fcb);
1998 RxSynchronizeWithScavenger(Context);
1999
2000 RxReleaseFcb(Context, Fcb);
2001
2002 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2003 RxOrphanThisFcb(Fcb);
2004 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2005
2006 Status = RxAcquireExclusiveFcb(Context, Fcb);
2007 ASSERT(NT_SUCCESS(Status));
2008 }
2009 }
2010 }
2011
2012 RxMarkFobxOnClose(Fobx);
2013 }
2014
2015 if (DereferenceFobx)
2016 {
2017 ASSERT(Fobx != NULL);
2018 RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
2019 }
2020 else
2021 {
2022 RxCloseAssociatedSrvOpen(Fobx, Context);
2023 if (Fobx != NULL)
2024 {
2025 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
2026 }
2027 }
2028
2029 Freed = RxDereferenceAndFinalizeNetFcb(Fcb, Context, FALSE, FALSE);
2030 AcquiredFcb = !Freed;
2031
2032 FileObject->FsContext = (PVOID)-1;
2033
2034 if (Freed)
2035 {
2036 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
2037 }
2038 else
2039 {
2040 RxReleaseFcb(Context, Fcb);
2041 AcquiredFcb = FALSE;
2042 }
2043 }
2044 _SEH2_FINALLY
2045 {
2046 if (_SEH2_AbnormalTermination())
2047 {
2048 if (AcquiredFcb)
2049 {
2050 RxReleaseFcb(Context, Fcb);
2051 }
2052 }
2053 else
2054 {
2055 ASSERT(!AcquiredFcb);
2056 }
2057 }
2058 _SEH2_END;
2059
2060 DPRINT("Status: %x\n", Status);
2061 return Status;
2062 #undef BugCheckFileId
2063 }
2064
2065 NTSTATUS
2066 NTAPI
2067 RxCommonCreate(
2068 PRX_CONTEXT Context)
2069 {
2070 PIRP Irp;
2071 NTSTATUS Status;
2072 PFILE_OBJECT FileObject;
2073 PIO_STACK_LOCATION Stack;
2074
2075 PAGED_CODE();
2076
2077 DPRINT("RxCommonCreate(%p)\n", Context);
2078
2079 Irp = Context->CurrentIrp;
2080 Stack = Context->CurrentIrpSp;
2081 FileObject = Stack->FileObject;
2082
2083 /* Check whether that's a device opening */
2084 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
2085 {
2086 FileObject->FsContext = &RxDeviceFCB;
2087 FileObject->FsContext2 = NULL;
2088
2089 ++RxDeviceFCB.NodeReferenceCount;
2090 ++RxDeviceFCB.OpenCount;
2091
2092 Irp->IoStatus.Information = FILE_OPENED;
2093 DPRINT("Device opening FO: %p, DO: %p, Name: %wZ\n", FileObject, Context->RxDeviceObject, &Context->RxDeviceObject->DeviceName);
2094
2095 Status = STATUS_SUCCESS;
2096 }
2097 else
2098 {
2099 PFCB RelatedFcb = NULL;
2100
2101 /* Make sure caller is consistent */
2102 if (FlagOn(Stack->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE) ==
2103 (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REMOTE_INSTANCE))
2104 {
2105 DPRINT1("Create.Options: %x\n", Stack->Parameters.Create.Options);
2106 return STATUS_INVALID_PARAMETER;
2107 }
2108
2109 DPRINT("Ctxt: %p, FO: %p, Options: %lx, Flags: %lx, Attr: %lx, ShareAccess: %lx, DesiredAccess: %lx\n",
2110 Context, FileObject, Stack->Parameters.Create.Options, Stack->Flags, Stack->Parameters.Create.FileAttributes,
2111 Stack->Parameters.Create.ShareAccess, Stack->Parameters.Create.SecurityContext->DesiredAccess);
2112 DPRINT("FileName: %wZ\n", &FileObject->FileName);
2113
2114 if (FileObject->RelatedFileObject != NULL)
2115 {
2116 RelatedFcb = FileObject->RelatedFileObject->FsContext;
2117 DPRINT("Rel FO: %p, path: %wZ\n", FileObject->RelatedFileObject, RelatedFcb->FcbTableEntry.Path);
2118 }
2119
2120 /* Going to rename? */
2121 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
2122 {
2123 DPRINT("TargetDir!\n");
2124 }
2125
2126 /* Copy create parameters to the context */
2127 RxCopyCreateParameters(Context);
2128
2129 /* If the caller wants to establish a connection, go ahead */
2130 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
2131 {
2132 Status = RxCreateTreeConnect(Context);
2133 }
2134 else
2135 {
2136 /* Validate file name */
2137 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2138 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2139 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2140 {
2141 FileObject->FileName.Length -= sizeof(WCHAR);
2142 RtlMoveMemory(&FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1],
2143 FileObject->FileName.Length);
2144
2145 if (FileObject->FileName.Length > sizeof(WCHAR) &&
2146 FileObject->FileName.Buffer[1] == OBJ_NAME_PATH_SEPARATOR &&
2147 FileObject->FileName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2148 {
2149 return STATUS_OBJECT_NAME_INVALID;
2150 }
2151 }
2152
2153 /* Attempt to open the file */
2154 do
2155 {
2156 UNICODE_STRING NetRootName;
2157
2158 /* Strip last \ if required */
2159 if (FileObject->FileName.Length != 0 &&
2160 FileObject->FileName.Buffer[FileObject->FileName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
2161 {
2162 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE))
2163 {
2164 return STATUS_OBJECT_NAME_INVALID;
2165 }
2166
2167 FileObject->FileName.Length -= sizeof(WCHAR);
2168 Context->Create.Flags |= RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH;
2169 }
2170
2171 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH))
2172 {
2173 FileObject->Flags |= FO_WRITE_THROUGH;
2174 }
2175
2176 /* Get the associated net root to opening */
2177 Status = RxCanonicalizeNameAndObtainNetRoot(Context, &FileObject->FileName, &NetRootName);
2178 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
2179 {
2180 break;
2181 }
2182
2183 /* And attempt to open */
2184 Status = RxCreateFromNetRoot(Context, &NetRootName);
2185 if (Status == STATUS_SHARING_VIOLATION)
2186 {
2187 UNIMPLEMENTED;
2188 }
2189 else if (Status == STATUS_REPARSE)
2190 {
2191 Context->CurrentIrp->IoStatus.Information = 0;
2192 }
2193 else
2194 {
2195 ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
2196 }
2197 }
2198 while (Status == STATUS_MORE_PROCESSING_REQUIRED);
2199 }
2200
2201 if (Status == STATUS_RETRY)
2202 {
2203 RxpPrepareCreateContextForReuse(Context);
2204 }
2205 ASSERT(Status != STATUS_PENDING);
2206 }
2207
2208 DPRINT("Status: %lx\n", Status);
2209 return Status;
2210 }
2211
2212 /*
2213 * @implemented
2214 */
2215 NTSTATUS
2216 NTAPI
2217 RxCommonDevFCBCleanup(
2218 PRX_CONTEXT Context)
2219 {
2220 PMRX_FCB Fcb;
2221 NTSTATUS Status;
2222
2223 PAGED_CODE();
2224
2225 DPRINT("RxCommonDevFCBCleanup(%p)\n", Context);
2226
2227 Fcb = Context->pFcb;
2228 Status = STATUS_SUCCESS;
2229 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2230
2231 /* Our FOBX if set, has to be a VNetRoot */
2232 if (Context->pFobx != NULL)
2233 {
2234 RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2235 if (Context->pFobx->NodeTypeCode != RDBSS_NTC_V_NETROOT)
2236 {
2237 Status = STATUS_INVALID_DEVICE_REQUEST;
2238 }
2239 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2240 }
2241 else
2242 {
2243 --Fcb->UncleanCount;
2244 }
2245
2246 return Status;
2247 }
2248
2249 /*
2250 * @implemented
2251 */
2252 NTSTATUS
2253 NTAPI
2254 RxCommonDevFCBClose(
2255 PRX_CONTEXT Context)
2256 {
2257 PMRX_FCB Fcb;
2258 NTSTATUS Status;
2259 PMRX_V_NET_ROOT NetRoot;
2260
2261 PAGED_CODE();
2262
2263 DPRINT("RxCommonDevFCBClose(%p)\n", Context);
2264
2265 Fcb = Context->pFcb;
2266 NetRoot = (PMRX_V_NET_ROOT)Context->pFobx;
2267 Status = STATUS_SUCCESS;
2268 ASSERT(NodeType(Fcb) == RDBSS_NTC_DEVICE_FCB);
2269
2270 /* Our FOBX if set, has to be a VNetRoot */
2271 if (NetRoot != NULL)
2272 {
2273 RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
2274 if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
2275 {
2276 --NetRoot->NumberOfOpens;
2277 RxDereferenceVNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2278 }
2279 else
2280 {
2281 Status = STATUS_NOT_IMPLEMENTED;
2282 }
2283 RxReleasePrefixTableLock(Context->RxDeviceObject->pRxNetNameTable);
2284 }
2285 else
2286 {
2287 --Fcb->OpenCount;
2288 }
2289
2290 return Status;
2291 }
2292
2293 NTSTATUS
2294 NTAPI
2295 RxCommonDevFCBFsCtl(
2296 PRX_CONTEXT Context)
2297 {
2298 UNIMPLEMENTED;
2299 return STATUS_NOT_IMPLEMENTED;
2300 }
2301
2302 /*
2303 * @implemented
2304 */
2305 NTSTATUS
2306 NTAPI
2307 RxCommonDevFCBIoCtl(
2308 PRX_CONTEXT Context)
2309 {
2310 NTSTATUS Status;
2311
2312 PAGED_CODE();
2313
2314 DPRINT("RxCommonDevFCBIoCtl(%p)\n", Context);
2315
2316 if (Context->pFobx != NULL)
2317 {
2318 return STATUS_INVALID_HANDLE;
2319 }
2320
2321 /* Is that a prefix claim from MUP? */
2322 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2323 {
2324 return RxPrefixClaim(Context);
2325 }
2326
2327 /* Otherwise, pass through the mini-rdr */
2328 Status = RxXXXControlFileCallthru(Context);
2329 if (Status != STATUS_PENDING)
2330 {
2331 if (Context->PostRequest)
2332 {
2333 Context->ResumeRoutine = RxCommonDevFCBIoCtl;
2334 Status = RxFsdPostRequest(Context);
2335 }
2336 }
2337
2338 DPRINT("Status: %lx\n", Status);
2339 return Status;
2340 }
2341
2342 NTSTATUS
2343 NTAPI
2344 RxCommonDevFCBQueryVolInfo(
2345 PRX_CONTEXT Context)
2346 {
2347 UNIMPLEMENTED;
2348 return STATUS_NOT_IMPLEMENTED;
2349 }
2350
2351 /*
2352 * @implemented
2353 */
2354 NTSTATUS
2355 NTAPI
2356 RxCommonDeviceControl(
2357 PRX_CONTEXT Context)
2358 {
2359 NTSTATUS Status;
2360
2361 PAGED_CODE();
2362
2363 /* Prefix claim is only allowed for device, not files */
2364 if (Context->CurrentIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)
2365 {
2366 return STATUS_INVALID_DEVICE_REQUEST;
2367 }
2368
2369 /* Submit to mini-rdr */
2370 RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_IOCTL);
2371 Status = RxLowIoSubmit(Context, RxLowIoIoCtlShellCompletion);
2372 if (Status == STATUS_PENDING)
2373 {
2374 RxDereferenceAndDeleteRxContext_Real(Context);
2375 }
2376
2377 return Status;
2378 }
2379
2380 /*
2381 * @implemented
2382 */
2383 NTSTATUS
2384 NTAPI
2385 RxCommonDirectoryControl(
2386 PRX_CONTEXT Context)
2387 {
2388 PFCB Fcb;
2389 PFOBX Fobx;
2390 NTSTATUS Status;
2391 PIO_STACK_LOCATION Stack;
2392
2393 PAGED_CODE();
2394
2395 Fcb = (PFCB)Context->pFcb;
2396 Fobx = (PFOBX)Context->pFobx;
2397 Stack = Context->CurrentIrpSp;
2398 DPRINT("RxCommonDirectoryControl(%p) FOBX: %p, FCB: %p, Minor: %d\n", Context, Fobx, Fcb, Stack->MinorFunction);
2399
2400 /* Call the appropriate helper */
2401 if (Stack->MinorFunction == IRP_MN_QUERY_DIRECTORY)
2402 {
2403 Status = RxQueryDirectory(Context);
2404 }
2405 else if (Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
2406 {
2407 Status = RxNotifyChangeDirectory(Context);
2408 if (Status == STATUS_PENDING)
2409 {
2410 RxDereferenceAndDeleteRxContext_Real(Context);
2411 }
2412 }
2413 else
2414 {
2415 Status = STATUS_INVALID_DEVICE_REQUEST;
2416 }
2417
2418 return Status;
2419 }
2420
2421 NTSTATUS
2422 NTAPI
2423 RxCommonDispatchProblem(
2424 PRX_CONTEXT Context)
2425 {
2426 UNIMPLEMENTED;
2427 return STATUS_NOT_IMPLEMENTED;
2428 }
2429
2430 NTSTATUS
2431 NTAPI
2432 RxCommonFileSystemControl(
2433 PRX_CONTEXT Context)
2434 {
2435 UNIMPLEMENTED;
2436 return STATUS_NOT_IMPLEMENTED;
2437 }
2438
2439 NTSTATUS
2440 NTAPI
2441 RxCommonFlushBuffers(
2442 PRX_CONTEXT Context)
2443 {
2444 UNIMPLEMENTED;
2445 return STATUS_NOT_IMPLEMENTED;
2446 }
2447
2448 NTSTATUS
2449 NTAPI
2450 RxCommonLockControl(
2451 PRX_CONTEXT Context)
2452 {
2453 UNIMPLEMENTED;
2454 return STATUS_NOT_IMPLEMENTED;
2455 }
2456
2457 NTSTATUS
2458 NTAPI
2459 RxCommonQueryEa(
2460 PRX_CONTEXT Context)
2461 {
2462 UNIMPLEMENTED;
2463 return STATUS_NOT_IMPLEMENTED;
2464 }
2465
2466 /*
2467 * @implemented
2468 */
2469 NTSTATUS
2470 NTAPI
2471 RxCommonQueryInformation(
2472 PRX_CONTEXT Context)
2473 {
2474 #define SET_SIZE_AND_QUERY(AlreadyConsummed, Function) \
2475 Context->Info.Length = Stack->Parameters.QueryFile.Length - (AlreadyConsummed); \
2476 Status = Function(Context, Add2Ptr(Buffer, AlreadyConsummed))
2477
2478 PFCB Fcb;
2479 PIRP Irp;
2480 PFOBX Fobx;
2481 BOOLEAN Locked;
2482 NTSTATUS Status;
2483 PIO_STACK_LOCATION Stack;
2484 FILE_INFORMATION_CLASS FileInfoClass;
2485
2486 PAGED_CODE();
2487
2488 Fcb = (PFCB)Context->pFcb;
2489 Fobx = (PFOBX)Context->pFobx;
2490 DPRINT("RxCommonQueryInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2491
2492 Irp = Context->CurrentIrp;
2493 Stack = Context->CurrentIrpSp;
2494 DPRINT("Buffer: %p, Length: %lx, Class: %ld\n", Irp->AssociatedIrp.SystemBuffer,
2495 Stack->Parameters.QueryFile.Length, Stack->Parameters.QueryFile.FileInformationClass);
2496
2497 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2498 FileInfoClass = Stack->Parameters.QueryFile.FileInformationClass;
2499
2500 Locked = FALSE;
2501 _SEH2_TRY
2502 {
2503 PVOID Buffer;
2504
2505 /* Get a writable buffer */
2506 Buffer = RxMapSystemBuffer(Context);
2507 if (Buffer == NULL)
2508 {
2509 Status = STATUS_INSUFFICIENT_RESOURCES;
2510 _SEH2_LEAVE;
2511 }
2512 /* Zero it */
2513 RtlZeroMemory(Buffer, Context->Info.Length);
2514
2515 /* Validate file type */
2516 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN)
2517 {
2518 if (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2519 {
2520 Status = STATUS_INVALID_PARAMETER;
2521 _SEH2_LEAVE;
2522 }
2523 else if (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE)
2524 {
2525 if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
2526 {
2527 Status = STATUS_NOT_IMPLEMENTED;
2528 }
2529 else
2530 {
2531 Status = STATUS_INVALID_PARAMETER;
2532 }
2533
2534 _SEH2_LEAVE;
2535 }
2536 }
2537
2538 /* Acquire the right lock */
2539 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
2540 FileInfoClass != FileNameInformation)
2541 {
2542 if (FileInfoClass == FileCompressionInformation)
2543 {
2544 Status = RxAcquireExclusiveFcb(Context, Fcb);
2545 }
2546 else
2547 {
2548 Status = RxAcquireSharedFcb(Context, Fcb);
2549 }
2550
2551 if (Status == STATUS_LOCK_NOT_GRANTED)
2552 {
2553 Status = STATUS_PENDING;
2554 _SEH2_LEAVE;
2555 }
2556 else if (!NT_SUCCESS(Status))
2557 {
2558 _SEH2_LEAVE;
2559 }
2560
2561 Locked = TRUE;
2562 }
2563
2564 /* Dispatch to the right helper */
2565 switch (FileInfoClass)
2566 {
2567 case FileBasicInformation:
2568 Status = RxQueryBasicInfo(Context, Buffer);
2569 break;
2570
2571 case FileStandardInformation:
2572 Status = RxQueryStandardInfo(Context, Buffer);
2573 break;
2574
2575 case FileInternalInformation:
2576 Status = RxQueryInternalInfo(Context, Buffer);
2577 break;
2578
2579 case FileEaInformation:
2580 Status = RxQueryEaInfo(Context, Buffer);
2581 break;
2582
2583 case FileNameInformation:
2584 Status = RxQueryNameInfo(Context, Buffer);
2585 break;
2586
2587 case FileAllInformation:
2588 SET_SIZE_AND_QUERY(0, RxQueryBasicInfo);
2589 if (!NT_SUCCESS(Status))
2590 {
2591 break;
2592 }
2593
2594 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION), RxQueryStandardInfo);
2595 if (!NT_SUCCESS(Status))
2596 {
2597 break;
2598 }
2599
2600 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2601 sizeof(FILE_STANDARD_INFORMATION), RxQueryInternalInfo);
2602 if (!NT_SUCCESS(Status))
2603 {
2604 break;
2605 }
2606
2607 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2608 sizeof(FILE_STANDARD_INFORMATION) +
2609 sizeof(FILE_INTERNAL_INFORMATION), RxQueryEaInfo);
2610 if (!NT_SUCCESS(Status))
2611 {
2612 break;
2613 }
2614
2615 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2616 sizeof(FILE_STANDARD_INFORMATION) +
2617 sizeof(FILE_INTERNAL_INFORMATION) +
2618 sizeof(FILE_EA_INFORMATION), RxQueryPositionInfo);
2619 if (!NT_SUCCESS(Status))
2620 {
2621 break;
2622 }
2623
2624 SET_SIZE_AND_QUERY(sizeof(FILE_BASIC_INFORMATION) +
2625 sizeof(FILE_STANDARD_INFORMATION) +
2626 sizeof(FILE_INTERNAL_INFORMATION) +
2627 sizeof(FILE_EA_INFORMATION) +
2628 sizeof(FILE_POSITION_INFORMATION), RxQueryNameInfo);
2629 break;
2630
2631 case FileAlternateNameInformation:
2632 Status = RxQueryAlternateNameInfo(Context, Buffer);
2633 break;
2634
2635 case FilePipeInformation:
2636 case FilePipeLocalInformation:
2637 case FilePipeRemoteInformation:
2638 Status = RxQueryPipeInfo(Context, Buffer);
2639 break;
2640
2641 case FileCompressionInformation:
2642 Status = RxQueryCompressedInfo(Context, Buffer);
2643 break;
2644
2645 default:
2646 Context->IoStatusBlock.Status = RxpQueryInfoMiniRdr(Context, FileInfoClass, Buffer);
2647 Status = Context->IoStatusBlock.Status;
2648 break;
2649 }
2650
2651 if (Context->Info.Length < 0)
2652 {
2653 Status = STATUS_BUFFER_OVERFLOW;
2654 Context->Info.Length = Stack->Parameters.QueryFile.Length;
2655 }
2656
2657 Irp->IoStatus.Information = Stack->Parameters.QueryFile.Length - Context->Info.Length;
2658 }
2659 _SEH2_FINALLY
2660 {
2661 if (Locked)
2662 {
2663 RxReleaseFcb(Context, Fcb);
2664 }
2665 }
2666 _SEH2_END;
2667
2668 DPRINT("Status: %x\n", Status);
2669 return Status;
2670
2671 #undef SET_SIZE_AND_QUERY
2672 }
2673
2674 NTSTATUS
2675 NTAPI
2676 RxCommonQueryQuotaInformation(
2677 PRX_CONTEXT Context)
2678 {
2679 UNIMPLEMENTED;
2680 return STATUS_NOT_IMPLEMENTED;
2681 }
2682
2683 NTSTATUS
2684 NTAPI
2685 RxCommonQuerySecurity(
2686 PRX_CONTEXT Context)
2687 {
2688 UNIMPLEMENTED;
2689 return STATUS_NOT_IMPLEMENTED;
2690 }
2691
2692 /*
2693 * @implemented
2694 */
2695 NTSTATUS
2696 NTAPI
2697 RxCommonQueryVolumeInformation(
2698 PRX_CONTEXT Context)
2699 {
2700 PIRP Irp;
2701 PFCB Fcb;
2702 PFOBX Fobx;
2703 NTSTATUS Status;
2704 PIO_STACK_LOCATION Stack;
2705
2706 PAGED_CODE();
2707
2708 Fcb = (PFCB)Context->pFcb;
2709 Fobx = (PFOBX)Context->pFobx;
2710
2711 DPRINT("RxCommonQueryVolumeInformation(%p) FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
2712
2713 Irp = Context->CurrentIrp;
2714 Stack = Context->CurrentIrpSp;
2715 DPRINT("Length: %lx, Class: %lx, Buffer %p\n", Stack->Parameters.QueryVolume.Length,
2716 Stack->Parameters.QueryVolume.FsInformationClass, Irp->AssociatedIrp.SystemBuffer);
2717
2718 Context->Info.FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
2719 Context->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
2720 Context->Info.Length = Stack->Parameters.QueryVolume.Length;
2721
2722 /* Forward to mini-rdr */
2723 MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxQueryVolumeInfo, (Context));
2724
2725 /* Post request if mini-rdr asked to */
2726 if (Context->PostRequest)
2727 {
2728 Status = RxFsdPostRequest(Context);
2729 }
2730 else
2731 {
2732 Irp->IoStatus.Information = Stack->Parameters.QueryVolume.Length - Context->Info.Length;
2733 }
2734
2735 DPRINT("Status: %x\n", Status);
2736 return Status;
2737 }
2738
2739 NTSTATUS
2740 NTAPI
2741 RxCommonRead(
2742 PRX_CONTEXT RxContext)
2743 {
2744 PFCB Fcb;
2745 PIRP Irp;
2746 PFOBX Fobx;
2747 NTSTATUS Status;
2748 PNET_ROOT NetRoot;
2749 PVOID SystemBuffer;
2750 PFILE_OBJECT FileObject;
2751 LARGE_INTEGER ByteOffset;
2752 PIO_STACK_LOCATION Stack;
2753 PLOWIO_CONTEXT LowIoContext;
2754 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2755 ULONG ReadLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
2756 BOOLEAN CanWait, PagingIo, NoCache, Sync, PostRequest, IsPipe, ReadCachingEnabled, ReadCachingDisabled, InFsp, OwnerSet;
2757
2758 PAGED_CODE();
2759
2760 Fcb = (PFCB)RxContext->pFcb;
2761 Fobx = (PFOBX)RxContext->pFobx;
2762 DPRINT("RxCommonRead(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
2763
2764 /* Get some parameters */
2765 Irp = RxContext->CurrentIrp;
2766 Stack = RxContext->CurrentIrpSp;
2767 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
2768 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
2769 NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
2770 Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
2771 InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
2772 ReadLength = Stack->Parameters.Read.Length;
2773 ByteOffset.QuadPart = Stack->Parameters.Read.ByteOffset.QuadPart;
2774 DPRINT("Reading: %lx@%I64x %s %s %s %s\n", ReadLength, ByteOffset.QuadPart,
2775 (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
2776
2777 RxItsTheSameContext();
2778
2779 Irp->IoStatus.Information = 0;
2780
2781 /* Should the read be loud - so far, it's just ignored on ReactOS:
2782 * s/DPRINT/DPRINT1/g will make it loud
2783 */
2784 LowIoContext = &RxContext->LowIoContext;
2785 CheckForLoudOperations(RxContext);
2786 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
2787 {
2788 DPRINT("LoudRead %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
2789 ByteOffset, ReadLength,
2790 Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
2791 }
2792
2793 RxDeviceObject = RxContext->RxDeviceObject;
2794 /* Update stats */
2795 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
2796 {
2797 InterlockedIncrement((volatile long *)&RxDeviceObject->ReadOperations);
2798
2799 if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedReadOffset)
2800 {
2801 InterlockedIncrement((volatile long *)&RxDeviceObject->RandomReadOperations);
2802 }
2803 Fobx->Specific.DiskFile.PredictedReadOffset = ByteOffset.QuadPart + ReadLength;
2804
2805 if (PagingIo)
2806 {
2807 ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingReadBytesRequested, ReadLength);
2808 }
2809 else if (NoCache)
2810 {
2811 ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingReadBytesRequested, ReadLength);
2812 }
2813 else
2814 {
2815 ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheReadBytesRequested, ReadLength);
2816 }
2817 }
2818
2819 /* A pagefile cannot be a pipe */
2820 IsPipe = Fcb->NetRoot->Type == NET_ROOT_PIPE;
2821 if (IsPipe && PagingIo)
2822 {
2823 return STATUS_INVALID_DEVICE_REQUEST;
2824 }
2825
2826 /* Null-length read is no-op */
2827 if (ReadLength == 0)
2828 {
2829 return STATUS_SUCCESS;
2830 }
2831
2832 /* Validate FCB type */
2833 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE && NodeType(Fcb) != RDBSS_NTC_VOLUME_FCB)
2834 {
2835 return STATUS_INVALID_DEVICE_REQUEST;
2836 }
2837
2838 /* Init the lowio context for possible forward */
2839 RxInitializeLowIoContext(LowIoContext, LOWIO_OP_READ);
2840
2841 PostRequest = FALSE;
2842 ReadCachingDisabled = FALSE;
2843 OwnerSet = FALSE;
2844 ReadCachingEnabled = BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
2845 FileObject = Stack->FileObject;
2846 NetRoot = (PNET_ROOT)Fcb->pNetRoot;
2847 _SEH2_TRY
2848 {
2849 LONGLONG FileSize;
2850
2851 /* If no caching, make sure current Cc data have been flushed */
2852 if (!PagingIo && NoCache && !ReadCachingEnabled && FileObject->SectionObjectPointer != NULL)
2853 {
2854 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
2855 if (Status == STATUS_LOCK_NOT_GRANTED)
2856 {
2857 PostRequest = TRUE;
2858 _SEH2_LEAVE;
2859 }
2860 else if (Status != STATUS_SUCCESS)
2861 {
2862 _SEH2_LEAVE;
2863 }
2864
2865 ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
2866 CcFlushCache(FileObject->SectionObjectPointer, &ByteOffset, ReadLength, &Irp->IoStatus);
2867 RxReleasePagingIoResource(RxContext, Fcb);
2868
2869 if (!NT_SUCCESS(Irp->IoStatus.Status))
2870 {
2871 _SEH2_LEAVE;
2872 }
2873
2874 RxAcquirePagingIoResource(RxContext, Fcb);
2875 RxReleasePagingIoResource(RxContext, Fcb);
2876 }
2877
2878 /* Acquire the appropriate lock */
2879 if (PagingIo && !ReadCachingEnabled)
2880 {
2881 ASSERT(!IsPipe);
2882
2883 if (!ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, CanWait))
2884 {
2885 PostRequest = TRUE;
2886 _SEH2_LEAVE;
2887 }
2888
2889 if (!CanWait)
2890 {
2891 LowIoContext->Resource = Fcb->Header.PagingIoResource;
2892 }
2893 }
2894 else
2895 {
2896 if (!ReadCachingEnabled)
2897 {
2898 if (!CanWait && NoCache)
2899 {
2900 Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
2901 if (Status == STATUS_LOCK_NOT_GRANTED)
2902 {
2903 DPRINT1("RdAsyLNG %x\n", RxContext);
2904 PostRequest = TRUE;
2905 _SEH2_LEAVE;
2906 }
2907 if (Status != STATUS_SUCCESS)
2908 {
2909 DPRINT1("RdAsyOthr %x\n", RxContext);
2910 _SEH2_LEAVE;
2911 }
2912
2913 if (RxIsFcbAcquiredShared(Fcb) <= 0xF000)
2914 {
2915 LowIoContext->Resource = Fcb->Header.Resource;
2916 }
2917 else
2918 {
2919 PostRequest = TRUE;
2920 _SEH2_LEAVE;
2921 }
2922 }
2923 else
2924 {
2925 Status = RxAcquireSharedFcb(RxContext, Fcb);
2926 if (Status == STATUS_LOCK_NOT_GRANTED)
2927 {
2928 PostRequest = TRUE;
2929 _SEH2_LEAVE;
2930 }
2931 else if (Status != STATUS_SUCCESS)
2932 {
2933 _SEH2_LEAVE;
2934 }
2935 }
2936 }
2937 }
2938
2939 RxItsTheSameContext();
2940
2941 ReadCachingDisabled = (ReadCachingEnabled == FALSE);
2942 if (IsPipe)
2943 {
2944 UNIMPLEMENTED;
2945 }
2946
2947 RxGetFileSizeWithLock(Fcb, &FileSize);
2948
2949 /* Make sure FLOCK doesn't conflict */
2950 if (!PagingIo)
2951 {
2952 if (!FsRtlCheckLockForReadAccess(&Fcb->Specific.Fcb.FileLock, Irp))
2953 {
2954 Status = STATUS_FILE_LOCK_CONFLICT;
2955 _SEH2_LEAVE;
2956 }
2957 }
2958
2959 /* Validate byteoffset vs length */
2960 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
2961 {
2962 if (ByteOffset.QuadPart >= FileSize)
2963 {
2964 Status = STATUS_END_OF_FILE;
2965 _SEH2_LEAVE;
2966 }
2967
2968 if (ReadLength > FileSize - ByteOffset.QuadPart)
2969 {
2970 ReadLength = FileSize - ByteOffset.QuadPart;
2971 }
2972 }
2973
2974 /* Read with Cc! */
2975 if (!PagingIo && !NoCache && ReadCachingEnabled &&
2976 !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING))
2977 {
2978 /* File was not cached yet, do it */
2979 if (FileObject->PrivateCacheMap == NULL)
2980 {
2981 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
2982 {
2983 Status = STATUS_FILE_CLOSED;
2984 _SEH2_LEAVE;
2985 }
2986
2987 RxAdjustAllocationSizeforCC(Fcb);
2988
2989 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
2990 FALSE, &RxData.CacheManagerCallbacks, Fcb);
2991
2992 if (BooleanFlagOn(Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD))
2993 {
2994 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
2995 }
2996 else
2997 {
2998 CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE);
2999 SetFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3000 }
3001
3002 CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
3003 }
3004
3005 /* This should never happen - fix your RDR */
3006 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
3007 {
3008 ASSERT(FALSE);
3009 ASSERT(CanWait);
3010
3011 CcMdlRead(FileObject, &ByteOffset, ReadLength, &Irp->MdlAddress, &Irp->IoStatus);
3012 Status = Irp->IoStatus.Status;
3013 ASSERT(NT_SUCCESS(Status));
3014 }
3015 else
3016 {
3017 /* Map buffer */
3018 SystemBuffer = RxNewMapUserBuffer(RxContext);
3019 if (SystemBuffer == NULL)
3020 {
3021 Status = STATUS_INSUFFICIENT_RESOURCES;
3022 _SEH2_LEAVE;
3023 }
3024
3025 SetFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3026
3027 RxItsTheSameContext();
3028
3029 /* Perform the read */
3030 if (!CcCopyRead(FileObject, &ByteOffset, ReadLength, CanWait, SystemBuffer, &Irp->IoStatus))
3031 {
3032 if (!ReadCachingEnabled)
3033 {
3034 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3035 }
3036
3037 RxItsTheSameContext();
3038
3039 PostRequest = TRUE;
3040 _SEH2_LEAVE;
3041 }
3042
3043 if (!ReadCachingEnabled)
3044 {
3045 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3046 }
3047
3048 Status = Irp->IoStatus.Status;
3049 ASSERT(NT_SUCCESS(Status));
3050 }
3051 }
3052 else
3053 {
3054 /* Validate the reading */
3055 if (FileObject->PrivateCacheMap != NULL && BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) &&
3056 ByteOffset.QuadPart >= 4096)
3057 {
3058 CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE);
3059 ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
3060 }
3061
3062 /* If it's consistent, forward to mini-rdr */
3063 if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
3064 ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
3065 {
3066 LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
3067 LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
3068
3069 RxItsTheSameContext();
3070
3071 if (InFsp && ReadCachingDisabled)
3072 {
3073 ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
3074 (PVOID)((ULONG_PTR)RxContext | 3));
3075 OwnerSet = TRUE;
3076 }
3077
3078 Status = RxLowIoReadShell(RxContext);
3079
3080 RxItsTheSameContext();
3081 }
3082 else
3083 {
3084 if (ByteOffset.QuadPart > FileSize)
3085 {
3086 ReadLength = 0;
3087 Irp->IoStatus.Information = ReadLength;
3088 _SEH2_LEAVE;
3089 }
3090
3091 if (ByteOffset.QuadPart + ReadLength > FileSize)
3092 {
3093 ReadLength = FileSize - ByteOffset.QuadPart;
3094 }
3095
3096 SystemBuffer = RxNewMapUserBuffer(RxContext);
3097 RtlZeroMemory(SystemBuffer, ReadLength);
3098 Irp->IoStatus.Information = ReadLength;
3099 }
3100 }
3101 }
3102 _SEH2_FINALLY
3103 {
3104 RxItsTheSameContext();
3105
3106 /* Post if required */
3107 if (PostRequest)
3108 {
3109 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
3110 Status = RxFsdPostRequest(RxContext);
3111 }
3112 else
3113 {
3114 /* Update FO in case of sync IO */
3115 if (!IsPipe && !PagingIo)
3116 {
3117 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
3118 {
3119 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
3120 }
3121 }
3122 }
3123
3124 /* Set FastIo if read was a success */
3125 if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
3126 {
3127 if (!IsPipe && !PagingIo)
3128 {
3129 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
3130 }
3131 }
3132
3133 /* In case we're done (not expected any further processing */
3134 if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
3135 {
3136 /* Release everything that can be */
3137 if (ReadCachingDisabled)
3138 {
3139 if (PagingIo)
3140 {
3141 if (OwnerSet)
3142 {
3143 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3144 }
3145 else
3146 {
3147 RxReleasePagingIoResource(RxContext, Fcb);
3148 }
3149 }
3150 else
3151 {
3152 if (OwnerSet)
3153 {
3154 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
3155 }
3156 else
3157 {
3158 RxReleaseFcb(RxContext, Fcb);
3159 }
3160 }
3161 }
3162
3163 /* Dereference/Delete context */
3164 if (PostRequest)
3165 {
3166 RxDereferenceAndDeleteRxContext(RxContext);
3167 }
3168 else
3169 {
3170 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
3171 {
3172 RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
3173 }
3174 }
3175
3176 /* We cannot return more than asked */
3177 if (Status == STATUS_SUCCESS)
3178 {
3179 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
3180 }
3181 }
3182 else
3183 {
3184 ASSERT(!Sync);
3185
3186 RxDereferenceAndDeleteRxContext(RxContext);
3187 }
3188 }
3189 _SEH2_END;
3190
3191 return Status;
3192 }
3193
3194 NTSTATUS
3195 NTAPI
3196 RxCommonSetEa(
3197 PRX_CONTEXT Context)
3198 {
3199 UNIMPLEMENTED;
3200 return STATUS_NOT_IMPLEMENTED;
3201 }
3202
3203 NTSTATUS
3204 NTAPI
3205 RxCommonSetInformation(
3206 PRX_CONTEXT Context)
3207 {
3208 UNIMPLEMENTED;
3209 return STATUS_NOT_IMPLEMENTED;
3210 }
3211
3212 NTSTATUS
3213 NTAPI
3214 RxCommonSetQuotaInformation(
3215 PRX_CONTEXT Context)
3216 {
3217 UNIMPLEMENTED;
3218 return STATUS_NOT_IMPLEMENTED;
3219 }
3220
3221 NTSTATUS
3222 NTAPI
3223 RxCommonSetSecurity(
3224 PRX_CONTEXT Context)
3225 {
3226 UNIMPLEMENTED;
3227 return STATUS_NOT_IMPLEMENTED;
3228 }
3229
3230 NTSTATUS
3231 NTAPI
3232 RxCommonSetVolumeInformation(
3233 PRX_CONTEXT Context)
3234 {
3235 UNIMPLEMENTED;
3236 return STATUS_NOT_IMPLEMENTED;
3237 }
3238
3239 NTSTATUS
3240 NTAPI
3241 RxCommonUnimplemented(
3242 PRX_CONTEXT Context)
3243 {
3244 UNIMPLEMENTED;
3245 return STATUS_NOT_IMPLEMENTED;
3246 }
3247
3248 NTSTATUS
3249 NTAPI
3250 RxCommonWrite(
3251 PRX_CONTEXT Context)
3252 {
3253 UNIMPLEMENTED;
3254 return STATUS_NOT_IMPLEMENTED;
3255 }
3256
3257 NTSTATUS
3258 NTAPI
3259 RxCompleteMdl(
3260 IN PRX_CONTEXT RxContext)
3261 {
3262 PAGED_CODE();
3263
3264 UNIMPLEMENTED;
3265 return STATUS_NOT_IMPLEMENTED;
3266 }
3267
3268 /*
3269 * @implemented
3270 */
3271 VOID
3272 RxCopyCreateParameters(
3273 IN PRX_CONTEXT RxContext)
3274 {
3275 PIRP Irp;
3276 PVOID DfsContext;
3277 PFILE_OBJECT FileObject;
3278 PIO_STACK_LOCATION Stack;
3279 PDFS_NAME_CONTEXT DfsNameContext;
3280 PIO_SECURITY_CONTEXT SecurityContext;
3281
3282 Irp = RxContext->CurrentIrp;
3283 Stack = RxContext->CurrentIrpSp;
3284 FileObject = Stack->FileObject;
3285 SecurityContext = Stack->Parameters.Create.SecurityContext;
3286
3287 RxContext->Create.NtCreateParameters.SecurityContext = SecurityContext;
3288 if (SecurityContext->AccessState != NULL && SecurityContext->AccessState->SecurityDescriptor != NULL)
3289 {
3290 RxContext->Create.SdLength = RtlLengthSecurityDescriptor(SecurityContext->AccessState->SecurityDescriptor);
3291 DPRINT("SD Ctxt: %p, Length: %lx\n", RxContext->Create.NtCreateParameters.SecurityContext,
3292 RxContext->Create.SdLength);
3293 }
3294 if (SecurityContext->SecurityQos != NULL)
3295 {
3296 RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityContext->SecurityQos->ImpersonationLevel;
3297 }
3298 else
3299 {
3300 RxContext->Create.NtCreateParameters.ImpersonationLevel = SecurityImpersonation;
3301 }
3302 RxContext->Create.NtCreateParameters.DesiredAccess = SecurityContext->DesiredAccess;
3303
3304 RxContext->Create.NtCreateParameters.AllocationSize.QuadPart = Irp->Overlay.AllocationSize.QuadPart;
3305 RxContext->Create.NtCreateParameters.FileAttributes = Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
3306 RxContext->Create.NtCreateParameters.ShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
3307 RxContext->Create.NtCreateParameters.Disposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
3308 RxContext->Create.NtCreateParameters.CreateOptions = Stack->Parameters.Create.Options & 0xFFFFFF;
3309
3310 DfsContext = FileObject->FsContext2;
3311 DfsNameContext = FileObject->FsContext;
3312 RxContext->Create.NtCreateParameters.DfsContext = DfsContext;
3313 RxContext->Create.NtCreateParameters.DfsNameContext = DfsNameContext;
3314 ASSERT(DfsContext == NULL || DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) ||
3315 DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) ||
3316 DfsContext == UIntToPtr(DFS_CSCAGENT_NAME_CONTEXT) ||
3317 DfsContext == UIntToPtr(DFS_USER_NAME_CONTEXT));
3318 ASSERT(DfsNameContext == NULL || DfsNameContext->NameContextType == DFS_OPEN_CONTEXT ||
3319 DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT ||
3320 DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT ||
3321 DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT);
3322 FileObject->FsContext2 = NULL;
3323 FileObject->FsContext = NULL;
3324
3325 RxContext->pFcb = NULL;
3326 RxContext->Create.ReturnedCreateInformation = 0;
3327
3328 /* if we stripped last \, it has to be a directory! */
3329 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
3330 {
3331 SetFlag(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DIRECTORY_FILE);
3332 }
3333
3334 RxContext->Create.EaLength = Stack->Parameters.Create.EaLength;
3335 if (RxContext->Create.EaLength == 0)
3336 {
3337 RxContext->Create.EaBuffer = NULL;
3338 }
3339 else
3340 {
3341 RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer;
3342 DPRINT("EA Buffer: %p, Length: %lx\n", Irp->AssociatedIrp.SystemBuffer, RxContext->Create.EaLength);
3343 }
3344 }
3345
3346 NTSTATUS
3347 RxCreateFromNetRoot(
3348 PRX_CONTEXT Context,
3349 PUNICODE_STRING NetRootName)
3350 {
3351 PFCB Fcb;
3352 NTSTATUS Status;
3353 PNET_ROOT NetRoot;
3354 PFILE_OBJECT FileObject;
3355 PIO_STACK_LOCATION Stack;
3356 ACCESS_MASK DesiredAccess;
3357 USHORT DesiredShareAccess;
3358
3359 PAGED_CODE();
3360
3361 /* Validate that the context is consistent */
3362 if (Context->Create.pNetRoot == NULL)
3363 {
3364 return STATUS_BAD_NETWORK_PATH;
3365 }
3366
3367 NetRoot = (PNET_ROOT)Context->Create.pNetRoot;
3368 if (Context->RxDeviceObject != NetRoot->pSrvCall->RxDeviceObject)
3369 {
3370 return STATUS_BAD_NETWORK_PATH;
3371 }
3372
3373 if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT) &&
3374 !BooleanFlagOn(NetRoot->pSrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER))
3375 {
3376 return STATUS_DFS_UNAVAILABLE;
3377 }
3378
3379 if (Context->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
3380 BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT))
3381 {
3382 return STATUS_OBJECT_TYPE_MISMATCH;
3383 }
3384
3385 Stack = Context->CurrentIrpSp;
3386 DesiredShareAccess = Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS;
3387 if (NetRoot->Type == NET_ROOT_PRINT)
3388 {
3389 DesiredShareAccess = FILE_SHARE_VALID_FLAGS;
3390 }
3391
3392 DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_ALL_ACCESS;
3393
3394 /* We don't support renaming yet */
3395 if (BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY))
3396 {
3397 UNIMPLEMENTED;
3398 return STATUS_NOT_IMPLEMENTED;
3399 }
3400
3401 /* Try to find (or create) the FCB for the file */
3402 Status = RxFindOrCreateFcb(Context, NetRootName);
3403 Fcb = (PFCB)Context->pFcb;
3404 if (Fcb == NULL)
3405 {
3406 ASSERT(!NT_SUCCESS(Status));
3407 }
3408 if (!NT_SUCCESS(Status) || Fcb == NULL)
3409 {
3410 return Status;
3411 }
3412
3413 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
3414 {
3415 Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT;
3416 }
3417 else
3418 {
3419 Status = STATUS_MORE_PROCESSING_REQUIRED;
3420 }
3421
3422 /* If finding FCB worked (mailslot case), mark the FCB as good and quit */
3423 if (NT_SUCCESS(Status))
3424 {
3425 RxTransitionNetFcb(Fcb, Condition_Good);
3426 DPRINT("Transitioning FCB %lx Condition %lx\n", Fcb, Fcb->Condition);
3427 ++Fcb->OpenCount;
3428 RxSetupNetFileObject(Context);
3429 return STATUS_SUCCESS;
3430 }
3431
3432 /* Not mailslot! */
3433 FileObject = Stack->FileObject;
3434 /* Check SA for conflict */
3435 if (Fcb->OpenCount > 0)
3436 {
3437 Status = RxCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
3438 &Fcb->ShareAccess, FALSE, "early check per useropens", "EarlyPerUO");
3439 if (!NT_SUCCESS(Status))
3440 {
3441 RxDereferenceNetFcb(Fcb);
3442 return Status;
3443 }
3444 }
3445
3446 if (BooleanFlagOn(Context->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE) &&
3447 !BooleanFlagOn(Context->Create.NtCreateParameters.DesiredAccess, ~SYNCHRONIZE))
3448 {
3449 UNIMPLEMENTED;
3450 }
3451
3452 _SEH2_TRY
3453 {
3454 /* Find a SRV_OPEN that suits the opening */
3455 Status = RxCollapseOrCreateSrvOpen(Context);
3456 if (Status == STATUS_SUCCESS)
3457 {
3458 PFOBX Fobx;
3459 PSRV_OPEN SrvOpen;
3460
3461 SrvOpen = (PSRV_OPEN)Context->pRelevantSrvOpen;
3462 Fobx = (PFOBX)Context->pFobx;
3463 /* There are already opens, check for conflict */
3464 if (Fcb->OpenCount != 0)
3465 {
3466 if (!NT_SUCCESS(RxCheckShareAccess(DesiredAccess, DesiredShareAccess,
3467 FileObject, &Fcb->ShareAccess,
3468 FALSE, "second check per useropens",
3469 "2ndAccPerUO")))
3470 {
3471 ++SrvOpen->UncleanFobxCount;
3472 RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
3473
3474 _SEH2_LEAVE;
3475 }
3476 }
3477 else
3478 {
3479 if (NetRoot->Type != NET_ROOT_PIPE)
3480 {
3481 RxSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject,
3482 &Fcb->ShareAccess, "initial shareaccess setup", "InitShrAcc");
3483 }
3484 }
3485
3486 RxSetupNetFileObject(Context);
3487
3488 /* No conflict? Set up SA */
3489 if (Fcb->OpenCount != 0 && NetRoot->Type != NET_ROOT_PIPE)
3490 {
3491 RxUpdateShareAccess(FileObject, &Fcb->ShareAccess, "update share access", "UpdShrAcc");
3492 }
3493
3494 ++Fcb->UncleanCount;
3495 if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
3496 {
3497 ++Fcb->UncachedUncleanCount;
3498 }
3499
3500 if (SrvOpen->UncleanFobxCount == 0 && Fcb->UncleanCount == 1 &&
3501 !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE))
3502 {
3503 RxChangeBufferingState(SrvOpen, NULL, FALSE);
3504 }
3505
3506 /* No pending close, we're active */
3507 ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
3508
3509 ++Fcb->OpenCount;
3510 ++SrvOpen->UncleanFobxCount;
3511 ++SrvOpen->OpenCount;
3512 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
3513
3514 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
3515 {
3516 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING);
3517 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
3518
3519 ClearFlag(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED);
3520 ClearFlag(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED);
3521
3522 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
3523 }
3524
3525 /* Now, update SA for the SRV_OPEN */
3526 RxUpdateShareAccessPerSrvOpens(SrvOpen);
3527
3528 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
3529 {
3530 SetFlag(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE);
3531 }
3532
3533 /* Update the FOBX info */
3534 if (Fobx != NULL)
3535 {
3536 if (Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
3537 {
3538 SetFlag(FileObject->Flags, FO_NAMED_PIPE);
3539 }
3540
3541 if (Context->Create.pNetRoot->Type == NET_ROOT_PRINT ||
3542 Context->Create.pNetRoot->Type == NET_ROOT_PIPE)
3543 {
3544 Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
3545
3546 Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0;
3547 Fobx->Specific.NamedPipe.CollectDataSize = Context->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
3548
3549 Fobx->Specific.NamedPipe.PipeHandleInformation.TypeOfPipe = Context->Create.PipeType;
3550 Fobx->Specific.NamedPipe.PipeHandleInformation.ReadMode = Context->Create.PipeReadMode;
3551 Fobx->Specific.NamedPipe.PipeHandleInformation.CompletionMode = Context->Create.PipeCompletionMode;
3552
3553 InitializeListHead(&Fobx->Specific.NamedPipe.ReadSerializationQueue);
3554 InitializeListHead(&Fobx->Specific.NamedPipe.WriteSerializationQueue);
3555 }
3556 }
3557
3558 Status = STATUS_SUCCESS;
3559 }
3560 }
3561 _SEH2_FINALLY
3562 {
3563 if (Fcb->OpenCount == 0)
3564 {
3565 if (Context->Create.FcbAcquired)
3566 {
3567 Context->Create.FcbAcquired = (RxDereferenceAndFinalizeNetFcb(Fcb,
3568 Context,
3569 FALSE,
3570 FALSE) == 0);
3571 if (!Context->Create.FcbAcquired)
3572 {
3573 RxTrackerUpdateHistory(Context, NULL, TRACKER_FCB_FREE, __LINE__, __FILE__, 0);
3574 }
3575 }
3576 }
3577 else
3578 {
3579 RxDereferenceNetFcb(Fcb);
3580 }
3581 }
3582 _SEH2_END;
3583
3584 return Status;
3585 }
3586
3587 /*
3588 * @implemented
3589 */
3590 NTSTATUS
3591 RxCreateTreeConnect(
3592 IN PRX_CONTEXT RxContext)
3593 {
3594 NTSTATUS Status;
3595 PV_NET_ROOT VNetRoot;
3596 PFILE_OBJECT FileObject;
3597 PIO_STACK_LOCATION Stack;
3598 NET_ROOT_TYPE NetRootType;
3599 UNICODE_STRING CanonicalName, RemainingName;
3600
3601 PAGED_CODE();
3602
3603 Stack = RxContext->CurrentIrpSp;
3604 FileObject = Stack->FileObject;
3605
3606 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
3607 /* As long as we don't know connection type, mark it wild */
3608 NetRootType = NET_ROOT_WILD;
3609 /* Get the type by parsing the name */
3610 Status = RxFirstCanonicalize(RxContext, &FileObject->FileName, &CanonicalName, &NetRootType);
3611 if (!NT_SUCCESS(Status))
3612 {
3613 return Status;
3614 }
3615
3616 RxContext->Create.ThisIsATreeConnectOpen = TRUE;
3617 RxContext->Create.TreeConnectOpenDeferred = FALSE;
3618 RtlInitEmptyUnicodeString(&RxContext->Create.TransportName, NULL, 0);
3619 RtlInitEmptyUnicodeString(&RxContext->Create.UserName, NULL, 0);
3620 RtlInitEmptyUnicodeString(&RxContext->Create.Password, NULL, 0);
3621 RtlInitEmptyUnicodeString(&RxContext->Create.UserDomainName, NULL, 0);
3622
3623 /* We don't handle EA - they come from DFS, don't care */
3624 if (Stack->Parameters.Create.EaLength > 0)
3625 {
3626 UNIMPLEMENTED;
3627 }
3628
3629 /* Mount if required */
3630 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
3631 if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT)
3632 {
3633 RxScavengeVNetRoots(RxContext->RxDeviceObject);
3634 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &RemainingName);
3635 }
3636
3637 if (!NT_SUCCESS(Status))
3638 {
3639 return Status;
3640 }
3641
3642 /* Validate the rest of the name with mini-rdr */
3643 if (RemainingName.Length > 0)
3644 {
3645 MINIRDR_CALL(Status, RxContext,
3646 RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
3647 MRxIsValidDirectory, (RxContext, &RemainingName));
3648 }
3649
3650 if (!NT_SUCCESS(Status))
3651 {
3652 return Status;
3653 }
3654
3655 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
3656 RxReferenceVNetRoot(VNetRoot);
3657 if (InterlockedCompareExchange(&VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0)
3658 {
3659 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3660 }
3661
3662 FileObject->FsContext = &RxDeviceFCB;
3663 FileObject->FsContext2 = VNetRoot;
3664
3665 VNetRoot->ConstructionStatus = STATUS_SUCCESS;
3666 ++VNetRoot->NumberOfOpens;
3667
3668 /* Create is over - clear context */
3669 RxContext->Create.pSrvCall = NULL;
3670 RxContext->Create.pNetRoot = NULL;
3671 RxContext->Create.pVNetRoot = NULL;
3672
3673 return Status;
3674 }
3675
3676 VOID
3677 NTAPI
3678 RxDebugControlCommand(
3679 _In_ PSTR ControlString)
3680 {
3681 UNIMPLEMENTED;
3682 }
3683
3684 NTSTATUS
3685 NTAPI
3686 RxDriverEntry(
3687 IN PDRIVER_OBJECT DriverObject,
3688 IN PUNICODE_STRING RegistryPath)
3689 {
3690 NTSTATUS Status;
3691 USHORT i, State = 0;
3692
3693 DPRINT("RxDriverEntry(%p, %p)\n", DriverObject, RegistryPath);
3694
3695 _SEH2_TRY
3696 {
3697 RxCheckFcbStructuresForAlignment();
3698
3699 RtlZeroMemory(&RxData, sizeof(RxData));
3700 RxData.NodeTypeCode = RDBSS_NTC_DATA_HEADER;
3701 RxData.NodeByteSize = sizeof(RxData);
3702 RxData.DriverObject = DriverObject;
3703
3704 RtlZeroMemory(&RxDeviceFCB, sizeof(RxDeviceFCB));
3705 RxDeviceFCB.spacer.NodeTypeCode = RDBSS_NTC_DEVICE_FCB;
3706 RxDeviceFCB.spacer.NodeByteSize = sizeof(RxDeviceFCB);
3707
3708 KeInitializeSpinLock(&RxStrucSupSpinLock);
3709 RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
3710
3711 RxInitializeDebugSupport();
3712
3713 RxFileSystemDeviceObject = (PRDBSS_DEVICE_OBJECT)&RxSpaceForTheWrappersDeviceObject;
3714 RtlZeroMemory(&RxSpaceForTheWrappersDeviceObject, sizeof(RxSpaceForTheWrappersDeviceObject));
3715
3716 RxInitializeLog();
3717 State = 2;
3718
3719 RxGetRegistryParameters(RegistryPath);
3720 RxReadRegistryParameters();
3721
3722 Status = RxInitializeRegistrationStructures();
3723 if (!NT_SUCCESS(Status))
3724 {
3725 _SEH2_LEAVE;
3726 }
3727 State = 1;
3728
3729 RxInitializeDispatcher();
3730
3731 ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
3732
3733 InitializeListHead(&RxIrpsList);
3734 KeInitializeSpinLock(&RxIrpsListSpinLock);
3735
3736 InitializeListHead(&RxActiveContexts);
3737 InitializeListHead(&RxSrvCalldownList);
3738
3739 ExInitializeFastMutex(&RxContextPerFileSerializationMutex);
3740 ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex);
3741 KeInitializeMutex(&RxScavengerMutex, 1);
3742 KeInitializeMutex(&RxSerializationMutex, 1);
3743
3744 for (i = 0; i < RxMaximumWorkQueue; ++i)
3745 {
3746 RxFileSystemDeviceObject->PostedRequestCount[i] = 0;
3747 RxFileSystemDeviceObject->OverflowQueueCount[i] = 0;
3748 InitializeListHead(&RxFileSystemDeviceObject->OverflowQueue[i]);
3749 }
3750
3751 KeInitializeSpinLock(&RxFileSystemDeviceObject->OverflowQueueSpinLock);
3752
3753 RxInitializeDispatchVectors(DriverObject);
3754
3755 ExInitializeResourceLite(&RxData.Resource);
3756 RxData.OurProcess = IoGetCurrentProcess();
3757
3758 RxInitializeRxTimer();
3759 }
3760 _SEH2_FINALLY
3761 {
3762 if (!NT_SUCCESS(Status))
3763 {
3764 RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BC4, Status);
3765 RxInitUnwind(DriverObject, State);
3766 }
3767 } _SEH2_END;
3768
3769 /* There are still bits to init - be consider it's fine for now */
3770 #if 0
3771 UNIMPLEMENTED;
3772 return STATUS_NOT_IMPLEMENTED;
3773 #else
3774 return STATUS_SUCCESS;
3775 #endif
3776 }
3777
3778 /*
3779 * @implemented
3780 */
3781 VOID
3782 RxDumpCurrentAccess(
3783 _In_ PSZ where1,
3784 _In_ PSZ where2,
3785 _In_ PSZ wherelogtag,
3786 _In_ PSHARE_ACCESS ShareAccess)
3787 {
3788 PAGED_CODE();
3789 }
3790
3791 /*
3792 * @implemented
3793 */
3794 VOID
3795 RxDumpWantedAccess(
3796 _In_ PSZ where1,
3797 _In_ PSZ where2,
3798 _In_ PSZ wherelogtag,
3799 _In_ ACCESS_MASK DesiredAccess,
3800 _In_ ULONG DesiredShareAccess)
3801 {
3802 PAGED_CODE();
3803 }
3804
3805 BOOLEAN
3806 NTAPI
3807 RxFastIoCheckIfPossible(
3808 PFILE_OBJECT FileObject,
3809 PLARGE_INTEGER FileOffset,
3810 ULONG Length, BOOLEAN Wait,
3811 ULONG LockKey, BOOLEAN CheckForReadOperation,
3812 PIO_STATUS_BLOCK IoStatus,
3813 PDEVICE_OBJECT DeviceObject)
3814 {
3815 PFCB Fcb;
3816 PSRV_OPEN SrvOpen;
3817
3818 PAGED_CODE();
3819
3820 /* Get the FCB to validate it */
3821 Fcb = FileObject->FsContext;
3822 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
3823 {
3824 DPRINT1("Not a file, FastIO not possible!\n");
3825 return FALSE;
3826 }
3827
3828 if (FileObject->DeletePending)
3829 {
3830 DPRINT1("File delete pending\n");
3831 return FALSE;
3832 }
3833
3834 /* If there's a pending write operation, deny fast operation */
3835 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
3836 {
3837 DPRINT1("Write operations to be completed\n");
3838 return FALSE;
3839 }
3840
3841 /* Deny read on orphaned node */
3842 SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
3843 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
3844 {
3845 DPRINT1("SRV_OPEN orphaned\n");
3846 return FALSE;
3847 }
3848
3849 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3850 {
3851 DPRINT1("FCB orphaned\n");
3852 return FALSE;
3853 }
3854
3855 /* If there's a buffering state change pending, deny fast operation (it might change
3856 * cache status)
3857 */
3858 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
3859 {
3860 DPRINT1("Buffering change pending\n");
3861 return FALSE;
3862 }
3863
3864 /* File got renamed/deleted, deny operation */
3865 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
3866 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
3867 {
3868 DPRINT1("File renamed/deleted\n");
3869 return FALSE;
3870 }
3871
3872 /* Process pending change buffering state operations */
3873 FsRtlEnterFileSystem();
3874 RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
3875 FsRtlExitFileSystem();
3876
3877 /* If operation to come is a read operation */
3878 if (CheckForReadOperation)
3879 {
3880 LARGE_INTEGER LargeLength;
3881
3882 /* Check that read cache is enabled */
3883 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
3884 {
3885 DPRINT1("Read caching disabled\n");
3886 return FALSE;
3887 }
3888
3889 /* Check whether there's a lock conflict */
3890 LargeLength.QuadPart = Length;
3891 if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
3892 FileOffset,
3893 &LargeLength,
3894 LockKey,
3895 FileObject,
3896 PsGetCurrentProcess()))
3897 {
3898 DPRINT1("FsRtlFastCheckLockForRead failed\n");
3899 return FALSE;
3900 }
3901
3902 return TRUE;
3903 }
3904
3905 UNIMPLEMENTED;
3906 return FALSE;
3907 }
3908
3909 BOOLEAN
3910 NTAPI
3911 RxFastIoDeviceControl(
3912 PFILE_OBJECT FileObject,
3913 BOOLEAN Wait,
3914 PVOID InputBuffer OPTIONAL,
3915 ULONG InputBufferLength,
3916 PVOID OutputBuffer OPTIONAL,
3917 ULONG OutputBufferLength,
3918 ULONG IoControlCode,
3919 PIO_STATUS_BLOCK IoStatus,
3920 PDEVICE_OBJECT DeviceObject)
3921 {
3922 /* Only supported IOCTL */
3923 if (IoControlCode == IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
3924 {
3925 UNIMPLEMENTED;
3926 return FALSE;
3927 }
3928 else
3929 {
3930 return FALSE;
3931 }
3932 }
3933
3934 /*
3935 * @implemented
3936 */
3937 BOOLEAN
3938 NTAPI
3939 RxFastIoRead(
3940 PFILE_OBJECT FileObject,
3941 PLARGE_INTEGER FileOffset,
3942 ULONG Length,
3943 BOOLEAN Wait,
3944 ULONG LockKey,
3945 PVOID Buffer,
3946 PIO_STATUS_BLOCK IoStatus,
3947 PDEVICE_OBJECT DeviceObject)
3948 {
3949 BOOLEAN Ret;
3950 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
3951
3952 PAGED_CODE();
3953
3954 DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
3955 FileObject->FsContext2);
3956 DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
3957
3958 /* Prepare a TLI context */
3959 ASSERT(RxIsThisTheTopLevelIrp(NULL));
3960 RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
3961 (PRDBSS_DEVICE_OBJECT)DeviceObject);
3962
3963 Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
3964 IoStatus, DeviceObject, &TopLevelContext);
3965 if (Ret)
3966 {
3967 DPRINT("Read OK\n");
3968 }
3969 else
3970 {
3971 DPRINT1("Read failed!\n");
3972 }
3973
3974 return Ret;
3975 }
3976
3977 BOOLEAN
3978 NTAPI
3979 RxFastIoWrite(
3980 PFILE_OBJECT FileObject,
3981 PLARGE_INTEGER FileOffset,
3982 ULONG Length,
3983 BOOLEAN Wait,
3984 ULONG LockKey,
3985 PVOID Buffer,
3986 PIO_STATUS_BLOCK IoStatus,
3987 PDEVICE_OBJECT DeviceObject)
3988 {
3989 UNIMPLEMENTED;
3990 return FALSE;
3991 }
3992
3993 NTSTATUS
3994 RxFindOrCreateFcb(
3995 PRX_CONTEXT RxContext,
3996 PUNICODE_STRING NetRootName)
3997 {
3998 PFCB Fcb;
3999 ULONG Version;
4000 NTSTATUS Status;
4001 PNET_ROOT NetRoot;
4002 PV_NET_ROOT VNetRoot;
4003 BOOLEAN TableAcquired, AcquiredExclusive;
4004
4005 PAGED_CODE();
4006
4007 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
4008 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
4009 ASSERT(NetRoot == VNetRoot->NetRoot);
4010
4011 Status = STATUS_SUCCESS;
4012 AcquiredExclusive = FALSE;
4013
4014 RxAcquireFcbTableLockShared(&NetRoot->FcbTable, TRUE);
4015 TableAcquired = TRUE;
4016 Version = NetRoot->FcbTable.Version;
4017
4018 /* Look for a cached FCB */
4019 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
4020 if (Fcb == NULL)
4021 {
4022 DPRINT("RxFcbTableLookupFcb returned NULL fcb for %wZ\n", NetRootName);
4023 }
4024 else
4025 {
4026 DPRINT("FCB found for %wZ\n", &Fcb->FcbTableEntry.Path);
4027 /* If FCB was to be orphaned, consider it as not suitable */
4028 if (Fcb->fShouldBeOrphaned)
4029 {
4030 RxDereferenceNetFcb(Fcb);
4031 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4032
4033 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
4034 TableAcquired = TRUE;
4035 AcquiredExclusive = TRUE;
4036
4037 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
4038 if (Fcb != NULL && Fcb->fShouldBeOrphaned)
4039 {
4040 RxOrphanThisFcb(Fcb);
4041 RxDereferenceNetFcb(Fcb);
4042 Fcb = NULL;
4043 }
4044 }
4045 }
4046
4047 /* If FCB was not found or is not covering full path, prepare for more work */
4048 if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
4049 {
4050 if (!AcquiredExclusive)
4051 {
4052 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4053 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
4054 TableAcquired = TRUE;
4055 }
4056
4057 /* If FCB table was updated in between, re-attempt a lookup */
4058 if (NetRoot->FcbTable.Version != Version)
4059 {
4060 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
4061 if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
4062 {
4063 Fcb = NULL;
4064 }
4065 }
4066 }
4067
4068 /* Allocate the FCB */
4069 _SEH2_TRY
4070 {
4071 if (Fcb == NULL)
4072 {
4073 Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName);
4074 if (Fcb == NULL)
4075 {
4076 Status = STATUS_INSUFFICIENT_RESOURCES;
4077 }
4078 else
4079 {
4080 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4081 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
4082 }
4083 }
4084 }
4085 _SEH2_FINALLY
4086 {
4087 if (_SEH2_AbnormalTermination())
4088 {
4089 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4090 TableAcquired = FALSE;
4091
4092 if (Fcb != NULL)
4093 {
4094 RxTransitionNetFcb(Fcb, Condition_Bad);
4095
4096 ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
4097 if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0)
4098 {
4099 ExReleaseResourceLite(Fcb->Header.Resource);
4100 }
4101 }
4102 }
4103 }
4104 _SEH2_END;
4105
4106 if (TableAcquired)
4107 {
4108 RxReleaseFcbTableLock(&NetRoot->FcbTable);
4109 }
4110
4111 if (!NT_SUCCESS(Status))
4112 {
4113 return Status;
4114 }
4115
4116 RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
4117 DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
4118
4119 if (!RxContext->Create.FcbAcquired)
4120 {
4121 RxWaitForStableNetFcb(Fcb, RxContext);
4122 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
4123 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
4124 }
4125
4126 return Status;
4127 }
4128
4129 NTSTATUS
4130 RxFirstCanonicalize(
4131 PRX_CONTEXT RxContext,
4132 PUNICODE_STRING FileName,
4133 PUNICODE_STRING CanonicalName,
4134 PNET_ROOT_TYPE NetRootType)
4135 {
4136 NTSTATUS Status;
4137 NET_ROOT_TYPE Type;
4138 BOOLEAN UncName, PrependString, IsSpecial;
4139 USHORT CanonicalLength;
4140 UNICODE_STRING SessionIdString;
4141 WCHAR SessionIdBuffer[16];
4142
4143 PAGED_CODE();
4144
4145 Type = NET_ROOT_WILD;
4146 PrependString = FALSE;
4147 IsSpecial = FALSE;
4148 UncName = FALSE;
4149 Status = STATUS_SUCCESS;
4150
4151 /* Name has to contain at least \\ */
4152 if (FileName->Length < 2 * sizeof(WCHAR))
4153 {
4154 return STATUS_OBJECT_NAME_INVALID;
4155 }
4156
4157 /* First easy check, is that a path with a name? */
4158 CanonicalLength = FileName->Length;
4159 if (FileName->Length > 5 * sizeof(WCHAR))
4160 {
4161 if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';')
4162 {
4163 if (FileName->Buffer[3] == ':')
4164 {
4165 Type = NET_ROOT_DISK;
4166 }
4167 else
4168 {
4169 Type = NET_ROOT_PRINT;
4170 }
4171 }
4172 }
4173
4174 /* Nope, attempt deeper parsing */
4175 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';')
4176 {
4177 ULONG SessionId;
4178 PWSTR FirstSlash, EndOfString;
4179
4180 SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME);
4181 UncName = TRUE;
4182
4183 /* The lack of drive letter will be replaced by session ID */
4184 SessionId = RxGetSessionId(RxContext->CurrentIrpSp);
4185 RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer));
4186 RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
4187
4188 EndOfString = Add2Ptr(FileName->Buffer, FileName->Length);
4189 for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash)
4190 {
4191 if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR)
4192 {
4193 break;
4194 }
4195 }
4196
4197 if (EndOfString - FirstSlash <= sizeof(WCHAR))
4198 {
4199 Status = STATUS_OBJECT_NAME_INVALID;
4200 }
4201 else
4202 {
4203 UNIMPLEMENTED;
4204 DPRINT1("WARNING: Assuming not special + disk!\n");
4205 Type = NET_ROOT_DISK;
4206 Status = STATUS_SUCCESS;
4207 //Status = STATUS_NOT_IMPLEMENTED;
4208 /* Should be check against IPC, mailslot, and so on */
4209 }
4210 }
4211
4212 /* Update net root type with our deduced one */
4213 *NetRootType = Type;
4214 DPRINT("Returning type: %x\n", Type);
4215
4216 if (!NT_SUCCESS(Status))
4217 {
4218 return Status;
4219 }
4220
4221 /* Do we have to prepend session ID? */
4222 if (UncName)
4223 {
4224 if (!IsSpecial)
4225 {
4226 PrependString = TRUE;
4227 CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR);
4228 }
4229 }
4230
4231 /* If not UNC path, we should preprend stuff */
4232 if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\')
4233 {
4234 return STATUS_OBJECT_PATH_INVALID;
4235 }
4236
4237 /* Allocate the buffer */
4238 Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength);
4239 if (!NT_SUCCESS(Status))
4240 {
4241 return Status;
4242 }
4243
4244 /* We don't support that case, we always return disk */
4245 if (IsSpecial)
4246 {
4247 ASSERT(CanonicalName->Length == CanonicalLength);
4248 UNIMPLEMENTED;
4249 Status = STATUS_NOT_IMPLEMENTED;
4250 }
4251 else
4252 {
4253 /* If we have to prepend, go ahead */
4254 if (PrependString)
4255 {
4256 CanonicalName->Buffer[0] = '\\';
4257 CanonicalName->Buffer[1] = ';';
4258 CanonicalName->Buffer[2] = ':';
4259 CanonicalName->Length = 3 * sizeof(WCHAR);
4260 RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString);
4261 RtlAppendUnicodeStringToString(CanonicalName, FileName);
4262
4263 DPRINT1("CanonicalName: %wZ\n", CanonicalName);
4264 }
4265 /* Otherwise, that's a simple copy */
4266 else
4267 {
4268 RtlCopyUnicodeString(CanonicalName, FileName);
4269 }
4270 }
4271
4272 return Status;
4273 }
4274
4275 /*
4276 * @implemented
4277 */
4278 VOID
4279 RxFreeCanonicalNameBuffer(
4280 PRX_CONTEXT Context)
4281 {
4282 /* These two buffers are always the same */
4283 ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
4284
4285 if (Context->Create.CanonicalNameBuffer != NULL)
4286 {
4287 RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
4288 Context->Create.CanonicalNameBuffer = NULL;
4289 Context->AlsoCanonicalNameBuffer = NULL;
4290 }
4291
4292 ASSERT(Context->AlsoCanonicalNameBuffer == NULL);
4293 }
4294
4295 NTSTATUS
4296 RxFsdCommonDispatch(
4297 PRX_FSD_DISPATCH_VECTOR DispatchVector,
4298 UCHAR MajorFunction,
4299 PIO_STACK_LOCATION Stack,
4300 PFILE_OBJECT FileObject,
4301 PIRP Irp,
4302 PRDBSS_DEVICE_OBJECT RxDeviceObject)
4303 {
4304 KIRQL OldIrql;
4305 NTSTATUS Status;
4306 PRX_CONTEXT Context;
4307 UCHAR MinorFunction;
4308 PFILE_OBJECT StackFileObject;
4309 PRX_FSD_DISPATCH DispatchFunc;
4310 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
4311 BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
4312
4313 Status = STATUS_SUCCESS;
4314
4315 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
4316
4317 FsRtlEnterFileSystem();
4318
4319 TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
4320
4321 _SEH2_TRY
4322 {
4323 CanWait = TRUE;
4324 Closing = FALSE;
4325 PostRequest = FALSE;
4326 SetCancelRoutine = TRUE;
4327 MinorFunction = Stack->MinorFunction;
4328 /* Can we wait? */
4329 switch (MajorFunction)
4330 {
4331 case IRP_MJ_FILE_SYSTEM_CONTROL:
4332 if (FileObject != NULL)
4333 {
4334 CanWait = IoIsOperationSynchronous(Irp);
4335 }
4336 else
4337 {
4338 CanWait = TRUE;
4339 }
4340 break;
4341
4342 case IRP_MJ_READ:
4343 case IRP_MJ_WRITE:
4344 case IRP_MJ_QUERY_INFORMATION:
4345 case IRP_MJ_SET_INFORMATION:
4346 case IRP_MJ_QUERY_EA:
4347 case IRP_MJ_SET_EA:
4348 case IRP_MJ_FLUSH_BUFFERS:
4349 case IRP_MJ_QUERY_VOLUME_INFORMATION:
4350 case IRP_MJ_SET_VOLUME_INFORMATION:
4351 case IRP_MJ_DIRECTORY_CONTROL:
4352 case IRP_MJ_DEVICE_CONTROL:
4353 case IRP_MJ_LOCK_CONTROL:
4354 case IRP_MJ_QUERY_SECURITY:
4355 case IRP_MJ_SET_SECURITY:
4356 CanWait = IoIsOperationSynchronous(Irp);
4357 break;
4358
4359 case IRP_MJ_CLOSE:
4360 case IRP_MJ_CLEANUP:
4361 Closing = TRUE;
4362 SetCancelRoutine = FALSE;
4363 break;
4364
4365 default:
4366 break;
4367 }
4368
4369 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
4370 /* Should we stop it right now, or mini-rdr deserves to know? */
4371 PassToDriver = TRUE;
4372 if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE)
4373 {
4374 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing)
4375 {
4376 PassToDriver = FALSE;
4377 Status = STATUS_REDIRECTOR_NOT_STARTED;
4378 DPRINT1("Not started!\n");
4379 }
4380 }
4381 else
4382 {
4383 if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL))
4384 {
4385 PassToDriver = FALSE;
4386 Status = STATUS_REDIRECTOR_NOT_STARTED;
4387 DPRINT1("Not started!\n");
4388 }
4389 }
4390 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
4391
4392 StackFileObject = Stack->FileObject;
4393 /* Make sure we don't deal with orphaned stuff */
4394 if (StackFileObject != NULL && StackFileObject->FsContext != NULL)
4395 {
4396 if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) &&
4397 StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
4398 StackFileObject->FsContext != &RxDeviceFCB)
4399 {
4400 PFCB Fcb;
4401 PFOBX Fobx;
4402
4403 Fcb = StackFileObject->FsContext;
4404 Fobx = StackFileObject->FsContext2;
4405
4406 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) ||
4407 BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
4408 {
4409 if (Closing)
4410 {
4411 PassToDriver = TRUE;
4412 }
4413 else
4414 {
4415 PassToDriver = FALSE;
4416 Status = STATUS_UNEXPECTED_NETWORK_ERROR;
4417 DPRINT1("Operation on orphaned FCB: %p\n", Fcb);
4418 }
4419 }
4420 }
4421 }
4422
4423 /* Did we receive a close request whereas we're stopping? */
4424 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing)
4425 {
4426 PFCB Fcb;
4427
4428 Fcb = StackFileObject->FsContext;
4429
4430 DPRINT1("Close received after stop\n");
4431 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
4432 Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
4433
4434 if (Fcb != NULL && Fcb != &RxDeviceFCB &&
4435 NodeTypeIsFcb(Fcb))
4436 {
4437 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
4438 Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path);
4439 }
4440 }
4441
4442 /* Should we stop the whole thing now? */
4443 if (!PassToDriver)
4444 {
4445 if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE)
4446 {
4447 IoMarkIrpPending(Irp);
4448 Irp->IoStatus.Status = Status;
4449 Irp->IoStatus.Information = 0;
4450 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4451 Status = STATUS_PENDING;
4452 }
4453 else
4454 {
4455 Irp->IoStatus.Status = Status;
4456 Irp->IoStatus.Information = 0;
4457 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4458 }
4459
4460 _SEH2_LEAVE;
4461 }
4462
4463 /* No? Allocate a context to deal with the mini-rdr */
4464 Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0));
4465 if (Context == NULL)
4466 {
4467 Status = STATUS_INSUFFICIENT_RESOURCES;
4468 RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES);
4469 _SEH2_LEAVE;
4470 }
4471
4472 /* Set cancel routine if required */
4473 if (SetCancelRoutine)
4474 {
4475 IoAcquireCancelSpinLock(&OldIrql);
4476 IoSetCancelRoutine(Irp, RxCancelRoutine);
4477 }
4478 else
4479 {
4480 IoAcquireCancelSpinLock(&OldIrql);
4481 IoSetCancelRoutine(Irp, NULL);
4482 }
4483 IoReleaseCancelSpinLock(OldIrql);
4484
4485 ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4486
4487 Irp->IoStatus.Status = STATUS_SUCCESS;
4488 Irp->IoStatus.Information = 0;
4489 /* Get the dispatch routine */
4490 DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
4491
4492 if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE)
4493 {
4494 /* Handle the complete MDL case */
4495 if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE))
4496 {
4497 DispatchFunc = RxCompleteMdl;
4498 }
4499 else
4500 {
4501 /* Do we have to post request? */
4502 if (BooleanFlagOn(MinorFunction, IRP_MN_DPC))
4503 {
4504 PostRequest = TRUE;
4505 }
4506 else
4507 {
4508 /* Our read function needs stack, make sure we won't overflow,
4509 * otherwise, post the request
4510 */
4511 if (MajorFunction == IRP_MJ_READ)
4512 {
4513 if (IoGetRemainingStackSize() < 0xE00)
4514 {
4515 Context->PendingReturned = TRUE;
4516 Status = RxPostStackOverflowRead(Context);
4517 if (Status != STATUS_PENDING)
4518 {
4519 Context->PendingReturned = FALSE;
4520 RxCompleteAsynchronousRequest(Context, Status);
4521 }
4522
4523 _SEH2_LEAVE;
4524 }
4525 }
4526 }
4527 }
4528 }
4529
4530 Context->ResumeRoutine = DispatchFunc;
4531 /* There's a dispatch routine? Time to dispatch! */
4532 if (DispatchFunc != NULL)
4533 {
4534 Context->PendingReturned = TRUE;
4535 if (PostRequest)
4536 {
4537 Status = RxFsdPostRequest(Context);
4538 }
4539 else
4540 {
4541 /* Retry as long as we have */
4542 do
4543 {
4544 Status = DispatchFunc(Context);
4545 }
4546 while (Status == STATUS_RETRY);
4547
4548 if (Status == STATUS_PENDING)
4549 {
4550 _SEH2_LEAVE;
4551 }
4552
4553 /* Sanity check: did someone mess with our context? */
4554 if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack ||
4555 Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction)
4556 {
4557 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context);
4558 DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp);
4559 DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack);
4560 DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction);
4561 DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction);
4562 }
4563 Context->PendingReturned = FALSE;
4564 Status = RxCompleteAsynchronousRequest(Context, Status);
4565 }
4566 }
4567 else
4568 {
4569 Status = STATUS_NOT_IMPLEMENTED;
4570 }
4571 }
4572 _SEH2_FINALLY
4573 {
4574 if (TopLevel)
4575 {
4576 RxUnwindTopLevelIrp(&TopLevelContext);
4577 }
4578
4579 FsRtlExitFileSystem();
4580 }
4581 _SEH2_END;
4582
4583 DPRINT("RxFsdDispatch, Status: %lx\n", Status);
4584 return Status;
4585 }
4586
4587 /*
4588 * @implemented
4589 */
4590 NTSTATUS
4591 NTAPI
4592 RxFsdDispatch(
4593 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4594 IN PIRP Irp)
4595 {
4596 PFCB Fcb;
4597 PIO_STACK_LOCATION Stack;
4598 PRX_FSD_DISPATCH_VECTOR DispatchVector;
4599
4600 PAGED_CODE();
4601
4602 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
4603
4604 Stack = IoGetCurrentIrpStackLocation(Irp);
4605
4606 /* Dispatch easy case */
4607 if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
4608 {
4609 return RxSystemControl(RxDeviceObject, Irp);
4610 }
4611
4612 /* Bail out broken cases */
4613 if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ||
4614 Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE)
4615 {
4616 IoMarkIrpPending(Irp);
4617 Irp->IoStatus.Information = 0;
4618 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
4619 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4620 return STATUS_PENDING;
4621 }
4622
4623 /* Immediately handle create */
4624 if (Stack->MajorFunction == IRP_MJ_CREATE)
4625 {
4626 return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
4627 }
4628
4629 /* If not a creation, we must have at least a FO with a FCB */
4630 if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL)
4631 {
4632 IoMarkIrpPending(Irp);
4633 Irp->IoStatus.Information = 0;
4634 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
4635 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4636 return STATUS_PENDING;
4637 }
4638
4639 /* Set the dispatch vector if required */
4640 Fcb = Stack->FileObject->FsContext;
4641 if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL)
4642 {
4643 DispatchVector = &RxFsdDispatchVector[0];
4644 }
4645 else
4646 {
4647 DispatchVector = Fcb->PrivateDispatchVector;
4648 }
4649
4650 /* Device cannot accept such requests */
4651 if (RxDeviceObject == RxFileSystemDeviceObject)
4652 {
4653 IoMarkIrpPending(Irp);
4654 Irp->IoStatus.Information = 0;
4655 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
4656 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4657 return STATUS_PENDING;
4658 }
4659
4660 /* Dispatch for real! */
4661 return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
4662 }
4663
4664 /*
4665 * @implemented
4666 */
4667 NTSTATUS
4668 RxFsdPostRequest(
4669 IN PRX_CONTEXT RxContext)
4670 {
4671 /* Initialize posting if required */
4672 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
4673 {
4674 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
4675 }
4676
4677 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
4678 RxContext->MinorFunction, RxContext,
4679 RxContext->CurrentIrp, RxContext->LastExecutionThread,
4680 RxContext->SerialNumber);
4681
4682 RxAddToWorkque(RxContext, RxContext->CurrentIrp);
4683 return STATUS_PENDING;
4684 }
4685
4686 /*
4687 * @implemented
4688 */
4689 VOID
4690 NTAPI
4691 RxFspDispatch(
4692 IN PVOID Context)
4693 {
4694 KIRQL EntryIrql;
4695 WORK_QUEUE_TYPE Queue;
4696 PRDBSS_DEVICE_OBJECT VolumeDO;
4697 PRX_CONTEXT RxContext, EntryContext;
4698
4699 PAGED_CODE();
4700
4701 RxContext = Context;
4702 EntryContext = Context;
4703 /* Save IRQL at entry for later checking */
4704 EntryIrql = KeGetCurrentIrql();
4705
4706 /* No FO, deal with device */
4707 if (RxContext->CurrentIrpSp->FileObject != NULL)
4708 {
4709 VolumeDO = RxFileSystemDeviceObject;
4710 }
4711 else
4712 {
4713 VolumeDO = NULL;
4714 }
4715
4716 /* Which queue to used for delayed? */
4717 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE))
4718 {
4719 Queue = DelayedWorkQueue;
4720 }
4721 else
4722 {
4723 ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
4724 Queue = CriticalWorkQueue;
4725 }
4726
4727 do
4728 {
4729 PIRP Irp;
4730 NTSTATUS Status;
4731 BOOLEAN RecursiveCall;
4732 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
4733
4734 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4735 ASSERT(!RxContext->PostRequest);
4736
4737 RxContext->LastExecutionThread = PsGetCurrentThread();
4738 SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
4739
4740 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx", RxContext->MinorFunction,
4741 RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
4742 RxContext->SerialNumber);
4743
4744 Irp = RxContext->CurrentIrp;
4745
4746 FsRtlEnterFileSystem();
4747
4748 RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
4749 RxTryToBecomeTheTopLevelIrp(&TopLevelContext,
4750 (RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp),
4751 RxContext->RxDeviceObject, TRUE);
4752
4753 ASSERT(RxContext->ResumeRoutine != NULL);
4754
4755 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL)
4756 {
4757 ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ));
4758 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4759 }
4760
4761 /* Call the resume routine */
4762 do
4763 {
4764 BOOLEAN NoComplete;
4765
4766 NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
4767
4768 Status = RxContext->ResumeRoutine(RxContext);
4769 if (!NoComplete && Status != STATUS_PENDING)
4770 {
4771 if (Status != STATUS_RETRY)
4772 {
4773 Status = RxCompleteRequest(RxContext, Status);
4774 }
4775 }
4776 }
4777 while (Status == STATUS_RETRY);
4778
4779 RxUnwindTopLevelIrp(&TopLevelContext);
4780 FsRtlExitFileSystem();
4781
4782 if (VolumeDO != NULL)
4783 {
4784 RxContext = RxRemoveOverflowEntry(VolumeDO, Queue);
4785 }
4786 else
4787 {
4788 RxContext = NULL;
4789 }
4790 } while (RxContext != NULL);
4791
4792 /* Did we mess with IRQL? */
4793 if (KeGetCurrentIrql() >= APC_LEVEL)
4794 {
4795 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql);
4796 }
4797 }
4798
4799 /*
4800 * @implemented
4801 */
4802 ULONG
4803 RxGetNetworkProviderPriority(
4804 PUNICODE_STRING DeviceName)
4805 {
4806 PAGED_CODE();
4807 return 1;
4808 }
4809
4810 /*
4811 * @implemented
4812 */
4813 VOID
4814 NTAPI
4815 RxGetRegistryParameters(
4816 IN PUNICODE_STRING RegistryPath)
4817 {
4818 USHORT i;
4819 NTSTATUS Status;
4820 UCHAR Buffer[0x400];
4821 HANDLE DriverHandle, KeyHandle;
4822 UNICODE_STRING KeyName, OutString;
4823 OBJECT_ATTRIBUTES ObjectAttributes;
4824
4825 PAGED_CODE();
4826
4827 InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
4828 Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
4829 if (!NT_SUCCESS(Status))
4830 {
4831 return;
4832 }
4833
4834 RtlInitUnicodeString(&KeyName, L"Parameters");
4835 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE);
4836 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
4837 if (NT_SUCCESS(Status))
4838 {
4839 /* The only parameter we deal with is InitialDebugString */
4840 RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0);
4841 if (OutString.Length != 0 && OutString.Length < 0x140)
4842 {
4843 PWSTR Read;
4844 PSTR Write;
4845
4846 Read = OutString.Buffer;
4847 Write = (PSTR)OutString.Buffer;
4848 for (i = 0; i < OutString.Length; ++i)
4849 {
4850 *Read = *Write;
4851 ++Write;
4852 *Write = ANSI_NULL;
4853 ++Read;
4854 }
4855
4856 /* Which is a string we'll just write out */
4857 DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer);
4858 RxDebugControlCommand((PSTR)OutString.Buffer);
4859 }
4860
4861 ZwClose(KeyHandle);
4862 }
4863
4864 ZwClose(DriverHandle);
4865 }
4866
4867 /*
4868 * @implemented
4869 */
4870 ULONG
4871 RxGetSessionId(
4872 IN PIO_STACK_LOCATION IrpSp)
4873 {
4874 ULONG SessionId;
4875 PACCESS_TOKEN Token;
4876 PIO_SECURITY_CONTEXT SecurityContext;
4877
4878 PAGED_CODE();
4879
4880 /* If that's not a prefix claim, not an open request, session id will be 0 */
4881 if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH)
4882 {
4883 if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL)
4884 {
4885 return 0;
4886 }
4887
4888 SecurityContext = IrpSp->Parameters.Create.SecurityContext;
4889 }
4890 else
4891 {
4892 SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext;
4893 }
4894
4895 /* Query the session id */
4896 Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext);
4897 SeQuerySessionIdToken(Token, &SessionId);
4898
4899 return SessionId;
4900 }
4901
4902 /*
4903 * @implemented
4904 */
4905 NTSTATUS
4906 NTAPI
4907 RxGetStringRegistryParameter(
4908 IN HANDLE KeyHandle,
4909 IN PCWSTR KeyName,
4910 OUT PUNICODE_STRING OutString,
4911 IN PUCHAR Buffer,
4912 IN ULONG BufferLength,
4913 IN BOOLEAN LogFailure)
4914 {
4915 NTSTATUS Status;
4916 ULONG ResultLength;
4917 UNICODE_STRING KeyString;
4918
4919 PAGED_CODE();
4920
4921 RtlInitUnicodeString(&KeyString, KeyName);
4922 Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength);
4923 OutString->Length = 0;
4924 OutString->Buffer = 0;
4925 if (!NT_SUCCESS(Status))
4926 {
4927 if (LogFailure)
4928 {
4929 RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status);
4930 }
4931
4932 return Status;
4933 }
4934
4935 OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
4936 OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL);
4937 OutString->MaximumLength = OutString->Length;
4938
4939 return STATUS_SUCCESS;
4940 }
4941
4942 /*
4943 * @implemented
4944 */
4945 PRDBSS_DEVICE_OBJECT
4946 RxGetTopDeviceObjectIfRdbssIrp(
4947 VOID)
4948 {
4949 PIRP TopLevelIrp;
4950 PRDBSS_DEVICE_OBJECT TopDevice = NULL;
4951
4952 TopLevelIrp = IoGetTopLevelIrp();
4953 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
4954 {
4955 TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject;
4956 }
4957
4958 return TopDevice;
4959 }
4960
4961 /*
4962 * @implemented
4963 */
4964 LUID
4965 RxGetUid(
4966 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
4967 {
4968 LUID Luid;
4969 PACCESS_TOKEN Token;
4970
4971 PAGED_CODE();
4972
4973 Token = SeQuerySubjectContextToken(SubjectSecurityContext);
4974 SeQueryAuthenticationIdToken(Token, &Luid);
4975
4976 return Luid;
4977 }
4978
4979 VOID
4980 NTAPI
4981 RxIndicateChangeOfBufferingStateForSrvOpen(
4982 PMRX_SRV_CALL SrvCall,
4983 PMRX_SRV_OPEN SrvOpen,
4984 PVOID SrvOpenKey,
4985 PVOID Context)
4986 {
4987 UNIMPLEMENTED;
4988 }
4989
4990 VOID
4991 NTAPI
4992 RxInitializeDebugSupport(
4993 VOID)
4994 {
4995 UNIMPLEMENTED;
4996 }
4997
4998 /*
4999 * @implemented
5000 */
5001 VOID
5002 NTAPI
5003 RxInitializeDispatchVectors(
5004 PDRIVER_OBJECT DriverObject)
5005 {
5006 USHORT i;
5007
5008 PAGED_CODE();
5009
5010 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
5011 {
5012 DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
5013 }
5014
5015 RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector;
5016 ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
5017 ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
5018
5019 DriverObject->FastIoDispatch = &RxFastIoDispatch;
5020 RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch);
5021 RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
5022 RxFastIoDispatch.FastIoRead = RxFastIoRead;
5023 RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
5024 RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
5025 RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
5026 RxFastIoDispatch.FastIoLock = NULL;
5027 RxFastIoDispatch.FastIoUnlockSingle = NULL;
5028 RxFastIoDispatch.FastIoUnlockAll = NULL;
5029 RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
5030 RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
5031 RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
5032 RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
5033 RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
5034 RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
5035
5036 RxInitializeTopLevelIrpPackage();
5037
5038 RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite;
5039 RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite;
5040 RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead;
5041 RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
5042
5043 RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire;
5044 RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease;
5045 RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire;
5046 RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;
5047 }
5048
5049 NTSTATUS
5050 NTAPI
5051 RxInitializeLog(
5052 VOID)
5053 {
5054 UNIMPLEMENTED;
5055 return STATUS_NOT_IMPLEMENTED;
5056 }
5057
5058 /*
5059 * @implemented
5060 */
5061 VOID
5062 RxInitializeMinirdrDispatchTable(
5063 IN PDRIVER_OBJECT DriverObject)
5064 {
5065 PAGED_CODE();
5066 }
5067
5068 /*
5069 * @implemented
5070 */
5071 NTSTATUS
5072 NTAPI
5073 RxInitializeRegistrationStructures(
5074 VOID)
5075 {
5076 PAGED_CODE();
5077
5078 ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
5079 RxData.NumberOfMinirdrsRegistered = 0;
5080 RxData.NumberOfMinirdrsStarted = 0;
5081 InitializeListHead(&RxData.RegisteredMiniRdrs);
5082
5083 return STATUS_SUCCESS;
5084 }
5085
5086 /*
5087 * @implemented
5088 */
5089 VOID
5090 NTAPI
5091 RxInitializeTopLevelIrpPackage(
5092 VOID)
5093 {
5094 KeInitializeSpinLock(&TopLevelIrpSpinLock);
5095 InitializeListHead(&TopLevelIrpAllocatedContextsList);
5096 }
5097
5098 VOID
5099 NTAPI
5100 RxInitUnwind(
5101 PDRIVER_OBJECT DriverObject,
5102 USHORT State)
5103 {
5104 UNIMPLEMENTED;
5105 }
5106
5107 /*
5108 * @implemented
5109 */
5110 BOOLEAN
5111 RxIsMemberOfTopLevelIrpAllocatedContextsList(
5112 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
5113 {
5114 KIRQL OldIrql;
5115 PLIST_ENTRY NextEntry;
5116 BOOLEAN Found = FALSE;
5117 PRX_TOPLEVELIRP_CONTEXT ListContext;
5118
5119 /* Browse all the allocated TLC to find ours */
5120 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
5121 for (NextEntry = TopLevelIrpAllocatedContextsList.Flink;
5122 NextEntry != &TopLevelIrpAllocatedContextsList;
5123 NextEntry = NextEntry->Flink)
5124 {
5125 ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry);
5126 ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
5127 ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
5128
5129 /* Found! */
5130 if (ListContext == TopLevelContext)
5131 {
5132 Found = TRUE;
5133 break;
5134 }
5135 }
5136 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
5137
5138 return Found;
5139 }
5140
5141 /*
5142 * @implemented
5143 */
5144 BOOLEAN
5145 RxIsOkToPurgeFcb(
5146 PFCB Fcb)
5147 {
5148 PLIST_ENTRY Entry;
5149
5150 /* No associated SRV_OPEN, it's OK to purge */
5151 if (IsListEmpty(&Fcb->SrvOpenList))
5152 {
5153 return TRUE;
5154 }
5155
5156 /* Only allow to purge if all the associated SRV_OPEN
5157 * - have no outstanding opens ongoing
5158 * - have only read attribute set
5159 */
5160 for (Entry = Fcb->SrvOpenList.Flink;
5161 Entry != &Fcb->SrvOpenList;
5162 Entry = Entry->Flink)
5163 {
5164 PSRV_OPEN SrvOpen;
5165
5166 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
5167
5168 /* Failing previous needs, don't allow purge */
5169 if (SrvOpen->UncleanFobxCount != 0 ||
5170 (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
5171 {
5172 return FALSE;
5173 }
5174 }
5175
5176 /* All correct, allow purge */
5177 return TRUE;
5178 }
5179
5180 /*
5181 * @implemented
5182 */
5183 BOOLEAN
5184 RxIsThisAnRdbssTopLevelContext(
5185 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
5186 {
5187 ULONG_PTR StackTop, StackBottom;
5188
5189 /* Bail out for flags */
5190 if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP)
5191 {
5192 return FALSE;
5193 }
5194
5195 /* Is our provided TLC allocated on stack? */
5196 IoGetStackLimits(&StackTop, &StackBottom);
5197 if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) &&
5198 (ULONG_PTR)TopLevelContext >= StackTop)
5199 {
5200 /* Yes, so check whether it's really a TLC by checking alignement & signature */
5201 if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)
5202 {
5203 return TRUE;
5204 }
5205
5206 return FALSE;
5207 }
5208
5209 /* No, use the helper function */
5210 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);
5211 }
5212
5213 /*
5214 * @implemented
5215 */
5216 BOOLEAN
5217 RxIsThisTheTopLevelIrp(
5218 IN PIRP Irp)
5219 {
5220 PIRP TopLevelIrp;
5221
5222 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
5223 TopLevelIrp = IoGetTopLevelIrp();
5224 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
5225 {
5226 TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp;
5227 }
5228
5229 return (TopLevelIrp == Irp);
5230 }
5231
5232 NTSTATUS
5233 NTAPI
5234 RxLockOperationCompletion(
5235 IN PVOID Context,
5236 IN PIRP Irp)
5237 {
5238 UNIMPLEMENTED;
5239 return STATUS_NOT_IMPLEMENTED;
5240 }
5241
5242 /*
5243 * @implemented
5244 */
5245 VOID
5246 NTAPI
5247 RxLogEventDirect(
5248 IN PRDBSS_DEVICE_OBJECT DeviceObject,
5249 IN PUNICODE_STRING OriginatorId,
5250 IN ULONG EventId,
5251 IN NTSTATUS Status,
5252 IN ULONG Line)
5253 {
5254 PUNICODE_STRING Originator = OriginatorId;
5255 LARGE_INTEGER LargeLine;
5256
5257 /* Set optional parameters */
5258 LargeLine.QuadPart = Line;
5259 if (OriginatorId == NULL || OriginatorId->Length == 0)
5260 {
5261 Originator = (PUNICODE_STRING)&unknownId;
5262 }
5263
5264 /* And log */
5265 RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);
5266 }
5267
5268 VOID
5269 NTAPI
5270 RxLogEventWithAnnotation(
5271 IN PRDBSS_DEVICE_OBJECT DeviceObject,
5272 IN ULONG EventId,
5273 IN NTSTATUS Status,
5274 IN PVOID DataBuffer,
5275 IN USHORT DataBufferLength,
5276 IN PUNICODE_STRING Annotation,
5277 IN ULONG AnnotationCount)
5278 {
5279 UNIMPLEMENTED;
5280 }
5281
5282 NTSTATUS
5283 NTAPI
5284 RxLowIoCompletion(
5285 PRX_CONTEXT RxContext)
5286 {
5287 UNIMPLEMENTED;
5288 return STATUS_NOT_IMPLEMENTED;
5289 }
5290
5291 /*
5292 * @implemented
5293 */
5294 NTSTATUS
5295 NTAPI
5296 RxLowIoIoCtlShellCompletion(
5297 PRX_CONTEXT RxContext)
5298 {
5299 PIRP Irp;
5300 NTSTATUS Status;
5301
5302 PAGED_CODE();
5303
5304 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
5305
5306 Irp = RxContext->CurrentIrp;
5307 Status = RxContext->IoStatusBlock.Status;
5308
5309 /* Set information and status */
5310 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
5311 {
5312 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
5313 }
5314
5315 Irp->IoStatus.Status = Status;
5316
5317 return Status;
5318 }
5319
5320 NTSTATUS
5321 RxLowIoLockControlShell(
5322 IN PRX_CONTEXT RxContext)
5323 {
5324 UNIMPLEMENTED;
5325 return STATUS_NOT_IMPLEMENTED;
5326 }
5327
5328 /*
5329 * @implemented
5330 */
5331 NTSTATUS
5332 RxLowIoReadShell(
5333 PRX_CONTEXT RxContext)
5334 {
5335 PFCB Fcb;
5336 NTSTATUS Status;
5337
5338 PAGED_CODE();
5339
5340 DPRINT("RxLowIoReadShell(%p)\n", RxContext);
5341
5342 Fcb = (PFCB)RxContext->pFcb;
5343 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
5344 {
5345 return STATUS_MORE_PROCESSING_REQUIRED;
5346 }
5347
5348 /* Always update stats for disks */
5349 if (Fcb->CachedNetRootType == NET_ROOT_DISK)
5350 {
5351 ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
5352 }
5353
5354 /* And forward the read to the mini-rdr */
5355 Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion);
5356 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
5357
5358 return Status;
5359 }
5360
5361 NTSTATUS
5362 NTAPI
5363 RxLowIoReadShellCompletion(
5364 PRX_CONTEXT RxContext)
5365 {
5366 PIRP Irp;
5367 PFCB Fcb;
5368 NTSTATUS Status;
5369 BOOLEAN PagingIo, IsPipe;
5370 PIO_STACK_LOCATION Stack;
5371 PLOWIO_CONTEXT LowIoContext;
5372
5373 PAGED_CODE();
5374
5375 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
5376
5377 Status = RxContext->IoStatusBlock.Status;
5378 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
5379
5380 Irp = RxContext->CurrentIrp;
5381 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
5382
5383 /* Set IRP information from the RX_CONTEXT status block */
5384 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
5385
5386 /* Fixup status for paging file if nothing was read */
5387 if (PagingIo)
5388 {
5389 if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0)
5390 {
5391 Status = STATUS_END_OF_FILE;
5392 }
5393 }
5394
5395 LowIoContext = &RxContext->LowIoContext;
5396 ASSERT(RxLowIoIsBufferLocked(LowIoContext));
5397
5398 /* Check broken cases that should never happen */
5399 Fcb = (PFCB)RxContext->pFcb;
5400 if (Status == STATUS_FILE_LOCK_CONFLICT)
5401 {
5402 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED))
5403 {
5404 ASSERT(FALSE);
5405 return STATUS_RETRY;
5406 }
5407 }
5408 else if (Status == STATUS_SUCCESS)
5409 {
5410 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
5411 {
5412 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) ||
5413 BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED))
5414 {
5415 ASSERT(FALSE);
5416 }
5417 }
5418
5419 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
5420 {
5421 ASSERT(FALSE);
5422 }
5423 }
5424
5425 /* Readahead should go through Cc and not finish here */
5426 ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
5427
5428 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
5429 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
5430 {
5431 return Status;
5432 }
5433
5434 Stack = RxContext->CurrentIrpSp;
5435 IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
5436 /* Release lock if required */
5437 if (PagingIo)
5438 {
5439 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
5440 }
5441 else
5442 {
5443 /* Set FastIo if read was a success */
5444 if (NT_SUCCESS(Status) && !IsPipe)
5445 {
5446 SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ);
5447 }
5448
5449 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
5450 {
5451 RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue);
5452 }
5453 else
5454 {
5455 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
5456 }
5457 }
5458
5459 if (IsPipe)
5460 {
5461 UNIMPLEMENTED;
5462 }
5463
5464 /* Final sanity checks */
5465 ASSERT(Status != STATUS_RETRY);
5466 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
5467 ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
5468
5469 return Status;
5470 }
5471
5472 NTSTATUS
5473 RxNotifyChangeDirectory(
5474 PRX_CONTEXT RxContext)
5475 {
5476 UNIMPLEMENTED;
5477 return STATUS_NOT_IMPLEMENTED;
5478 }
5479
5480 NTSTATUS
5481 RxPostStackOverflowRead (
5482 IN PRX_CONTEXT RxContext)
5483 {
5484 PAGED_CODE();
5485
5486 UNIMPLEMENTED;
5487 return STATUS_NOT_IMPLEMENTED;
5488 }
5489
5490 /*
5491 * @implemented
5492 */
5493 VOID
5494 RxpPrepareCreateContextForReuse(
5495 PRX_CONTEXT RxContext)
5496 {
5497 /* Reuse can only happen for open operations (STATUS_RETRY) */
5498 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
5499
5500 /* Release the FCB if it was acquired */
5501 if (RxContext->Create.FcbAcquired)
5502 {
5503 RxReleaseFcb(RxContext, RxContext->pFcb);
5504 RxContext->Create.FcbAcquired = FALSE;
5505 }
5506
5507 /* Free the canonical name */
5508 RxFreeCanonicalNameBuffer(RxContext);
5509
5510 /* If we have a VNetRoot associated */
5511 if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL)
5512 {
5513 /* Remove our link and thus, dereference the VNetRoot */
5514 RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE);
5515 if (RxContext->Create.pVNetRoot != NULL)
5516 {
5517 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE);
5518 RxContext->Create.pVNetRoot = NULL;
5519 }
5520 RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
5521 }
5522
5523 DPRINT("RxContext: %p prepared for reuse\n", RxContext);
5524 }
5525
5526 /*
5527 * @implemented
5528 */
5529 NTSTATUS
5530 RxpQueryInfoMiniRdr(
5531 PRX_CONTEXT RxContext,
5532 FILE_INFORMATION_CLASS FileInfoClass,
5533 PVOID Buffer)
5534 {
5535 PFCB Fcb;
5536 NTSTATUS Status;
5537
5538 Fcb = (PFCB)RxContext->pFcb;
5539
5540 /* Set the RX_CONTEXT */
5541 RxContext->Info.FileInformationClass = FileInfoClass;
5542 RxContext->Info.Buffer = Buffer;
5543
5544 /* Pass down */
5545 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
5546
5547 return Status;
5548 }
5549
5550 /*
5551 * @implemented
5552 */
5553 NTSTATUS
5554 RxPrefixClaim(
5555 IN PRX_CONTEXT RxContext)
5556 {
5557 PIRP Irp;
5558 NTSTATUS Status;
5559 NET_ROOT_TYPE NetRootType;
5560 UNICODE_STRING CanonicalName, FileName, NetRootName;
5561
5562 PAGED_CODE();
5563
5564 Irp = RxContext->CurrentIrp;
5565
5566 /* This has to come from MUP */
5567 if (Irp->RequestorMode == UserMode)
5568 {
5569 return STATUS_INVALID_DEVICE_REQUEST;
5570 }
5571
5572 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL)
5573 {
5574 PQUERY_PATH_REQUEST QueryRequest;
5575
5576 /* Get parameters */
5577 QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
5578
5579 /* Don't overflow allocation */
5580 if (QueryRequest->PathNameLength >= MAXUSHORT - 1)
5581 {
5582 return STATUS_INVALID_DEVICE_REQUEST;
5583 }
5584
5585 /* Forcefully rewrite IRP MJ */
5586 RxContext->MajorFunction = IRP_MJ_CREATE;
5587
5588 /* Fake canon name */
5589 RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
5590 if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
5591 {
5592 Status = STATUS_INSUFFICIENT_RESOURCES;
5593 goto Leave;
5594 }
5595
5596 /* Copy the prefix to look for */
5597 RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength);
5598 RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength;
5599 RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
5600
5601 /* Zero the create parameters */
5602 RtlZeroMemory(&RxContext->Create.NtCreateParameters,
5603 FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters));
5604 RxContext->Create.ThisIsATreeConnectOpen = TRUE;
5605 RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext;
5606 }
5607 else
5608 {
5609 /* If not devcontrol, it comes from open, name was already copied */
5610 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
5611 ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL);
5612 }
5613
5614 /* Canonilize name */
5615 NetRootType = NET_ROOT_WILD;
5616 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
5617 FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
5618 FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
5619 FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
5620 NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
5621 NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
5622 NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
5623 Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType);
5624 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
5625 if (NT_SUCCESS(Status))
5626 {
5627 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName);
5628 }
5629 if (Status == STATUS_PENDING)
5630 {
5631 return Status;
5632 }
5633 /* Reply to MUP */
5634 if (NT_SUCCESS(Status))
5635 {
5636 PQUERY_PATH_RESPONSE QueryResponse;
5637
5638 /* We accept the length that was canon (minus netroot) */
5639 QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
5640 QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length;
5641 }
5642
5643 Leave:
5644 /* If we reach that point with MJ, reset everything and make IRP being a device control */
5645 if (RxContext->MajorFunction == IRP_MJ_CREATE)
5646 {
5647 if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
5648 {
5649 RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
5650 }
5651
5652 RxpPrepareCreateContextForReuse(RxContext);
5653
5654 RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
5655 }
5656
5657 return Status;
5658 }
5659
5660 NTSTATUS
5661 NTAPI
5662 RxPrepareToReparseSymbolicLink(
5663 PRX_CONTEXT RxContext,
5664 BOOLEAN SymbolicLinkEmbeddedInOldPath,
5665 PUNICODE_STRING NewPath,
5666 BOOLEAN NewPathIsAbsolute,
5667 PBOOLEAN ReparseRequired)
5668 {
5669 UNIMPLEMENTED;
5670 return STATUS_NOT_IMPLEMENTED;
5671 }
5672
5673 /*
5674 * @implemented
5675 */
5676 VOID
5677 RxPrePostIrp(
5678 IN PVOID Context,
5679 IN PIRP Irp)
5680 {
5681 LOCK_OPERATION Lock;
5682 PIO_STACK_LOCATION Stack;
5683 PRX_CONTEXT RxContext = Context;
5684
5685 /* NULL IRP is no option */
5686 if (Irp == NULL)
5687 {
5688 return;
5689 }
5690
5691 /* Check whether preparation was really needed */
5692 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
5693 {
5694 return;
5695 }
5696 /* Mark the context as prepared */
5697 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
5698
5699 /* Just lock the user buffer, with the correct length, depending on the MJ */
5700 Lock = IoReadAccess;
5701 Stack = RxContext->CurrentIrpSp;
5702 if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
5703 {
5704 if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
5705 {
5706 if (RxContext->MajorFunction == IRP_MJ_READ)
5707 {
5708 Lock = IoWriteAccess;
5709 }
5710 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length);
5711 }
5712 }
5713 else
5714 {
5715 if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) ||
5716 RxContext->MajorFunction == IRP_MJ_QUERY_EA)
5717 {
5718 Lock = IoWriteAccess;
5719 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length);
5720 }
5721 else if (RxContext->MajorFunction == IRP_MJ_SET_EA)
5722 {
5723 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length);
5724 }
5725 }
5726
5727 /* As it will be posted (async), mark the IRP pending */
5728 IoMarkIrpPending(Irp);
5729 }
5730
5731 VOID
5732 NTAPI
5733 RxpUnregisterMinirdr(
5734 IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
5735 {
5736 UNIMPLEMENTED;
5737 }
5738
5739 /*
5740 * @implemented
5741 */
5742 VOID
5743 RxPurgeNetFcb(
5744 PFCB Fcb,
5745 PRX_CONTEXT LocalContext)
5746 {
5747 NTSTATUS Status;
5748
5749 PAGED_CODE();
5750
5751 /* First, flush */
5752 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
5753
5754 /* And force close */
5755 RxReleaseFcb(NULL, Fcb);
5756 MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
5757 Status = RxAcquireExclusiveFcb(NULL, Fcb);
5758 ASSERT(Status == STATUS_SUCCESS);
5759 }
5760
5761 NTSTATUS
5762 RxQueryAlternateNameInfo(
5763 PRX_CONTEXT RxContext,
5764 PFILE_NAME_INFORMATION AltNameInfo)
5765 {
5766 UNIMPLEMENTED;
5767 return STATUS_NOT_IMPLEMENTED;
5768 }
5769
5770 /*
5771 * @implemented
5772 */
5773 NTSTATUS
5774 RxQueryBasicInfo(
5775 PRX_CONTEXT RxContext,
5776 PFILE_BASIC_INFORMATION BasicInfo)
5777 {
5778 PAGED_CODE();
5779
5780 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
5781
5782 /* Simply zero and forward to mini-rdr */
5783 RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION));
5784 return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);
5785 }
5786
5787 NTSTATUS
5788 RxQueryCompressedInfo(
5789 PRX_CONTEXT RxContext,
5790 PFILE_COMPRESSION_INFORMATION CompressionInfo)
5791 {
5792 UNIMPLEMENTED;
5793 return STATUS_NOT_IMPLEMENTED;
5794 }
5795
5796 /*
5797 * @implemented
5798 */
5799 NTSTATUS
5800 RxQueryDirectory(
5801 PRX_CONTEXT RxContext)
5802 {
5803 PIRP Irp;
5804 PFCB Fcb;
5805 PFOBX Fobx;
5806 UCHAR Flags;
5807 NTSTATUS Status;
5808 BOOLEAN LockNotGranted;
5809 ULONG Length, FileIndex;
5810 PUNICODE_STRING FileName;
5811 PIO_STACK_LOCATION Stack;
5812 FILE_INFORMATION_CLASS FileInfoClass;
5813
5814 PAGED_CODE();
5815
5816 DPRINT("RxQueryDirectory(%p)\n", RxContext);
5817
5818 /* Get parameters */
5819 Stack = RxContext->CurrentIrpSp;
5820 Length = Stack->Parameters.QueryDirectory.Length;
5821 FileName = Stack->Parameters.QueryDirectory.FileName;
5822 FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass;
5823 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
5824 FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length,
5825 FileName, FileInfoClass);
5826
5827 Irp = RxContext->CurrentIrp;
5828 Flags = Stack->Flags;
5829 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
5830 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
5831
5832 if (FileName != NULL)
5833 {
5834 DPRINT("FileName: %wZ\n", FileName);
5835 }
5836
5837 /* No FOBX: not a standard file/directory */
5838 Fobx = (PFOBX)RxContext->pFobx;
5839 if (Fobx == NULL)
5840 {
5841 return STATUS_OBJECT_NAME_INVALID;
5842 }
5843
5844 /* We can only deal with a disk */
5845 Fcb = (PFCB)RxContext->pFcb;
5846 if (Fcb->pNetRoot->Type != NET_ROOT_DISK)
5847 {
5848 DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type);
5849 return STATUS_INVALID_DEVICE_REQUEST;
5850 }
5851
5852 /* Setup RX_CONTEXT related fields */
5853 RxContext->QueryDirectory.FileIndex = FileIndex;
5854 RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN);
5855 RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY);
5856 RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED);
5857 RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
5858
5859 /* We don't support (yet?) a specific index being set */
5860 if (RxContext->QueryDirectory.IndexSpecified)
5861 {
5862 return STATUS_NOT_IMPLEMENTED;
5863 }
5864
5865 /* Try to lock FCB */
5866 LockNotGranted = TRUE;
5867 if (RxContext->QueryDirectory.InitialQuery)
5868 {
5869 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5870 if (Status != STATUS_LOCK_NOT_GRANTED)
5871 {
5872 if (!NT_SUCCESS(Status))
5873 {
5874 return Status;
5875 }
5876
5877 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
5878 {
5879 RxContext->QueryDirectory.InitialQuery = FALSE;
5880 RxConvertToSharedFcb(RxContext, Fcb);
5881 }
5882
5883 LockNotGranted = FALSE;
5884 }
5885 }
5886 else
5887 {
5888 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5889 if (Status != STATUS_LOCK_NOT_GRANTED)
5890 {
5891 if (!NT_SUCCESS(Status))
5892 {
5893 return Status;
5894 }
5895
5896 LockNotGranted = FALSE;
5897 }
5898 }
5899
5900 /* If it failed, post request */
5901 if (LockNotGranted)
5902 {
5903 return RxFsdPostRequest(RxContext);
5904 }
5905
5906 /* This cannot be done on a orphaned directory */
5907 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
5908 {
5909 RxReleaseFcb(RxContext, Fcb);
5910 return STATUS_FILE_CLOSED;
5911 }
5912
5913 _SEH2_TRY
5914 {
5915 /* Set index */
5916 if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan)
5917 {
5918 RxContext->QueryDirectory.FileIndex = 0;
5919 }
5920
5921 /* Assume success */
5922 Status = STATUS_SUCCESS;
5923 /* If initial query, prepare FOBX */
5924 if (RxContext->QueryDirectory.InitialQuery)
5925 {
5926 /* We cannot have a template already! */
5927 ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
5928
5929 /* If we have a file name and a correct one, duplicate it in the FOBX */
5930 if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL &&
5931 (FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') &&
5932 (FileName->Length != 12 * sizeof(WCHAR) ||
5933 RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR)))
5934 {
5935 Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
5936
5937 Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
5938 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
5939 {
5940 /* UNICODE_STRING; length has to be even */
5941 if ((FileName->Length & 1) != 0)
5942 {
5943 Status = STATUS_INVALID_PARAMETER;
5944 RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
5945 }
5946 else
5947 {
5948 Fobx->UnicodeQueryTemplate.Length = FileName->Length;
5949 Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
5950 RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
5951
5952 SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE);
5953 }
5954 }
5955 else
5956 {
5957 Status = STATUS_INSUFFICIENT_RESOURCES;
5958 }
5959 }
5960 /* No name specified, or a match all wildcard? Match everything */
5961 else
5962 {
5963 Fobx->ContainsWildCards = TRUE;
5964
5965 Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate;
5966 Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
5967 Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
5968
5969 SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
5970 }
5971
5972 /* No need for exclusive any longer */
5973 if (NT_SUCCESS(Status))
5974 {
5975 RxConvertToSharedFcb(RxContext, Fcb);
5976 }
5977 }
5978
5979 /* Lock user buffer and forward to mini-rdr */
5980 if (NT_SUCCESS(Status))
5981 {
5982 RxLockUserBuffer(RxContext, IoModifyAccess, Length);
5983 RxContext->Info.FileInformationClass = FileInfoClass;
5984 RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext);
5985 RxContext->Info.Length = Length;
5986
5987 if (RxContext->Info.Buffer != NULL)
5988 {
5989 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext));
5990 }
5991
5992 /* Post if mini-rdr asks to */
5993 if (RxContext->PostRequest)
5994 {
5995 RxFsdPostRequest(RxContext);
5996 }
5997 else
5998 {
5999 Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining;
6000 }
6001 }
6002 }
6003 _SEH2_FINALLY
6004 {
6005 RxReleaseFcb(RxContext, Fcb);
6006 }
6007 _SEH2_END;
6008
6009 return Status;
6010 }
6011
6012 NTSTATUS
6013 RxQueryEaInfo(
6014 PRX_CONTEXT RxContext,
6015 PFILE_EA_INFORMATION EaInfo)
6016 {
6017 UNIMPLEMENTED;
6018 return STATUS_NOT_IMPLEMENTED;
6019 }
6020
6021 NTSTATUS
6022 RxQueryInternalInfo(
6023 PRX_CONTEXT RxContext,
6024 PFILE_INTERNAL_INFORMATION InternalInfo)
6025 {
6026 UNIMPLEMENTED;
6027 return STATUS_NOT_IMPLEMENTED;
6028 }
6029
6030 NTSTATUS
6031 RxQueryNameInfo(
6032 PRX_CONTEXT RxContext,
6033 PFILE_NAME_INFORMATION NameInfo)
6034 {
6035 UNIMPLEMENTED;
6036 return STATUS_NOT_IMPLEMENTED;
6037 }
6038
6039 NTSTATUS
6040 RxQueryPipeInfo(
6041 PRX_CONTEXT RxContext,
6042 PFILE_PIPE_INFORMATION PipeInfo)
6043 {
6044 UNIMPLEMENTED;
6045 return STATUS_NOT_IMPLEMENTED;
6046 }
6047
6048 NTSTATUS
6049 RxQueryPositionInfo(
6050 PRX_CONTEXT RxContext,
6051 PFILE_POSITION_INFORMATION PositionInfo)
6052 {
6053 UNIMPLEMENTED;
6054 return STATUS_NOT_IMPLEMENTED;
6055 }
6056
6057 /*
6058 * @implemented
6059 */
6060 NTSTATUS
6061 RxQueryStandardInfo(
6062 PRX_CONTEXT RxContext,
6063 PFILE_STANDARD_INFORMATION StandardInfo)
6064 {
6065 PFCB Fcb;
6066 PFOBX Fobx;
6067 NTSTATUS Status;
6068
6069 PAGED_CODE();
6070
6071 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
6072
6073 /* Zero output buffer */
6074 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
6075
6076 Fcb = (PFCB)RxContext->pFcb;
6077 Fobx = (PFOBX)RxContext->pFobx;
6078 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
6079 if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
6080 BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
6081 {
6082 return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
6083 }
6084
6085 /* Otherwise, fill what we can already */
6086 Status = STATUS_SUCCESS;
6087 StandardInfo->NumberOfLinks = Fcb->NumberOfLinks;
6088 StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
6089 StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
6090 if (StandardInfo->NumberOfLinks == 0)
6091 {
6092 StandardInfo->NumberOfLinks = 1;
6093 }
6094
6095 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
6096 {
6097 StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
6098 RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart);
6099 }
6100
6101 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
6102 if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED))
6103 {
6104 Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
6105 }
6106 else
6107 {
6108 RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION);
6109 }
6110
6111 return Status;
6112 }
6113
6114 /*
6115 * @implemented
6116 */
6117 VOID
6118 NTAPI
6119 RxReadRegistryParameters(
6120 VOID)
6121 {
6122 NTSTATUS Status;
6123 HANDLE KeyHandle;
6124 ULONG ResultLength;
6125 UCHAR Buffer[0x40];
6126 UNICODE_STRING KeyName, ParamName;
6127 OBJECT_ATTRIBUTES ObjectAttributes;
6128 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
6129
6130 PAGED_CODE();
6131
6132 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
6133 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
6134 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6135 if (!NT_SUCCESS(Status))
6136 {
6137 return;
6138 }
6139
6140 PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
6141 RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles");
6142 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
6143 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
6144 {
6145 DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
6146 }
6147
6148 RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
6149 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
6150 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
6151 {
6152 ULONG Granularity = *(PULONG)PartialInfo->Data;
6153
6154 if (Granularity > 16)
6155 {
6156 Granularity = 16;
6157 }
6158
6159 ReadAheadGranularity = Granularity << PAGE_SHIFT;
6160 }
6161
6162 RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup");
6163 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
6164 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
6165 {
6166 DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
6167 }
6168
6169 ZwClose(KeyHandle);
6170 }
6171
6172 /*
6173 * @implemented
6174 */
6175 NTSTATUS
6176 NTAPI
6177 RxRegisterMinirdr(
6178 OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
6179 IN OUT PDRIVER_OBJECT DriverObject,
6180 IN PMINIRDR_DISPATCH MrdrDispatch,
6181 IN ULONG Controls,
6182 IN PUNICODE_STRING DeviceName,
6183 IN ULONG DeviceExtensionSize,
6184 IN DEVICE_TYPE DeviceType,
6185 IN ULONG DeviceCharacteristics)
6186 {
6187 NTSTATUS Status;
6188 PRDBSS_DEVICE_OBJECT RDBSSDevice;
6189
6190 PAGED_CODE();
6191
6192 if (!DeviceObject)
6193 {
6194 return STATUS_INVALID_PARAMETER;
6195 }
6196
6197 /* Create device object with provided parameters */
6198 Status = IoCreateDevice(DriverObject,
6199 DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT),
6200 DeviceName,
6201 DeviceType,
6202 DeviceCharacteristics,
6203 FALSE,
6204 (PDEVICE_OBJECT *)&RDBSSDevice);
6205 if (!NT_SUCCESS(Status))
6206 {
6207 return Status;
6208 }
6209
6210 if (!RxData.DriverObject)
6211 {
6212 return STATUS_UNSUCCESSFUL;
6213 }
6214
6215 /* Initialize our DO extension */
6216 RDBSSDevice->RDBSSDeviceObject = NULL;
6217 ++RxFileSystemDeviceObject->ReferenceCount;
6218 *DeviceObject = RDBSSDevice;
6219 RDBSSDevice->RdbssExports = &RxExports;
6220 RDBSSDevice->Dispatch = MrdrDispatch;
6221 RDBSSDevice->RegistrationControls = Controls;
6222 RDBSSDevice->DeviceName = *DeviceName;
6223 RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
6224 RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
6225 InitializeListHead(&RDBSSDevice->OverflowQueue[0]);
6226 InitializeListHead(&RDBSSDevice->OverflowQueue[1]);
6227 InitializeListHead(&RDBSSDevice->OverflowQueue[2]);
6228 KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock);
6229 RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
6230
6231 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
6232
6233 ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex);
6234 InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks);
6235 ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
6236
6237 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
6238 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH))
6239 {
6240 RxInitializeMinirdrDispatchTable(DriverObject);
6241 }
6242
6243 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
6244 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER))
6245 {
6246 LARGE_INTEGER ScavengerTimeLimit;
6247
6248 RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject;
6249 RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
6250 RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
6251 ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
6252 RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
6253 RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
6254 }
6255
6256 RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
6257
6258 return STATUS_SUCCESS;
6259 }
6260
6261 VOID
6262 NTAPI
6263 RxReleaseFcbFromLazyWrite(
6264 PVOID Context)
6265 {
6266 UNIMPLEMENTED;
6267 }
6268
6269 VOID
6270 NTAPI
6271 RxReleaseFcbFromReadAhead(
6272 PVOID Context)
6273 {
6274 UNIMPLEMENTED;
6275 }
6276
6277 VOID
6278 NTAPI
6279 RxReleaseFileForNtCreateSection(
6280 PFILE_OBJECT FileObject)
6281 {
6282 UNIMPLEMENTED;
6283 }
6284
6285 NTSTATUS
6286 NTAPI
6287 RxReleaseForCcFlush(
6288 PFILE_OBJECT FileObject,
6289 PDEVICE_OBJECT DeviceObject)
6290 {
6291 UNIMPLEMENTED;
6292 return STATUS_NOT_IMPLEMENTED;
6293 }
6294
6295 /*
6296 * @implemented
6297 */
6298 VOID
6299 RxRemoveFromTopLevelIrpAllocatedContextsList(
6300 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6301 {
6302 KIRQL OldIrql;
6303
6304 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
6305 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6306 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6307
6308 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
6309 RemoveEntryList(&TopLevelContext->ListEntry);
6310 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
6311 }
6312
6313 /*
6314 * @implemented
6315 */
6316 PRX_CONTEXT
6317 RxRemoveOverflowEntry(
6318 PRDBSS_DEVICE_OBJECT DeviceObject,
6319 WORK_QUEUE_TYPE Queue)
6320 {
6321 KIRQL OldIrql;
6322 PRX_CONTEXT Context;
6323
6324 KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql);
6325 if (DeviceObject->OverflowQueueCount[Queue] <= 0)
6326 {
6327 /* No entries left, nothing to return */
6328 InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]);
6329 Context = NULL;
6330 }
6331 else
6332 {
6333 PLIST_ENTRY Entry;
6334
6335 /* Decrement count */
6336 --DeviceObject->OverflowQueueCount[Queue];
6337
6338 /* Return head */
6339 Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]);
6340 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry);
6341 ClearFlag(Context->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
6342 Context->OverflowListEntry.Flink = NULL;
6343 }
6344 KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
6345
6346 return Context;
6347 }
6348
6349 /*
6350 * @implemented
6351 */
6352 VOID
6353 RxRemoveShareAccess(
6354 _Inout_ PFILE_OBJECT FileObject,
6355 _Inout_ PSHARE_ACCESS ShareAccess,
6356 _In_ PSZ where,
6357 _In_ PSZ wherelogtag)
6358 {
6359 PAGED_CODE();
6360
6361 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
6362 IoRemoveShareAccess(FileObject, ShareAccess);
6363 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
6364 }
6365
6366 /*
6367 * @implemented
6368 */
6369 VOID
6370 RxRemoveShareAccessPerSrvOpens(
6371 IN OUT PSRV_OPEN SrvOpen)
6372 {
6373 ACCESS_MASK DesiredAccess;
6374 BOOLEAN ReadAccess;
6375 BOOLEAN WriteAccess;
6376 BOOLEAN DeleteAccess;
6377
6378 PAGED_CODE();
6379
6380 /* Get access that were granted to SRV_OPEN */
6381 DesiredAccess = SrvOpen->DesiredAccess;
6382 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
6383 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
6384 DeleteAccess = (DesiredAccess & DELETE) != 0;
6385
6386 /* If any, drop them */
6387 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
6388 {
6389 BOOLEAN SharedRead;
6390 BOOLEAN SharedWrite;
6391 BOOLEAN SharedDelete;
6392 ULONG DesiredShareAccess;
6393 PSHARE_ACCESS ShareAccess;
6394
6395 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
6396 DesiredShareAccess = SrvOpen->ShareAccess;
6397
6398 ShareAccess->Readers -= ReadAccess;
6399 ShareAccess->Writers -= WriteAccess;
6400 ShareAccess->Deleters -= DeleteAccess;
6401
6402 ShareAccess->OpenCount--;
6403
6404 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
6405 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
6406 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
6407 ShareAccess->SharedRead -= SharedRead;
6408 ShareAccess->SharedWrite -= SharedWrite;
6409 ShareAccess->SharedDelete -= SharedDelete;
6410 }
6411 }
6412
6413 NTSTATUS
6414 RxSearchForCollapsibleOpen(
6415 PRX_CONTEXT RxContext,
6416 ACCESS_MASK DesiredAccess,
6417 ULONG ShareAccess)
6418 {
6419 PFCB Fcb;
6420 NTSTATUS Status;
6421 PLIST_ENTRY ListEntry;
6422 BOOLEAN ShouldTry, Purged, Scavenged;
6423
6424 PAGED_CODE();
6425
6426 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
6427
6428 Fcb = (PFCB)RxContext->pFcb;
6429
6430 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
6431 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
6432 {
6433 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
6434
6435 RxScavengeRelatedFobxs(Fcb);
6436 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
6437
6438 return STATUS_NOT_FOUND;
6439 }
6440
6441 /* If basic open, ask the mini-rdr if we should try to collapse */
6442 if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN ||
6443 RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF)
6444 {
6445 ShouldTry = TRUE;
6446
6447 if (Fcb->MRxDispatch != NULL)
6448 {
6449 ASSERT(RxContext->pRelevantSrvOpen == NULL);
6450 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
6451
6452 ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext));
6453 }
6454 }
6455 else
6456 {
6457 ShouldTry = FALSE;
6458 }
6459
6460 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE))
6461 {
6462 ShouldTry = FALSE;
6463 }
6464
6465 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
6466 if (!ShouldTry)
6467 {
6468 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess)))
6469 {
6470 return STATUS_NOT_FOUND;
6471 }
6472
6473 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
6474
6475 RxScavengeRelatedFobxs(Fcb);
6476 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
6477
6478 return STATUS_NOT_FOUND;
6479 }
6480
6481 /* Only collapse for matching NET_ROOT & disks */
6482 if (Fcb->pNetRoot != RxContext->Create.pNetRoot ||
6483 Fcb->pNetRoot->Type != NET_ROOT_DISK)
6484 {
6485 return STATUS_NOT_FOUND;
6486 }
6487
6488 Purged = FALSE;
6489 Scavenged = FALSE;
6490 Status = STATUS_NOT_FOUND;
6491 TryAgain:
6492 /* Browse all our SRV_OPEN to find the matching one */
6493 for (ListEntry = Fcb->SrvOpenList.Flink;
6494 ListEntry != &Fcb->SrvOpenList;
6495 ListEntry = ListEntry->Flink)
6496 {
6497 PSRV_OPEN SrvOpen;
6498
6499 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
6500 /* Not the same VNET_ROOT, move to the next one */
6501 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
6502 {
6503 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
6504 continue;
6505 }
6506
6507 /* Is there a sharing violation? */
6508 if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess ||
6509 BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED)))
6510 {
6511 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
6512 {
6513 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
6514 continue;
6515 }
6516
6517 /* Check against the SRV_OPEN */
6518 Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess);
6519 if (!NT_SUCCESS(Status))
6520 {
6521 break;
6522 }
6523 }
6524 else
6525 {
6526 /* Don't allow collaspse for reparse point opening */
6527 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT))
6528 {
6529 Purged = TRUE;
6530 Scavenged = TRUE;
6531 Status = STATUS_NOT_FOUND;
6532 break;
6533 }
6534
6535 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
6536 if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY))
6537 {
6538 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
6539
6540 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
6541 if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)))
6542 {
6543 /* Is close delayed - great reuse*/
6544 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
6545 {
6546 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen);
6547 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
6548 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
6549 }
6550
6551 return STATUS_SUCCESS;
6552 }
6553
6554 Status = STATUS_NOT_FOUND;
6555 break;
6556 }
6557 }
6558 }
6559 /* We browse the whole list and didn't find any matching? NOT_FOUND */
6560 if (ListEntry == &Fcb->SrvOpenList)
6561 {
6562 Status = STATUS_NOT_FOUND;
6563 }
6564
6565 /* Only required access: read attributes? Don't reuse */
6566 if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES)
6567 {
6568 return STATUS_NOT_FOUND;
6569 }
6570
6571 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
6572 if (!Scavenged)
6573 {
6574 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
6575 Scavenged = TRUE;
6576 RxScavengeRelatedFobxs(Fcb);
6577 goto TryAgain;
6578 }
6579
6580 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
6581 if (!Purged && RxIsOkToPurgeFcb(Fcb))
6582 {
6583 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
6584 Purged = TRUE;
6585 goto TryAgain;
6586 }
6587
6588 /* If sharing violation, keep track of it */
6589 if (Status == STATUS_SHARING_VIOLATION)
6590 {
6591 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
6592 }
6593
6594 DPRINT("Status: %x\n", Status);
6595 return Status;
6596 }
6597
6598 /*
6599 * @implemented
6600 */
6601 VOID
6602 RxSetShareAccess(
6603 _In_ ACCESS_MASK DesiredAccess,
6604 _In_ ULONG DesiredShareAccess,
6605 _Inout_ PFILE_OBJECT FileObject,
6606 _Out_ PSHARE_ACCESS ShareAccess,
6607 _In_ PSZ where,
6608 _In_ PSZ wherelogtag)
6609 {
6610 PAGED_CODE();
6611
6612 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
6613 IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
6614 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
6615 }
6616
6617 /*
6618 * @implemented
6619 */
6620 VOID
6621 RxSetupNetFileObject(
6622 PRX_CONTEXT RxContext)
6623 {
6624 PFCB Fcb;
6625 PFOBX Fobx;
6626 PFILE_OBJECT FileObject;
6627 PIO_STACK_LOCATION Stack;
6628
6629 PAGED_CODE();
6630
6631 /* Assert FOBX is FOBX or NULL */
6632 Fobx = (PFOBX)RxContext->pFobx;
6633 ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
6634
6635 Fcb = (PFCB)RxContext->pFcb;
6636 Stack = RxContext->CurrentIrpSp;
6637 FileObject = Stack->FileObject;
6638 /* If it's temporary mark FO as such */
6639 if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB &&
6640 BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY))
6641 {
6642 if (FileObject == NULL)
6643 {
6644 return;
6645 }
6646
6647 FileObject->Flags |= FO_TEMPORARY_FILE;
6648 }
6649
6650 /* No FO, nothing to setup */
6651 if (FileObject == NULL)
6652 {
6653 return;
6654 }
6655
6656 /* Assign FCB & CCB (FOBX) to FO */
6657 FileObject->FsContext = Fcb;
6658 FileObject->FsContext2 = Fobx;
6659 if (Fobx != NULL)
6660 {
6661 ULONG_PTR StackTop, StackBottom;
6662
6663 /* If FO is allocated on pool, keep track of it */
6664 IoGetStackLimits(&StackTop, &StackBottom);
6665 if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop)
6666 {
6667 Fobx->AssociatedFileObject = FileObject;
6668 }
6669 else
6670 {
6671 Fobx->AssociatedFileObject = NULL;
6672 }
6673
6674 /* Make sure to mark FOBX if it's a DFS open */
6675 if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))
6676 {
6677 SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
6678 }
6679 else
6680 {
6681 ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
6682 }
6683 }
6684
6685 /* Set Cc pointers */
6686 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
6687
6688 /* Update access state */
6689 if (Stack->Parameters.Create.SecurityContext != NULL)
6690 {
6691 PACCESS_STATE AccessState;
6692
6693 AccessState = Stack->Parameters.Create.SecurityContext->AccessState;
6694 AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess;
6695 AccessState->RemainingDesiredAccess = 0;
6696 }
6697 }
6698
6699 /*
6700 * @implemented
6701 */
6702 NTSTATUS
6703 NTAPI
6704 RxStartMinirdr(
6705 IN PRX_CONTEXT RxContext,
6706 OUT PBOOLEAN PostToFsp)
6707 {
6708 NTSTATUS Status;
6709 BOOLEAN Wait, AlreadyStarted;
6710 PRDBSS_DEVICE_OBJECT DeviceObject;
6711
6712 /* If we've not been post, then, do it */
6713 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
6714 {
6715 SECURITY_SUBJECT_CONTEXT SubjectContext;
6716
6717 SeCaptureSubjectContext(&SubjectContext);
6718 RxContext->FsdUid = RxGetUid(&SubjectContext);
6719 SeReleaseSubjectContext(&SubjectContext);
6720
6721 *PostToFsp = TRUE;
6722 return STATUS_PENDING;
6723 }
6724
6725 /* Acquire all the required locks */
6726 Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
6727 if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait))
6728 {
6729 *PostToFsp = TRUE;
6730 return STATUS_PENDING;
6731 }
6732
6733 if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait))
6734 {
6735 ExReleaseResourceLite(&RxData.Resource);
6736 *PostToFsp = TRUE;
6737 return STATUS_PENDING;
6738 }
6739
6740 AlreadyStarted = FALSE;
6741 DeviceObject = RxContext->RxDeviceObject;
6742 _SEH2_TRY
6743 {
6744 /* MUP handle set, means already registered */
6745 if (DeviceObject->MupHandle != NULL)
6746 {
6747 AlreadyStarted = TRUE;
6748 Status = STATUS_REDIRECTOR_STARTED;
6749 _SEH2_LEAVE;
6750 }
6751
6752 /* If we're asked to register to MUP, then do it */
6753 Status = STATUS_SUCCESS;
6754 if (DeviceObject->RegisterUncProvider)
6755 {
6756 Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle,
6757 &DeviceObject->DeviceName,
6758 DeviceObject->RegisterMailSlotProvider);
6759 }
6760 if (!NT_SUCCESS(Status))
6761 {
6762 DeviceObject->MupHandle = NULL;
6763 _SEH2_LEAVE;
6764 }
6765
6766 /* Register as file system */
6767 IoRegisterFileSystem(&DeviceObject->DeviceObject);
6768 DeviceObject->RegisteredAsFileSystem = TRUE;
6769
6770 /* Inform mini-rdr it has to start */
6771 MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject));
6772 if (NT_SUCCESS(Status))
6773 {
6774 ++DeviceObject->StartStopContext.Version;
6775 RxSetRdbssState(DeviceObject, RDBSS_STARTED);
6776 InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
6777
6778 Status = RxInitializeMRxDispatcher(DeviceObject);
6779 }
6780 }
6781 _SEH2_FINALLY
6782 {
6783 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status))
6784 {
6785 if (!AlreadyStarted)
6786 {
6787 RxUnstart(RxContext, DeviceObject);
6788 }
6789 }
6790
6791 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
6792 ExReleaseResourceLite(&RxData.Resource);
6793 }
6794 _SEH2_END;
6795
6796 return Status;
6797 }
6798
6799 NTSTATUS
6800 NTAPI
6801 RxStopMinirdr(
6802 IN PRX_CONTEXT RxContext,
6803 OUT PBOOLEAN PostToFsp)
6804 {
6805 UNIMPLEMENTED;
6806 return STATUS_NOT_IMPLEMENTED;
6807 }
6808
6809 NTSTATUS
6810 RxSystemControl(
6811 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
6812 IN PIRP Irp)
6813 {
6814 UNIMPLEMENTED;
6815 return STATUS_NOT_IMPLEMENTED;
6816 }
6817
6818 /*
6819 * @implemented
6820 */
6821 BOOLEAN
6822 RxTryToBecomeTheTopLevelIrp(
6823 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
6824 IN PIRP Irp,
6825 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
6826 IN BOOLEAN ForceTopLevel
6827 )
6828 {
6829 BOOLEAN FromPool = FALSE;
6830
6831 PAGED_CODE();
6832
6833 /* If not top level, and not have to be, quit */
6834 if (IoGetTopLevelIrp() && !ForceTopLevel)
6835 {
6836 return FALSE;
6837 }
6838
6839 /* If not TLC provider, allocate one */
6840 if (TopLevelContext == NULL)
6841 {
6842 TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
6843 if (TopLevelContext == NULL)
6844 {
6845 return FALSE;
6846 }
6847
6848 FromPool = TRUE;
6849 }
6850
6851 /* Init it */
6852 __RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
6853
6854 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6855 if (FromPool)
6856 {
6857 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6858 }
6859
6860 /* Make it top level IRP */
6861 IoSetTopLevelIrp((PIRP)TopLevelContext);
6862 return TRUE;
6863 }
6864
6865 /*
6866 * @implemented
6867 */
6868 VOID
6869 RxUpdateShareAccess(
6870 _Inout_ PFILE_OBJECT FileObject,
6871 _Inout_ PSHARE_ACCESS ShareAccess,
6872 _In_ PSZ where,
6873 _In_ PSZ wherelogtag)
6874 {
6875 PAGED_CODE();
6876
6877 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
6878 IoUpdateShareAccess(FileObject, ShareAccess);
6879 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
6880 }
6881
6882 /*
6883 * @implemented
6884 */
6885 VOID
6886 RxUninitializeCacheMap(
6887 PRX_CONTEXT RxContext,
6888 PFILE_OBJECT FileObject,
6889 PLARGE_INTEGER TruncateSize)
6890 {
6891 PFCB Fcb;
6892 NTSTATUS Status;
6893 CACHE_UNINITIALIZE_EVENT UninitEvent;
6894
6895 PAGED_CODE();
6896
6897 Fcb = FileObject->FsContext;
6898 ASSERT(NodeTypeIsFcb(Fcb));
6899 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6900
6901 KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE);
6902 CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
6903
6904 /* Always release the FCB before waiting for the uninit event */
6905 RxReleaseFcb(RxContext, Fcb);
6906
6907 KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
6908
6909 /* Re-acquire it afterwards */
6910 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
6911 ASSERT(NT_SUCCESS(Status));
6912 }
6913
6914 VOID
6915 NTAPI
6916 RxUnload(
6917 IN PDRIVER_OBJECT DriverObject)
6918 {
6919 UNIMPLEMENTED;
6920 }
6921
6922 VOID
6923 NTAPI
6924 RxUnlockOperation(
6925 IN PVOID Context,
6926 IN PFILE_LOCK_INFO LockInfo)
6927 {
6928 UNIMPLEMENTED;
6929 }
6930
6931 VOID
6932 RxUnstart(
6933 PRX_CONTEXT Context,
6934 PRDBSS_DEVICE_OBJECT DeviceObject)
6935 {
6936 UNIMPLEMENTED;
6937 }
6938
6939 /*
6940 * @implemented
6941 */
6942 VOID
6943 RxUnwindTopLevelIrp(
6944 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6945 {
6946 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
6947
6948 /* No TLC provided? Ask the system for ours! */
6949 if (TopLevelContext == NULL)
6950 {
6951 TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
6952 if (TopLevelContext == NULL)
6953 {
6954 return;
6955 }
6956
6957 /* In that case, just assert it's really ours */
6958 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext));
6959 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6960 }
6961
6962 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6963 ASSERT(TopLevelContext->Thread == PsGetCurrentThread());
6964 /* Restore the previous top level IRP */
6965 IoSetTopLevelIrp(TopLevelContext->Previous);
6966 /* If TLC was allocated from pool, remove it from list and release it */
6967 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
6968 {
6969 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
6970 RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
6971 }
6972 }
6973
6974 /*
6975 * @implemented
6976 */
6977 VOID
6978 RxUpdateShareAccessPerSrvOpens(
6979 IN PSRV_OPEN SrvOpen)
6980 {
6981 ACCESS_MASK DesiredAccess;
6982 BOOLEAN ReadAccess;
6983 BOOLEAN WriteAccess;
6984 BOOLEAN DeleteAccess;
6985
6986 PAGED_CODE();
6987
6988 /* If already updated, no need to continue */
6989 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED))
6990 {
6991 return;
6992 }
6993
6994 /* Check if any access wanted */
6995 DesiredAccess = SrvOpen->DesiredAccess;
6996 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
6997 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
6998 DeleteAccess = (DesiredAccess & DELETE) != 0;
6999
7000 /* In that case, update it */
7001 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
7002 {
7003 BOOLEAN SharedRead;
7004 BOOLEAN SharedWrite;
7005 BOOLEAN SharedDelete;
7006 ULONG DesiredShareAccess;
7007 PSHARE_ACCESS ShareAccess;
7008
7009 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
7010 DesiredShareAccess = SrvOpen->ShareAccess;
7011
7012 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
7013 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
7014 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
7015
7016 ShareAccess->OpenCount++;
7017
7018 ShareAccess->Readers += ReadAccess;
7019 ShareAccess->Writers += WriteAccess;
7020 ShareAccess->Deleters += DeleteAccess;
7021 ShareAccess->SharedRead += SharedRead;
7022 ShareAccess->SharedWrite += SharedWrite;
7023 ShareAccess->SharedDelete += SharedDelete;
7024 }
7025
7026 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);
7027 }
7028
7029 /*
7030 * @implemented
7031 */
7032 NTSTATUS
7033 RxXXXControlFileCallthru(
7034 PRX_CONTEXT Context)
7035 {
7036 NTSTATUS Status;
7037
7038 PAGED_CODE();
7039
7040 DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
7041
7042 /* No dispatch table? Nothing to dispatch */
7043 if (Context->RxDeviceObject->Dispatch == NULL)
7044 {
7045 Context->pFobx = NULL;
7046 return STATUS_INVALID_DEVICE_REQUEST;
7047 }
7048
7049 /* Init the lowio context */
7050 Status = RxLowIoPopulateFsctlInfo(Context);
7051 if (!NT_SUCCESS(Status))
7052 {
7053 return Status;
7054 }
7055
7056 /* Check whether we're consistent: a length means a buffer */
7057 if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) ||
7058 (Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL))
7059 {
7060 return STATUS_INVALID_PARAMETER;
7061 }
7062
7063 /* Forward the call to the mini-rdr */
7064 DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile);
7065 Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context);
7066 if (Status != STATUS_PENDING)
7067 {
7068 Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn;
7069 }
7070
7071 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information);
7072 return Status;
7073 }