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