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