[RDBSS]
[reactos.git] / reactos / sdk / lib / drivers / rdbsslib / rdbss.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rdbsslib/rdbss.c
23 * PURPOSE: RDBSS library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <limits.h>
32 #include <dfs.h>
33 #include <copysup.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define RX_TOPLEVELCTX_FLAG_FROM_POOL 1
39
40 typedef
41 NTSTATUS
42 (NTAPI *PRX_FSD_DISPATCH) (
43 PRX_CONTEXT Context);
44
45 typedef struct _RX_FSD_DISPATCH_VECTOR
46 {
47 PRX_FSD_DISPATCH CommonRoutine;
48 } RX_FSD_DISPATCH_VECTOR, *PRX_FSD_DISPATCH_VECTOR;
49
50 VOID
51 NTAPI
52 RxAcquireFileForNtCreateSection(
53 PFILE_OBJECT FileObject);
54
55 NTSTATUS
56 NTAPI
57 RxAcquireForCcFlush(
58 PFILE_OBJECT FileObject,
59 PDEVICE_OBJECT DeviceObject);
60
61 VOID
62 RxAddToTopLevelIrpAllocatedContextsList(
63 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
64
65 VOID
66 RxAssert(
67 PVOID Assert,
68 PVOID File,
69 ULONG Line,
70 PVOID Message);
71
72 NTSTATUS
73 NTAPI
74 RxCommonCleanup(
75 PRX_CONTEXT Context);
76
77 NTSTATUS
78 NTAPI
79 RxCommonClose(
80 PRX_CONTEXT Context);
81
82 NTSTATUS
83 NTAPI
84 RxCommonCreate(
85 PRX_CONTEXT Context);
86
87 NTSTATUS
88 NTAPI
89 RxCommonDevFCBCleanup(
90 PRX_CONTEXT Context);
91
92 NTSTATUS
93 NTAPI
94 RxCommonDevFCBClose(
95 PRX_CONTEXT Context);
96
97 NTSTATUS
98 NTAPI
99 RxCommonDevFCBFsCtl(
100 PRX_CONTEXT Context);
101
102 NTSTATUS
103 NTAPI
104 RxCommonDevFCBIoCtl(
105 PRX_CONTEXT Context);
106
107 NTSTATUS
108 NTAPI
109 RxCommonDevFCBQueryVolInfo(
110 PRX_CONTEXT Context);
111
112 NTSTATUS
113 NTAPI
114 RxCommonDeviceControl(
115 PRX_CONTEXT Context);
116
117 NTSTATUS
118 NTAPI
119 RxCommonDirectoryControl(
120 PRX_CONTEXT Context);
121
122 NTSTATUS
123 NTAPI
124 RxCommonDispatchProblem(
125 PRX_CONTEXT Context);
126
127 NTSTATUS
128 NTAPI
129 RxCommonFileSystemControl(
130 PRX_CONTEXT Context);
131
132 NTSTATUS
133 NTAPI
134 RxCommonFlushBuffers(
135 PRX_CONTEXT Context);
136
137 NTSTATUS
138 NTAPI
139 RxCommonLockControl(
140 PRX_CONTEXT Context);
141
142 NTSTATUS
143 NTAPI
144 RxCommonQueryEa(
145 PRX_CONTEXT Context);
146
147 NTSTATUS
148 NTAPI
149 RxCommonQueryInformation(
150 PRX_CONTEXT Context);
151
152 NTSTATUS
153 NTAPI
154 RxCommonQueryQuotaInformation(
155 PRX_CONTEXT Context);
156
157 NTSTATUS
158 NTAPI
159 RxCommonQuerySecurity(
160 PRX_CONTEXT Context);
161
162 NTSTATUS
163 NTAPI
164 RxCommonQueryVolumeInformation(
165 PRX_CONTEXT Context);
166
167 NTSTATUS
168 NTAPI
169 RxCommonRead(
170 PRX_CONTEXT Context);
171
172 NTSTATUS
173 NTAPI
174 RxCommonSetEa(
175 PRX_CONTEXT Context);
176
177 NTSTATUS
178 NTAPI
179 RxCommonSetInformation(
180 PRX_CONTEXT Context);
181
182 NTSTATUS
183 NTAPI
184 RxCommonSetQuotaInformation(
185 PRX_CONTEXT Context);
186
187 NTSTATUS
188 NTAPI
189 RxCommonSetSecurity(
190 PRX_CONTEXT Context);
191
192 NTSTATUS
193 NTAPI
194 RxCommonSetVolumeInformation(
195 PRX_CONTEXT Context);
196
197 NTSTATUS
198 NTAPI
199 RxCommonUnimplemented(
200 PRX_CONTEXT Context);
201
202 NTSTATUS
203 NTAPI
204 RxCommonWrite(
205 PRX_CONTEXT Context);
206
207 VOID
208 RxCopyCreateParameters(
209 IN PRX_CONTEXT RxContext);
210
211 NTSTATUS
212 RxCreateFromNetRoot(
213 PRX_CONTEXT Context,
214 PUNICODE_STRING NetRootName);
215
216 NTSTATUS
217 RxCreateTreeConnect(
218 IN PRX_CONTEXT RxContext);
219
220 BOOLEAN
221 NTAPI
222 RxFastIoCheckIfPossible(
223 PFILE_OBJECT FileObject,
224 PLARGE_INTEGER FileOffset,
225 ULONG Length, BOOLEAN Wait,
226 ULONG LockKey, BOOLEAN CheckForReadOperation,
227 PIO_STATUS_BLOCK IoStatus,
228 PDEVICE_OBJECT DeviceObject);
229
230 BOOLEAN
231 NTAPI
232 RxFastIoDeviceControl(
233 PFILE_OBJECT FileObject,
234 BOOLEAN Wait,
235 PVOID InputBuffer OPTIONAL,
236 ULONG InputBufferLength,
237 PVOID OutputBuffer OPTIONAL,
238 ULONG OutputBufferLength,
239 ULONG IoControlCode,
240 PIO_STATUS_BLOCK IoStatus,
241 PDEVICE_OBJECT DeviceObject);
242
243 BOOLEAN
244 NTAPI
245 RxFastIoRead(
246 PFILE_OBJECT FileObject,
247 PLARGE_INTEGER FileOffset,
248 ULONG Length,
249 BOOLEAN Wait,
250 ULONG LockKey,
251 PVOID Buffer,
252 PIO_STATUS_BLOCK IoStatus,
253 PDEVICE_OBJECT DeviceObject);
254
255 BOOLEAN
256 NTAPI
257 RxFastIoWrite(
258 PFILE_OBJECT FileObject,
259 PLARGE_INTEGER FileOffset,
260 ULONG Length,
261 BOOLEAN Wait,
262 ULONG LockKey,
263 PVOID Buffer,
264 PIO_STATUS_BLOCK IoStatus,
265 PDEVICE_OBJECT DeviceObject);
266
267 NTSTATUS
268 RxFindOrCreateFcb(
269 PRX_CONTEXT RxContext,
270 PUNICODE_STRING NetRootName);
271
272 NTSTATUS
273 RxFirstCanonicalize(
274 PRX_CONTEXT RxContext,
275 PUNICODE_STRING FileName,
276 PUNICODE_STRING CanonicalName,
277 PNET_ROOT_TYPE NetRootType);
278
279 VOID
280 RxFreeCanonicalNameBuffer(
281 PRX_CONTEXT Context);
282
283 VOID
284 NTAPI
285 RxFspDispatch(
286 IN PVOID Context);
287
288 VOID
289 NTAPI
290 RxGetRegistryParameters(
291 IN PUNICODE_STRING RegistryPath);
292
293 NTSTATUS
294 NTAPI
295 RxGetStringRegistryParameter(
296 IN HANDLE KeyHandle,
297 IN PCWSTR KeyName,
298 OUT PUNICODE_STRING OutString,
299 IN PUCHAR Buffer,
300 IN ULONG BufferLength,
301 IN BOOLEAN LogFailure);
302
303 VOID
304 NTAPI
305 RxInitializeDebugSupport(
306 VOID);
307
308 VOID
309 NTAPI
310 RxInitializeDispatchVectors(
311 PDRIVER_OBJECT DriverObject);
312
313 NTSTATUS
314 NTAPI
315 RxInitializeRegistrationStructures(
316 VOID);
317
318 VOID
319 NTAPI
320 RxInitializeTopLevelIrpPackage(
321 VOID);
322
323 VOID
324 NTAPI
325 RxInitUnwind(
326 PDRIVER_OBJECT DriverObject,
327 USHORT State);
328
329 BOOLEAN
330 RxIsThisAnRdbssTopLevelContext(
331 PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
332
333 NTSTATUS
334 NTAPI
335 RxLowIoIoCtlShellCompletion(
336 PRX_CONTEXT RxContext);
337
338 NTSTATUS
339 RxLowIoReadShell(
340 PRX_CONTEXT RxContext);
341
342 NTSTATUS
343 NTAPI
344 RxLowIoReadShellCompletion(
345 PRX_CONTEXT RxContext);
346
347 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 (!AcquiredExclusive)
5668 {
5669 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5670 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5671 TableAcquired = TRUE;
5672 }
5673
5674 /* If FCB table was updated in between, re-attempt a lookup */
5675 if (NetRoot->FcbTable.Version != Version)
5676 {
5677 Fcb = RxFcbTableLookupFcb(&NetRoot->FcbTable, NetRootName);
5678 if (Fcb != NULL && Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
5679 {
5680 Fcb = NULL;
5681 }
5682 }
5683 }
5684
5685 /* Allocate the FCB */
5686 _SEH2_TRY
5687 {
5688 if (Fcb == NULL)
5689 {
5690 Fcb = RxCreateNetFcb(RxContext, VNetRoot, NetRootName);
5691 if (Fcb == NULL)
5692 {
5693 Status = STATUS_INSUFFICIENT_RESOURCES;
5694 }
5695 else
5696 {
5697 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5698 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5699 }
5700 }
5701 }
5702 _SEH2_FINALLY
5703 {
5704 if (_SEH2_AbnormalTermination())
5705 {
5706 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5707 TableAcquired = FALSE;
5708
5709 if (Fcb != NULL)
5710 {
5711 RxTransitionNetFcb(Fcb, Condition_Bad);
5712
5713 ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
5714 if (RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE) != 0)
5715 {
5716 ExReleaseResourceLite(Fcb->Header.Resource);
5717 }
5718 }
5719 }
5720 }
5721 _SEH2_END;
5722
5723 if (TableAcquired)
5724 {
5725 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5726 }
5727
5728 if (!NT_SUCCESS(Status))
5729 {
5730 return Status;
5731 }
5732
5733 RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
5734 DPRINT("FCB %p is in condition %lx\n", Fcb, Fcb->Condition);
5735
5736 if (!RxContext->Create.FcbAcquired)
5737 {
5738 RxWaitForStableNetFcb(Fcb, RxContext);
5739 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
5740 RxContext->Create.FcbAcquired = NT_SUCCESS(Status);
5741 }
5742
5743 return Status;
5744 }
5745
5746 NTSTATUS
5747 RxFirstCanonicalize(
5748 PRX_CONTEXT RxContext,
5749 PUNICODE_STRING FileName,
5750 PUNICODE_STRING CanonicalName,
5751 PNET_ROOT_TYPE NetRootType)
5752 {
5753 NTSTATUS Status;
5754 NET_ROOT_TYPE Type;
5755 BOOLEAN UncName, PrependString, IsSpecial;
5756 USHORT CanonicalLength;
5757 UNICODE_STRING SessionIdString;
5758 WCHAR SessionIdBuffer[16];
5759
5760 PAGED_CODE();
5761
5762 Type = NET_ROOT_WILD;
5763 PrependString = FALSE;
5764 IsSpecial = FALSE;
5765 UncName = FALSE;
5766 Status = STATUS_SUCCESS;
5767
5768 /* Name has to contain at least \\ */
5769 if (FileName->Length < 2 * sizeof(WCHAR))
5770 {
5771 return STATUS_OBJECT_NAME_INVALID;
5772 }
5773
5774 /* First easy check, is that a path with a name? */
5775 CanonicalLength = FileName->Length;
5776 if (FileName->Length > 5 * sizeof(WCHAR))
5777 {
5778 if (FileName->Buffer[0] == '\\' && FileName->Buffer[1] == ';')
5779 {
5780 if (FileName->Buffer[3] == ':')
5781 {
5782 Type = NET_ROOT_DISK;
5783 }
5784 else
5785 {
5786 Type = NET_ROOT_PRINT;
5787 }
5788 }
5789 }
5790
5791 /* Nope, attempt deeper parsing */
5792 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR && FileName->Buffer[1] != ';')
5793 {
5794 ULONG SessionId;
5795 PWSTR FirstSlash, EndOfString;
5796
5797 SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME);
5798 UncName = TRUE;
5799
5800 /* The lack of drive letter will be replaced by session ID */
5801 SessionId = RxGetSessionId(RxContext->CurrentIrpSp);
5802 RtlInitEmptyUnicodeString(&SessionIdString, SessionIdBuffer, sizeof(SessionIdBuffer));
5803 RtlIntegerToUnicodeString(SessionId, 10, &SessionIdString);
5804
5805 EndOfString = Add2Ptr(FileName->Buffer, FileName->Length);
5806 for (FirstSlash = &FileName->Buffer[1]; FirstSlash != EndOfString; ++FirstSlash)
5807 {
5808 if (*FirstSlash == OBJ_NAME_PATH_SEPARATOR)
5809 {
5810 break;
5811 }
5812 }
5813
5814 if (EndOfString - FirstSlash <= sizeof(WCHAR))
5815 {
5816 Status = STATUS_OBJECT_NAME_INVALID;
5817 }
5818 else
5819 {
5820 UNIMPLEMENTED;
5821 DPRINT1("WARNING: Assuming not special + disk!\n");
5822 Type = NET_ROOT_DISK;
5823 Status = STATUS_SUCCESS;
5824 //Status = STATUS_NOT_IMPLEMENTED;
5825 /* Should be check against IPC, mailslot, and so on */
5826 }
5827 }
5828
5829 /* Update net root type with our deduced one */
5830 *NetRootType = Type;
5831 DPRINT("Returning type: %x\n", Type);
5832
5833 if (!NT_SUCCESS(Status))
5834 {
5835 return Status;
5836 }
5837
5838 /* Do we have to prepend session ID? */
5839 if (UncName)
5840 {
5841 if (!IsSpecial)
5842 {
5843 PrependString = TRUE;
5844 CanonicalLength += SessionIdString.Length + 3 * sizeof(WCHAR);
5845 }
5846 }
5847
5848 /* If not UNC path, we should preprend stuff */
5849 if (!PrependString && !IsSpecial && FileName->Buffer[0] != '\\')
5850 {
5851 return STATUS_OBJECT_PATH_INVALID;
5852 }
5853
5854 /* Allocate the buffer */
5855 Status = RxAllocateCanonicalNameBuffer(RxContext, CanonicalName, CanonicalLength);
5856 if (!NT_SUCCESS(Status))
5857 {
5858 return Status;
5859 }
5860
5861 /* We don't support that case, we always return disk */
5862 if (IsSpecial)
5863 {
5864 ASSERT(CanonicalName->Length == CanonicalLength);
5865 UNIMPLEMENTED;
5866 Status = STATUS_NOT_IMPLEMENTED;
5867 }
5868 else
5869 {
5870 /* If we have to prepend, go ahead */
5871 if (PrependString)
5872 {
5873 CanonicalName->Buffer[0] = '\\';
5874 CanonicalName->Buffer[1] = ';';
5875 CanonicalName->Buffer[2] = ':';
5876 CanonicalName->Length = 3 * sizeof(WCHAR);
5877 RtlAppendUnicodeStringToString(CanonicalName, &SessionIdString);
5878 RtlAppendUnicodeStringToString(CanonicalName, FileName);
5879
5880 DPRINT1("CanonicalName: %wZ\n", CanonicalName);
5881 }
5882 /* Otherwise, that's a simple copy */
5883 else
5884 {
5885 RtlCopyUnicodeString(CanonicalName, FileName);
5886 }
5887 }
5888
5889 return Status;
5890 }
5891
5892 /*
5893 * @implemented
5894 */
5895 VOID
5896 RxFreeCanonicalNameBuffer(
5897 PRX_CONTEXT Context)
5898 {
5899 /* These two buffers are always the same */
5900 ASSERT(Context->Create.CanonicalNameBuffer == Context->AlsoCanonicalNameBuffer);
5901
5902 if (Context->Create.CanonicalNameBuffer != NULL)
5903 {
5904 RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
5905 Context->Create.CanonicalNameBuffer = NULL;
5906 Context->AlsoCanonicalNameBuffer = NULL;
5907 }
5908
5909 ASSERT(Context->AlsoCanonicalNameBuffer == NULL);
5910 }
5911
5912 NTSTATUS
5913 RxFsdCommonDispatch(
5914 PRX_FSD_DISPATCH_VECTOR DispatchVector,
5915 UCHAR MajorFunction,
5916 PIO_STACK_LOCATION Stack,
5917 PFILE_OBJECT FileObject,
5918 PIRP Irp,
5919 PRDBSS_DEVICE_OBJECT RxDeviceObject)
5920 {
5921 KIRQL OldIrql;
5922 NTSTATUS Status;
5923 PRX_CONTEXT Context;
5924 UCHAR MinorFunction;
5925 PFILE_OBJECT StackFileObject;
5926 PRX_FSD_DISPATCH DispatchFunc;
5927 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
5928 BOOLEAN TopLevel, Closing, PassToDriver, SetCancelRoutine, PostRequest, CanWait;
5929
5930 Status = STATUS_SUCCESS;
5931
5932 DPRINT("RxFsdCommonDispatch(%p, %d, %p, %p, %p, %p)\n", DispatchVector, MajorFunction, Stack, FileObject, Irp, RxDeviceObject);
5933
5934 FsRtlEnterFileSystem();
5935
5936 TopLevel = RxTryToBecomeTheTopLevelIrp(&TopLevelContext, Irp, RxDeviceObject, FALSE);
5937
5938 _SEH2_TRY
5939 {
5940 CanWait = TRUE;
5941 Closing = FALSE;
5942 PostRequest = FALSE;
5943 SetCancelRoutine = TRUE;
5944 MinorFunction = Stack->MinorFunction;
5945 /* Can we wait? */
5946 switch (MajorFunction)
5947 {
5948 case IRP_MJ_FILE_SYSTEM_CONTROL:
5949 if (FileObject != NULL)
5950 {
5951 CanWait = IoIsOperationSynchronous(Irp);
5952 }
5953 else
5954 {
5955 CanWait = TRUE;
5956 }
5957 break;
5958
5959 case IRP_MJ_READ:
5960 case IRP_MJ_WRITE:
5961 case IRP_MJ_QUERY_INFORMATION:
5962 case IRP_MJ_SET_INFORMATION:
5963 case IRP_MJ_QUERY_EA:
5964 case IRP_MJ_SET_EA:
5965 case IRP_MJ_FLUSH_BUFFERS:
5966 case IRP_MJ_QUERY_VOLUME_INFORMATION:
5967 case IRP_MJ_SET_VOLUME_INFORMATION:
5968 case IRP_MJ_DIRECTORY_CONTROL:
5969 case IRP_MJ_DEVICE_CONTROL:
5970 case IRP_MJ_LOCK_CONTROL:
5971 case IRP_MJ_QUERY_SECURITY:
5972 case IRP_MJ_SET_SECURITY:
5973 CanWait = IoIsOperationSynchronous(Irp);
5974 break;
5975
5976 case IRP_MJ_CLOSE:
5977 case IRP_MJ_CLEANUP:
5978 Closing = TRUE;
5979 SetCancelRoutine = FALSE;
5980 break;
5981
5982 default:
5983 break;
5984 }
5985
5986 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
5987 /* Should we stop it right now, or mini-rdr deserves to know? */
5988 PassToDriver = TRUE;
5989 if (RxGetRdbssState(RxDeviceObject) != RDBSS_STARTABLE)
5990 {
5991 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && !Closing)
5992 {
5993 PassToDriver = FALSE;
5994 Status = STATUS_REDIRECTOR_NOT_STARTED;
5995 DPRINT1("Not started!\n");
5996 }
5997 }
5998 else
5999 {
6000 if (DispatchVector != RxDeviceFCBVector && (FileObject->FileName.Length != 0 || FileObject->RelatedFileObject != NULL))
6001 {
6002 PassToDriver = FALSE;
6003 Status = STATUS_REDIRECTOR_NOT_STARTED;
6004 DPRINT1("Not started!\n");
6005 }
6006 }
6007 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
6008
6009 StackFileObject = Stack->FileObject;
6010 /* Make sure we don't deal with orphaned stuff */
6011 if (StackFileObject != NULL && StackFileObject->FsContext != NULL)
6012 {
6013 if (StackFileObject->FsContext2 != UIntToPtr(DFS_OPEN_CONTEXT) &&
6014 StackFileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT) &&
6015 StackFileObject->FsContext != &RxDeviceFCB)
6016 {
6017 PFCB Fcb;
6018 PFOBX Fobx;
6019
6020 Fcb = StackFileObject->FsContext;
6021 Fobx = StackFileObject->FsContext2;
6022
6023 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED) ||
6024 BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
6025 {
6026 if (Closing)
6027 {
6028 PassToDriver = TRUE;
6029 }
6030 else
6031 {
6032 PassToDriver = FALSE;
6033 Status = STATUS_UNEXPECTED_NETWORK_ERROR;
6034 DPRINT1("Operation on orphaned FCB: %p\n", Fcb);
6035 }
6036 }
6037 }
6038 }
6039
6040 /* Did we receive a close request whereas we're stopping? */
6041 if (RxGetRdbssState(RxDeviceObject) == RDBSS_STOP_IN_PROGRESS && Closing)
6042 {
6043 PFCB Fcb;
6044
6045 Fcb = StackFileObject->FsContext;
6046
6047 DPRINT1("Close received after stop\n");
6048 DPRINT1("Irp: %p %d:%d FO: %p FCB: %p\n",
6049 Irp, Stack->MajorFunction, Stack->MinorFunction, StackFileObject, Fcb);
6050
6051 if (Fcb != NULL && Fcb != &RxDeviceFCB &&
6052 NodeTypeIsFcb(Fcb))
6053 {
6054 DPRINT1("OpenCount: %ld, UncleanCount: %ld, Name: %wZ\n",
6055 Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path);
6056 }
6057 }
6058
6059 /* Should we stop the whole thing now? */
6060 if (!PassToDriver)
6061 {
6062 if (MajorFunction != IRP_MJ_DIRECTORY_CONTROL || MinorFunction != IRP_MN_REMOVE_DEVICE)
6063 {
6064 IoMarkIrpPending(Irp);
6065 Irp->IoStatus.Status = Status;
6066 Irp->IoStatus.Information = 0;
6067 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6068 Status = STATUS_PENDING;
6069 }
6070 else
6071 {
6072 Irp->IoStatus.Status = Status;
6073 Irp->IoStatus.Information = 0;
6074 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6075 }
6076
6077 _SEH2_LEAVE;
6078 }
6079
6080 /* No? Allocate a context to deal with the mini-rdr */
6081 Context = RxCreateRxContext(Irp, RxDeviceObject, (CanWait ? RX_CONTEXT_FLAG_WAIT : 0));
6082 if (Context == NULL)
6083 {
6084 Status = STATUS_INSUFFICIENT_RESOURCES;
6085 RxCompleteRequest_Real(RxNull, Irp, STATUS_INSUFFICIENT_RESOURCES);
6086 _SEH2_LEAVE;
6087 }
6088
6089 /* Set cancel routine if required */
6090 if (SetCancelRoutine)
6091 {
6092 IoAcquireCancelSpinLock(&OldIrql);
6093 IoSetCancelRoutine(Irp, RxCancelRoutine);
6094 }
6095 else
6096 {
6097 IoAcquireCancelSpinLock(&OldIrql);
6098 IoSetCancelRoutine(Irp, NULL);
6099 }
6100 IoReleaseCancelSpinLock(OldIrql);
6101
6102 ASSERT(MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6103
6104 Irp->IoStatus.Status = STATUS_SUCCESS;
6105 Irp->IoStatus.Information = 0;
6106 /* Get the dispatch routine */
6107 DispatchFunc = DispatchVector[MajorFunction].CommonRoutine;
6108
6109 if (MajorFunction == IRP_MJ_READ || MajorFunction == IRP_MJ_WRITE)
6110 {
6111 /* Handle the complete MDL case */
6112 if (BooleanFlagOn(MinorFunction, IRP_MN_COMPLETE))
6113 {
6114 DispatchFunc = RxCompleteMdl;
6115 }
6116 else
6117 {
6118 /* Do we have to post request? */
6119 if (BooleanFlagOn(MinorFunction, IRP_MN_DPC))
6120 {
6121 PostRequest = TRUE;
6122 }
6123 else
6124 {
6125 /* Our read function needs stack, make sure we won't overflow,
6126 * otherwise, post the request
6127 */
6128 if (MajorFunction == IRP_MJ_READ)
6129 {
6130 if (IoGetRemainingStackSize() < 0xE00)
6131 {
6132 Context->PendingReturned = TRUE;
6133 Status = RxPostStackOverflowRead(Context);
6134 if (Status != STATUS_PENDING)
6135 {
6136 Context->PendingReturned = FALSE;
6137 RxCompleteAsynchronousRequest(Context, Status);
6138 }
6139
6140 _SEH2_LEAVE;
6141 }
6142 }
6143 }
6144 }
6145 }
6146
6147 Context->ResumeRoutine = DispatchFunc;
6148 /* There's a dispatch routine? Time to dispatch! */
6149 if (DispatchFunc != NULL)
6150 {
6151 Context->PendingReturned = TRUE;
6152 if (PostRequest)
6153 {
6154 Status = RxFsdPostRequest(Context);
6155 }
6156 else
6157 {
6158 /* Retry as long as we have */
6159 do
6160 {
6161 Status = DispatchFunc(Context);
6162 }
6163 while (Status == STATUS_RETRY);
6164
6165 if (Status == STATUS_PENDING)
6166 {
6167 _SEH2_LEAVE;
6168 }
6169
6170 /* Sanity check: did someone mess with our context? */
6171 if (Context->CurrentIrp != Irp || Context->CurrentIrpSp != Stack ||
6172 Context->MajorFunction != MajorFunction || Stack->MinorFunction != MinorFunction)
6173 {
6174 DPRINT1("RX_CONTEXT %p has been contaminated!\n", Context);
6175 DPRINT1("->CurrentIrp %p %p\n", Context->CurrentIrp, Irp);
6176 DPRINT1("->CurrentIrpSp %p %p\n", Context->CurrentIrpSp, Stack);
6177 DPRINT1("->MajorFunction %d %d\n", Context->MajorFunction, MajorFunction);
6178 DPRINT1("->MinorFunction %d %d\n", Context->MinorFunction, MinorFunction);
6179 }
6180 Context->PendingReturned = FALSE;
6181 Status = RxCompleteAsynchronousRequest(Context, Status);
6182 }
6183 }
6184 else
6185 {
6186 Status = STATUS_NOT_IMPLEMENTED;
6187 }
6188 }
6189 _SEH2_FINALLY
6190 {
6191 if (TopLevel)
6192 {
6193 RxUnwindTopLevelIrp(&TopLevelContext);
6194 }
6195
6196 FsRtlExitFileSystem();
6197 }
6198 _SEH2_END;
6199
6200 DPRINT("RxFsdDispatch, Status: %lx\n", Status);
6201 return Status;
6202 }
6203
6204 /*
6205 * @implemented
6206 */
6207 NTSTATUS
6208 NTAPI
6209 RxFsdDispatch(
6210 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
6211 IN PIRP Irp)
6212 {
6213 PFCB Fcb;
6214 PIO_STACK_LOCATION Stack;
6215 PRX_FSD_DISPATCH_VECTOR DispatchVector;
6216
6217 PAGED_CODE();
6218
6219 DPRINT("RxFsdDispatch(%p, %p)\n", RxDeviceObject, Irp);
6220
6221 Stack = IoGetCurrentIrpStackLocation(Irp);
6222
6223 /* Dispatch easy case */
6224 if (Stack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
6225 {
6226 return RxSystemControl(RxDeviceObject, Irp);
6227 }
6228
6229 /* Bail out broken cases */
6230 if (Stack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ||
6231 Stack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE)
6232 {
6233 IoMarkIrpPending(Irp);
6234 Irp->IoStatus.Information = 0;
6235 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
6236 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6237 return STATUS_PENDING;
6238 }
6239
6240 /* Immediately handle create */
6241 if (Stack->MajorFunction == IRP_MJ_CREATE)
6242 {
6243 return RxFsdCommonDispatch(&RxFsdDispatchVector[0], Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6244 }
6245
6246 /* If not a creation, we must have at least a FO with a FCB */
6247 if (Stack->FileObject == NULL || Stack->FileObject->FsContext == NULL)
6248 {
6249 IoMarkIrpPending(Irp);
6250 Irp->IoStatus.Information = 0;
6251 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6252 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6253 return STATUS_PENDING;
6254 }
6255
6256 /* Set the dispatch vector if required */
6257 Fcb = Stack->FileObject->FsContext;
6258 if (!NodeTypeIsFcb(Fcb) || Fcb->PrivateDispatchVector == NULL)
6259 {
6260 DispatchVector = &RxFsdDispatchVector[0];
6261 }
6262 else
6263 {
6264 DispatchVector = Fcb->PrivateDispatchVector;
6265 }
6266
6267 /* Device cannot accept such requests */
6268 if (RxDeviceObject == RxFileSystemDeviceObject)
6269 {
6270 IoMarkIrpPending(Irp);
6271 Irp->IoStatus.Information = 0;
6272 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6273 IoCompleteRequest(Irp, IO_NO_INCREMENT);
6274 return STATUS_PENDING;
6275 }
6276
6277 /* Dispatch for real! */
6278 return RxFsdCommonDispatch(DispatchVector, Stack->MajorFunction, Stack, Stack->FileObject, Irp, RxDeviceObject);
6279 }
6280
6281 /*
6282 * @implemented
6283 */
6284 NTSTATUS
6285 RxFsdPostRequest(
6286 IN PRX_CONTEXT RxContext)
6287 {
6288 /* Initialize posting if required */
6289 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
6290 {
6291 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
6292 }
6293
6294 DPRINT("Posting MN: %d, Ctxt: %p, IRP: %p, Thrd: %lx #%lx\n",
6295 RxContext->MinorFunction, RxContext,
6296 RxContext->CurrentIrp, RxContext->LastExecutionThread,
6297 RxContext->SerialNumber);
6298
6299 RxAddToWorkque(RxContext, RxContext->CurrentIrp);
6300 return STATUS_PENDING;
6301 }
6302
6303 /*
6304 * @implemented
6305 */
6306 VOID
6307 NTAPI
6308 RxFspDispatch(
6309 IN PVOID Context)
6310 {
6311 KIRQL EntryIrql;
6312 WORK_QUEUE_TYPE Queue;
6313 PRDBSS_DEVICE_OBJECT VolumeDO;
6314 PRX_CONTEXT RxContext, EntryContext;
6315
6316 PAGED_CODE();
6317
6318 RxContext = Context;
6319 EntryContext = Context;
6320 /* Save IRQL at entry for later checking */
6321 EntryIrql = KeGetCurrentIrql();
6322
6323 /* No FO, deal with device */
6324 if (RxContext->CurrentIrpSp->FileObject != NULL)
6325 {
6326 VolumeDO = RxFileSystemDeviceObject;
6327 }
6328 else
6329 {
6330 VolumeDO = NULL;
6331 }
6332
6333 /* Which queue to used for delayed? */
6334 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE))
6335 {
6336 Queue = DelayedWorkQueue;
6337 }
6338 else
6339 {
6340 ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
6341 Queue = CriticalWorkQueue;
6342 }
6343
6344 do
6345 {
6346 PIRP Irp;
6347 NTSTATUS Status;
6348 BOOLEAN RecursiveCall;
6349 RX_TOPLEVELIRP_CONTEXT TopLevelContext;
6350
6351 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
6352 ASSERT(!RxContext->PostRequest);
6353
6354 RxContext->LastExecutionThread = PsGetCurrentThread();
6355 SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
6356
6357 DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx", RxContext->MinorFunction,
6358 RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
6359 RxContext->SerialNumber);
6360
6361 Irp = RxContext->CurrentIrp;
6362
6363 FsRtlEnterFileSystem();
6364
6365 RecursiveCall = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
6366 RxTryToBecomeTheTopLevelIrp(&TopLevelContext,
6367 (RecursiveCall ? (PIRP)FSRTL_FSP_TOP_LEVEL_IRP : RxContext->CurrentIrp),
6368 RxContext->RxDeviceObject, TRUE);
6369
6370 ASSERT(RxContext->ResumeRoutine != NULL);
6371
6372 if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_DPC) && Irp->Tail.Overlay.Thread == NULL)
6373 {
6374 ASSERT((RxContext->MajorFunction == IRP_MJ_WRITE) || (RxContext->MajorFunction == IRP_MJ_READ));
6375 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
6376 }
6377
6378 /* Call the resume routine */
6379 do
6380 {
6381 BOOLEAN NoComplete;
6382
6383 NoComplete = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
6384
6385 Status = RxContext->ResumeRoutine(RxContext);
6386 if (!NoComplete && Status != STATUS_PENDING)
6387 {
6388 if (Status != STATUS_RETRY)
6389 {
6390 Status = RxCompleteRequest(RxContext, Status);
6391 }
6392 }
6393 }
6394 while (Status == STATUS_RETRY);
6395
6396 RxUnwindTopLevelIrp(&TopLevelContext);
6397 FsRtlExitFileSystem();
6398
6399 if (VolumeDO != NULL)
6400 {
6401 RxContext = RxRemoveOverflowEntry(VolumeDO, Queue);
6402 }
6403 else
6404 {
6405 RxContext = NULL;
6406 }
6407 } while (RxContext != NULL);
6408
6409 /* Did we mess with IRQL? */
6410 if (KeGetCurrentIrql() >= APC_LEVEL)
6411 {
6412 DPRINT1("High IRQL for Ctxt %p, on entry: %x\n", EntryContext, EntryIrql);
6413 }
6414 }
6415
6416 /*
6417 * @implemented
6418 */
6419 ULONG
6420 RxGetNetworkProviderPriority(
6421 PUNICODE_STRING DeviceName)
6422 {
6423 PAGED_CODE();
6424 return 1;
6425 }
6426
6427 /*
6428 * @implemented
6429 */
6430 VOID
6431 NTAPI
6432 RxGetRegistryParameters(
6433 IN PUNICODE_STRING RegistryPath)
6434 {
6435 USHORT i;
6436 NTSTATUS Status;
6437 UCHAR Buffer[0x400];
6438 HANDLE DriverHandle, KeyHandle;
6439 UNICODE_STRING KeyName, OutString;
6440 OBJECT_ATTRIBUTES ObjectAttributes;
6441
6442 PAGED_CODE();
6443
6444 InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
6445 Status = ZwOpenKey(&DriverHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6446 if (!NT_SUCCESS(Status))
6447 {
6448 return;
6449 }
6450
6451 RtlInitUnicodeString(&KeyName, L"Parameters");
6452 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DriverHandle, FALSE);
6453 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
6454 if (NT_SUCCESS(Status))
6455 {
6456 /* The only parameter we deal with is InitialDebugString */
6457 RxGetStringRegistryParameter(KeyHandle, L"InitialDebugString", &OutString, Buffer, sizeof(Buffer), 0);
6458 if (OutString.Length != 0 && OutString.Length < 0x140)
6459 {
6460 PWSTR Read;
6461 PSTR Write;
6462
6463 Read = OutString.Buffer;
6464 Write = (PSTR)OutString.Buffer;
6465 for (i = 0; i < OutString.Length; ++i)
6466 {
6467 *Read = *Write;
6468 ++Write;
6469 *Write = ANSI_NULL;
6470 ++Read;
6471 }
6472
6473 /* Which is a string we'll just write out */
6474 DPRINT("InitialDebugString read from registry: '%s'\n", OutString.Buffer);
6475 RxDebugControlCommand((PSTR)OutString.Buffer);
6476 }
6477
6478 ZwClose(KeyHandle);
6479 }
6480
6481 ZwClose(DriverHandle);
6482 }
6483
6484 /*
6485 * @implemented
6486 */
6487 ULONG
6488 RxGetSessionId(
6489 IN PIO_STACK_LOCATION IrpSp)
6490 {
6491 ULONG SessionId;
6492 PACCESS_TOKEN Token;
6493 PIO_SECURITY_CONTEXT SecurityContext;
6494
6495 PAGED_CODE();
6496
6497 /* If that's not a prefix claim, not an open request, session id will be 0 */
6498 if (IrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL || IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_REDIR_QUERY_PATH)
6499 {
6500 if (IrpSp->MajorFunction != IRP_MJ_CREATE || IrpSp->Parameters.Create.SecurityContext == NULL)
6501 {
6502 return 0;
6503 }
6504
6505 SecurityContext = IrpSp->Parameters.Create.SecurityContext;
6506 }
6507 else
6508 {
6509 SecurityContext = ((PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->SecurityContext;
6510 }
6511
6512 /* Query the session id */
6513 Token = SeQuerySubjectContextToken(&SecurityContext->AccessState->SubjectSecurityContext);
6514 SeQuerySessionIdToken(Token, &SessionId);
6515
6516 return SessionId;
6517 }
6518
6519 /*
6520 * @implemented
6521 */
6522 NTSTATUS
6523 NTAPI
6524 RxGetStringRegistryParameter(
6525 IN HANDLE KeyHandle,
6526 IN PCWSTR KeyName,
6527 OUT PUNICODE_STRING OutString,
6528 IN PUCHAR Buffer,
6529 IN ULONG BufferLength,
6530 IN BOOLEAN LogFailure)
6531 {
6532 NTSTATUS Status;
6533 ULONG ResultLength;
6534 UNICODE_STRING KeyString;
6535
6536 PAGED_CODE();
6537
6538 RtlInitUnicodeString(&KeyString, KeyName);
6539 Status = ZwQueryValueKey(KeyHandle, &KeyString, KeyValuePartialInformation, Buffer, BufferLength, &ResultLength);
6540 OutString->Length = 0;
6541 OutString->Buffer = 0;
6542 if (!NT_SUCCESS(Status))
6543 {
6544 if (LogFailure)
6545 {
6546 RxLogFailure(RxFileSystemDeviceObject, NULL, 0x80000BD3, Status);
6547 }
6548
6549 return Status;
6550 }
6551
6552 OutString->Buffer = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
6553 OutString->Length = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->DataLength - sizeof(UNICODE_NULL);
6554 OutString->MaximumLength = OutString->Length;
6555
6556 return STATUS_SUCCESS;
6557 }
6558
6559 /*
6560 * @implemented
6561 */
6562 PRDBSS_DEVICE_OBJECT
6563 RxGetTopDeviceObjectIfRdbssIrp(
6564 VOID)
6565 {
6566 PIRP TopLevelIrp;
6567 PRDBSS_DEVICE_OBJECT TopDevice = NULL;
6568
6569 TopLevelIrp = IoGetTopLevelIrp();
6570 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6571 {
6572 TopDevice = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->RxDeviceObject;
6573 }
6574
6575 return TopDevice;
6576 }
6577
6578 /*
6579 * @implemented
6580 */
6581 PIRP
6582 RxGetTopIrpIfRdbssIrp(
6583 VOID)
6584 {
6585 PIRP Irp = NULL;
6586 PRX_TOPLEVELIRP_CONTEXT TopLevel;
6587
6588 TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
6589 if (RxIsThisAnRdbssTopLevelContext(TopLevel))
6590 {
6591 Irp = TopLevel->Irp;
6592 }
6593
6594 return Irp;
6595 }
6596
6597 /*
6598 * @implemented
6599 */
6600 LUID
6601 RxGetUid(
6602 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext)
6603 {
6604 LUID Luid;
6605 PACCESS_TOKEN Token;
6606
6607 PAGED_CODE();
6608
6609 Token = SeQuerySubjectContextToken(SubjectSecurityContext);
6610 SeQueryAuthenticationIdToken(Token, &Luid);
6611
6612 return Luid;
6613 }
6614
6615 VOID
6616 NTAPI
6617 RxIndicateChangeOfBufferingStateForSrvOpen(
6618 PMRX_SRV_CALL SrvCall,
6619 PMRX_SRV_OPEN SrvOpen,
6620 PVOID SrvOpenKey,
6621 PVOID Context)
6622 {
6623 UNIMPLEMENTED;
6624 }
6625
6626 VOID
6627 NTAPI
6628 RxInitializeDebugSupport(
6629 VOID)
6630 {
6631 UNIMPLEMENTED;
6632 }
6633
6634 /*
6635 * @implemented
6636 */
6637 VOID
6638 NTAPI
6639 RxInitializeDispatchVectors(
6640 PDRIVER_OBJECT DriverObject)
6641 {
6642 USHORT i;
6643
6644 PAGED_CODE();
6645
6646 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
6647 {
6648 DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
6649 }
6650
6651 RxDeviceFCB.PrivateDispatchVector = RxDeviceFCBVector;
6652 ASSERT(RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6653 ASSERT(RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL);
6654
6655 DriverObject->FastIoDispatch = &RxFastIoDispatch;
6656 RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(RxFastIoDispatch);
6657 RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
6658 RxFastIoDispatch.FastIoRead = RxFastIoRead;
6659 RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
6660 RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
6661 RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
6662 RxFastIoDispatch.FastIoLock = NULL;
6663 RxFastIoDispatch.FastIoUnlockSingle = NULL;
6664 RxFastIoDispatch.FastIoUnlockAll = NULL;
6665 RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
6666 RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
6667 RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
6668 RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
6669 RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
6670 RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
6671
6672 RxInitializeTopLevelIrpPackage();
6673
6674 RxData.CacheManagerCallbacks.AcquireForLazyWrite = RxAcquireFcbForLazyWrite;
6675 RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = RxReleaseFcbFromLazyWrite;
6676 RxData.CacheManagerCallbacks.AcquireForReadAhead = RxAcquireFcbForReadAhead;
6677 RxData.CacheManagerCallbacks.ReleaseFromReadAhead = RxReleaseFcbFromReadAhead;
6678
6679 RxData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = RxNoOpAcquire;
6680 RxData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = RxNoOpRelease;
6681 RxData.CacheManagerNoOpCallbacks.AcquireForReadAhead = RxNoOpAcquire;
6682 RxData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = RxNoOpRelease;
6683 }
6684
6685 NTSTATUS
6686 NTAPI
6687 RxInitializeLog(
6688 VOID)
6689 {
6690 UNIMPLEMENTED;
6691 return STATUS_NOT_IMPLEMENTED;
6692 }
6693
6694 /*
6695 * @implemented
6696 */
6697 VOID
6698 RxInitializeMinirdrDispatchTable(
6699 IN PDRIVER_OBJECT DriverObject)
6700 {
6701 PAGED_CODE();
6702 }
6703
6704 /*
6705 * @implemented
6706 */
6707 NTSTATUS
6708 NTAPI
6709 RxInitializeRegistrationStructures(
6710 VOID)
6711 {
6712 PAGED_CODE();
6713
6714 ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
6715 RxData.NumberOfMinirdrsRegistered = 0;
6716 RxData.NumberOfMinirdrsStarted = 0;
6717 InitializeListHead(&RxData.RegisteredMiniRdrs);
6718
6719 return STATUS_SUCCESS;
6720 }
6721
6722 /*
6723 * @implemented
6724 */
6725 VOID
6726 NTAPI
6727 RxInitializeTopLevelIrpPackage(
6728 VOID)
6729 {
6730 KeInitializeSpinLock(&TopLevelIrpSpinLock);
6731 InitializeListHead(&TopLevelIrpAllocatedContextsList);
6732 }
6733
6734 VOID
6735 NTAPI
6736 RxInitUnwind(
6737 PDRIVER_OBJECT DriverObject,
6738 USHORT State)
6739 {
6740 UNIMPLEMENTED;
6741 }
6742
6743 /*
6744 * @implemented
6745 */
6746 BOOLEAN
6747 RxIsMemberOfTopLevelIrpAllocatedContextsList(
6748 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6749 {
6750 KIRQL OldIrql;
6751 PLIST_ENTRY NextEntry;
6752 BOOLEAN Found = FALSE;
6753 PRX_TOPLEVELIRP_CONTEXT ListContext;
6754
6755 /* Browse all the allocated TLC to find ours */
6756 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
6757 for (NextEntry = TopLevelIrpAllocatedContextsList.Flink;
6758 NextEntry != &TopLevelIrpAllocatedContextsList;
6759 NextEntry = NextEntry->Flink)
6760 {
6761 ListContext = CONTAINING_RECORD(NextEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry);
6762 ASSERT(ListContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
6763 ASSERT(BooleanFlagOn(ListContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
6764
6765 /* Found! */
6766 if (ListContext == TopLevelContext)
6767 {
6768 Found = TRUE;
6769 break;
6770 }
6771 }
6772 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
6773
6774 return Found;
6775 }
6776
6777 /*
6778 * @implemented
6779 */
6780 BOOLEAN
6781 RxIsOkToPurgeFcb(
6782 PFCB Fcb)
6783 {
6784 PLIST_ENTRY Entry;
6785
6786 /* No associated SRV_OPEN, it's OK to purge */
6787 if (IsListEmpty(&Fcb->SrvOpenList))
6788 {
6789 return TRUE;
6790 }
6791
6792 /* Only allow to purge if all the associated SRV_OPEN
6793 * - have no outstanding opens ongoing
6794 * - have only read attribute set
6795 */
6796 for (Entry = Fcb->SrvOpenList.Flink;
6797 Entry != &Fcb->SrvOpenList;
6798 Entry = Entry->Flink)
6799 {
6800 PSRV_OPEN SrvOpen;
6801
6802 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
6803
6804 /* Failing previous needs, don't allow purge */
6805 if (SrvOpen->UncleanFobxCount != 0 ||
6806 (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
6807 {
6808 return FALSE;
6809 }
6810 }
6811
6812 /* All correct, allow purge */
6813 return TRUE;
6814 }
6815
6816 /*
6817 * @implemented
6818 */
6819 BOOLEAN
6820 RxIsThisAnRdbssTopLevelContext(
6821 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
6822 {
6823 ULONG_PTR StackTop, StackBottom;
6824
6825 /* Bail out for flags */
6826 if ((ULONG_PTR)TopLevelContext <= FSRTL_FAST_IO_TOP_LEVEL_IRP)
6827 {
6828 return FALSE;
6829 }
6830
6831 /* Is our provided TLC allocated on stack? */
6832 IoGetStackLimits(&StackTop, &StackBottom);
6833 if ((ULONG_PTR)TopLevelContext <= StackBottom - sizeof(RX_TOPLEVELIRP_CONTEXT) &&
6834 (ULONG_PTR)TopLevelContext >= StackTop)
6835 {
6836 /* Yes, so check whether it's really a TLC by checking alignement & signature */
6837 if (!BooleanFlagOn((ULONG_PTR)TopLevelContext, 0x3) && TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)
6838 {
6839 return TRUE;
6840 }
6841
6842 return FALSE;
6843 }
6844
6845 /* No, use the helper function */
6846 return RxIsMemberOfTopLevelIrpAllocatedContextsList(TopLevelContext);
6847 }
6848
6849 /*
6850 * @implemented
6851 */
6852 BOOLEAN
6853 RxIsThisTheTopLevelIrp(
6854 IN PIRP Irp)
6855 {
6856 PIRP TopLevelIrp;
6857
6858 /* When we put oursleves as top level, we set TLC as 'IRP', so look for it */
6859 TopLevelIrp = IoGetTopLevelIrp();
6860 if (RxIsThisAnRdbssTopLevelContext((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp))
6861 {
6862 TopLevelIrp = ((PRX_TOPLEVELIRP_CONTEXT)TopLevelIrp)->Irp;
6863 }
6864
6865 return (TopLevelIrp == Irp);
6866 }
6867
6868 NTSTATUS
6869 NTAPI
6870 RxLockOperationCompletion(
6871 IN PVOID Context,
6872 IN PIRP Irp)
6873 {
6874 UNIMPLEMENTED;
6875 return STATUS_NOT_IMPLEMENTED;
6876 }
6877
6878 /*
6879 * @implemented
6880 */
6881 VOID
6882 NTAPI
6883 RxLogEventDirect(
6884 IN PRDBSS_DEVICE_OBJECT DeviceObject,
6885 IN PUNICODE_STRING OriginatorId,
6886 IN ULONG EventId,
6887 IN NTSTATUS Status,
6888 IN ULONG Line)
6889 {
6890 PUNICODE_STRING Originator = OriginatorId;
6891 LARGE_INTEGER LargeLine;
6892
6893 /* Set optional parameters */
6894 LargeLine.QuadPart = Line;
6895 if (OriginatorId == NULL || OriginatorId->Length == 0)
6896 {
6897 Originator = (PUNICODE_STRING)&unknownId;
6898 }
6899
6900 /* And log */
6901 RxLogEventWithAnnotation(DeviceObject, EventId, Status, &LargeLine, sizeof(LargeLine), Originator, 1);
6902 }
6903
6904 VOID
6905 NTAPI
6906 RxLogEventWithAnnotation(
6907 IN PRDBSS_DEVICE_OBJECT DeviceObject,
6908 IN ULONG EventId,
6909 IN NTSTATUS Status,
6910 IN PVOID DataBuffer,
6911 IN USHORT DataBufferLength,
6912 IN PUNICODE_STRING Annotation,
6913 IN ULONG AnnotationCount)
6914 {
6915 UNIMPLEMENTED;
6916 }
6917
6918 NTSTATUS
6919 NTAPI
6920 RxLowIoCompletion(
6921 PRX_CONTEXT RxContext)
6922 {
6923 UNIMPLEMENTED;
6924 return STATUS_NOT_IMPLEMENTED;
6925 }
6926
6927 /*
6928 * @implemented
6929 */
6930 NTSTATUS
6931 NTAPI
6932 RxLowIoIoCtlShellCompletion(
6933 PRX_CONTEXT RxContext)
6934 {
6935 PIRP Irp;
6936 NTSTATUS Status;
6937
6938 PAGED_CODE();
6939
6940 DPRINT("RxLowIoIoCtlShellCompletion(%p)\n", RxContext);
6941
6942 Irp = RxContext->CurrentIrp;
6943 Status = RxContext->IoStatusBlock.Status;
6944
6945 /* Set information and status */
6946 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
6947 {
6948 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
6949 }
6950
6951 Irp->IoStatus.Status = Status;
6952
6953 return Status;
6954 }
6955
6956 NTSTATUS
6957 RxLowIoLockControlShell(
6958 IN PRX_CONTEXT RxContext)
6959 {
6960 UNIMPLEMENTED;
6961 return STATUS_NOT_IMPLEMENTED;
6962 }
6963
6964 /*
6965 * @implemented
6966 */
6967 NTSTATUS
6968 NTAPI
6969 RxLowIoNotifyChangeDirectoryCompletion(
6970 PRX_CONTEXT RxContext)
6971 {
6972 PAGED_CODE();
6973
6974 DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
6975
6976 /* Just copy back the IO_STATUS to the IRP */
6977 RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status);
6978 RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
6979
6980 return RxContext->IoStatusBlock.Status;
6981 }
6982
6983 /*
6984 * @implemented
6985 */
6986 NTSTATUS
6987 RxLowIoReadShell(
6988 PRX_CONTEXT RxContext)
6989 {
6990 PFCB Fcb;
6991 NTSTATUS Status;
6992
6993 PAGED_CODE();
6994
6995 DPRINT("RxLowIoReadShell(%p)\n", RxContext);
6996
6997 Fcb = (PFCB)RxContext->pFcb;
6998 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
6999 {
7000 return STATUS_MORE_PROCESSING_REQUIRED;
7001 }
7002
7003 /* Always update stats for disks */
7004 if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7005 {
7006 ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkReadBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7007 }
7008
7009 /* And forward the read to the mini-rdr */
7010 Status = RxLowIoSubmit(RxContext, RxLowIoReadShellCompletion);
7011 DPRINT("RxLowIoReadShell(%p), Status: %lx\n", RxContext, Status);
7012
7013 return Status;
7014 }
7015
7016 NTSTATUS
7017 NTAPI
7018 RxLowIoReadShellCompletion(
7019 PRX_CONTEXT RxContext)
7020 {
7021 PIRP Irp;
7022 PFCB Fcb;
7023 NTSTATUS Status;
7024 BOOLEAN PagingIo, IsPipe;
7025 PIO_STACK_LOCATION Stack;
7026 PLOWIO_CONTEXT LowIoContext;
7027
7028 PAGED_CODE();
7029
7030 DPRINT("RxLowIoReadShellCompletion(%p)\n", RxContext);
7031
7032 Status = RxContext->IoStatusBlock.Status;
7033 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7034
7035 Irp = RxContext->CurrentIrp;
7036 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7037
7038 /* Set IRP information from the RX_CONTEXT status block */
7039 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7040
7041 /* Fixup status for paging file if nothing was read */
7042 if (PagingIo)
7043 {
7044 if (NT_SUCCESS(Status) && RxContext->IoStatusBlock.Information == 0)
7045 {
7046 Status = STATUS_END_OF_FILE;
7047 }
7048 }
7049
7050 LowIoContext = &RxContext->LowIoContext;
7051 ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7052
7053 /* Check broken cases that should never happen */
7054 Fcb = (PFCB)RxContext->pFcb;
7055 if (Status == STATUS_FILE_LOCK_CONFLICT)
7056 {
7057 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED))
7058 {
7059 ASSERT(FALSE);
7060 return STATUS_RETRY;
7061 }
7062 }
7063 else if (Status == STATUS_SUCCESS)
7064 {
7065 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
7066 {
7067 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED) ||
7068 BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED))
7069 {
7070 ASSERT(FALSE);
7071 }
7072 }
7073
7074 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED))
7075 {
7076 ASSERT(FALSE);
7077 }
7078 }
7079
7080 /* Readahead should go through Cc and not finish here */
7081 ASSERT(!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD));
7082
7083 /* If it's sync, RxCommonRead will finish the work - nothing to do here */
7084 if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7085 {
7086 return Status;
7087 }
7088
7089 Stack = RxContext->CurrentIrpSp;
7090 IsPipe = BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
7091 /* Release lock if required */
7092 if (PagingIo)
7093 {
7094 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7095 }
7096 else
7097 {
7098 /* Set FastIo if read was a success */
7099 if (NT_SUCCESS(Status) && !IsPipe)
7100 {
7101 SetFlag(Stack->FileObject->Flags, FO_FILE_FAST_IO_READ);
7102 }
7103
7104 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7105 {
7106 RxResumeBlockedOperations_Serially(RxContext, &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.ReadSerializationQueue);
7107 }
7108 else
7109 {
7110 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7111 }
7112 }
7113
7114 if (IsPipe)
7115 {
7116 UNIMPLEMENTED;
7117 }
7118
7119 /* Final sanity checks */
7120 ASSERT(Status != STATUS_RETRY);
7121 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
7122 ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
7123
7124 return Status;
7125 }
7126
7127 /*
7128 * @implemented
7129 */
7130 NTSTATUS
7131 RxLowIoWriteShell(
7132 IN PRX_CONTEXT RxContext)
7133 {
7134 PFCB Fcb;
7135 NTSTATUS Status;
7136
7137 PAGED_CODE();
7138
7139 DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
7140
7141 Fcb = (PFCB)RxContext->pFcb;
7142
7143 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7144 !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7145
7146 /* Always update stats for disks */
7147 if (Fcb->CachedNetRootType == NET_ROOT_DISK)
7148 {
7149 ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
7150 }
7151
7152 /* And forward the write to the mini-rdr */
7153 Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion);
7154 DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
7155
7156 return Status;
7157 }
7158
7159 NTSTATUS
7160 NTAPI
7161 RxLowIoWriteShellCompletion(
7162 PRX_CONTEXT RxContext)
7163 {
7164 PIRP Irp;
7165 PFCB Fcb;
7166 NTSTATUS Status;
7167 BOOLEAN PagingIo;
7168 PLOWIO_CONTEXT LowIoContext;
7169
7170 PAGED_CODE();
7171
7172 DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
7173
7174 Status = RxContext->IoStatusBlock.Status;
7175 DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
7176
7177 Irp = RxContext->CurrentIrp;
7178
7179 /* Set IRP information from the RX_CONTEXT status block */
7180 Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
7181
7182 LowIoContext = &RxContext->LowIoContext;
7183 ASSERT(RxLowIoIsBufferLocked(LowIoContext));
7184
7185 /* Perform a few sanity checks */
7186 Fcb = (PFCB)RxContext->pFcb;
7187 if (Status == STATUS_SUCCESS)
7188 {
7189 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED))
7190 {
7191 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
7192 !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
7193 }
7194
7195 ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED));
7196 }
7197
7198 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
7199 if (Status != STATUS_SUCCESS && PagingIo)
7200 {
7201 DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status);
7202 }
7203
7204 /* In case of async call, perform last bits not done in RxCommonWrite */
7205 if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
7206 {
7207 PFILE_OBJECT FileObject;
7208 PIO_STACK_LOCATION Stack;
7209
7210 /* We only succeed if we wrote what was asked for */
7211 if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7212 {
7213 ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount);
7214 }
7215
7216 /* If write succeed, ,also update FILE_OBJECT flags */
7217 Stack = RxContext->CurrentIrpSp;
7218 FileObject = Stack->FileObject;
7219 if (!PagingIo)
7220 {
7221 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
7222 }
7223
7224 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE))
7225 {
7226 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
7227 }
7228
7229 /* If VDL was extended, fix attributes */
7230 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL))
7231 {
7232 LONGLONG LastOffset, FileSize;
7233
7234 LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset +
7235 Irp->IoStatus.Information;
7236 RxGetFileSizeWithLock(Fcb, &FileSize);
7237
7238 if (FileSize < LastOffset)
7239 {
7240 LastOffset = FileSize;
7241 }
7242
7243 Fcb->Header.ValidDataLength.QuadPart = LastOffset;
7244 }
7245
7246 /* One less outstanding write */
7247 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7248 {
7249 PNON_PAGED_FCB NonPagedFcb;
7250
7251 NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
7252 if (NonPagedFcb != NULL)
7253 {
7254 if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites,
7255 -1, &RxStrucSupSpinLock) == 1)
7256 {
7257 KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
7258 }
7259 }
7260 }
7261
7262 /* Release paging resource if acquired */
7263 if (RxContext->FcbPagingIoResourceAcquired)
7264 {
7265 RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7266 }
7267
7268 /* Resume blocked operations for pipes */
7269 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7270 {
7271 RxResumeBlockedOperations_Serially(RxContext,
7272 &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue);
7273 }
7274 else
7275 {
7276 /* And release FCB only for files */
7277 if (RxContext->FcbResourceAcquired)
7278 {
7279 RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
7280 }
7281 }
7282
7283 /* Final sanity checks */
7284 ASSERT(Status != STATUS_RETRY);
7285 ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length));
7286 ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
7287
7288 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
7289 {
7290 UNIMPLEMENTED;
7291 }
7292 }
7293
7294 return Status;
7295 }
7296
7297 /*
7298 * @implemented
7299 */
7300 NTSTATUS
7301 RxNotifyChangeDirectory(
7302 PRX_CONTEXT RxContext)
7303 {
7304 PIRP Irp;
7305 NTSTATUS Status;
7306 PIO_STACK_LOCATION Stack;
7307
7308 PAGED_CODE();
7309
7310 /* The IRP can abviously wait */
7311 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
7312
7313 /* Initialize its lowio */
7314 RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
7315
7316 _SEH2_TRY
7317 {
7318 /* Lock user buffer */
7319 Stack = RxContext->CurrentIrpSp;
7320 RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
7321
7322 /* Copy parameters from IO_STACK */
7323 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE);
7324 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter;
7325 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
7326
7327 /* If we have an associated MDL */
7328 Irp = RxContext->CurrentIrp;
7329 if (Irp->MdlAddress != NULL)
7330 {
7331 /* Then, call mini-rdr */
7332 RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
7333 if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL)
7334 {
7335 Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion);
7336 }
7337 else
7338 {
7339 Status = STATUS_INSUFFICIENT_RESOURCES;
7340 }
7341 }
7342 else
7343 {
7344 Status = STATUS_INVALID_PARAMETER;
7345 }
7346 }
7347 _SEH2_FINALLY
7348 {
7349 /* All correct */
7350 }
7351 _SEH2_END;
7352
7353 return Status;
7354 }
7355
7356 NTSTATUS
7357 RxPostStackOverflowRead (
7358 IN PRX_CONTEXT RxContext)
7359 {
7360 PAGED_CODE();
7361
7362 UNIMPLEMENTED;
7363 return STATUS_NOT_IMPLEMENTED;
7364 }
7365
7366 /*
7367 * @implemented
7368 */
7369 VOID
7370 RxpPrepareCreateContextForReuse(
7371 PRX_CONTEXT RxContext)
7372 {
7373 /* Reuse can only happen for open operations (STATUS_RETRY) */
7374 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7375
7376 /* Release the FCB if it was acquired */
7377 if (RxContext->Create.FcbAcquired)
7378 {
7379 RxReleaseFcb(RxContext, RxContext->pFcb);
7380 RxContext->Create.FcbAcquired = FALSE;
7381 }
7382
7383 /* Free the canonical name */
7384 RxFreeCanonicalNameBuffer(RxContext);
7385
7386 /* If we have a VNetRoot associated */
7387 if (RxContext->Create.pVNetRoot != NULL || RxContext->Create.NetNamePrefixEntry != NULL)
7388 {
7389 /* Remove our link and thus, dereference the VNetRoot */
7390 RxpAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE, TRUE);
7391 if (RxContext->Create.pVNetRoot != NULL)
7392 {
7393 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot, TRUE);
7394 RxContext->Create.pVNetRoot = NULL;
7395 }
7396 RxpReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
7397 }
7398
7399 DPRINT("RxContext: %p prepared for reuse\n", RxContext);
7400 }
7401
7402 /*
7403 * @implemented
7404 */
7405 NTSTATUS
7406 RxpQueryInfoMiniRdr(
7407 PRX_CONTEXT RxContext,
7408 FILE_INFORMATION_CLASS FileInfoClass,
7409 PVOID Buffer)
7410 {
7411 PFCB Fcb;
7412 NTSTATUS Status;
7413
7414 Fcb = (PFCB)RxContext->pFcb;
7415
7416 /* Set the RX_CONTEXT */
7417 RxContext->Info.FileInformationClass = FileInfoClass;
7418 RxContext->Info.Buffer = Buffer;
7419
7420 /* Pass down */
7421 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryFileInfo, (RxContext));
7422
7423 return Status;
7424 }
7425
7426 /*
7427 * @implemented
7428 */
7429 NTSTATUS
7430 RxPrefixClaim(
7431 IN PRX_CONTEXT RxContext)
7432 {
7433 PIRP Irp;
7434 NTSTATUS Status;
7435 NET_ROOT_TYPE NetRootType;
7436 UNICODE_STRING CanonicalName, FileName, NetRootName;
7437
7438 PAGED_CODE();
7439
7440 Irp = RxContext->CurrentIrp;
7441
7442 /* This has to come from MUP */
7443 if (Irp->RequestorMode == UserMode)
7444 {
7445 return STATUS_INVALID_DEVICE_REQUEST;
7446 }
7447
7448 if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL)
7449 {
7450 PQUERY_PATH_REQUEST QueryRequest;
7451
7452 /* Get parameters */
7453 QueryRequest = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7454
7455 /* Don't overflow allocation */
7456 if (QueryRequest->PathNameLength >= MAXUSHORT - 1)
7457 {
7458 return STATUS_INVALID_DEVICE_REQUEST;
7459 }
7460
7461 /* Forcefully rewrite IRP MJ */
7462 RxContext->MajorFunction = IRP_MJ_CREATE;
7463
7464 /* Fake canon name */
7465 RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
7466 if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
7467 {
7468 Status = STATUS_INSUFFICIENT_RESOURCES;
7469 goto Leave;
7470 }
7471
7472 /* Copy the prefix to look for */
7473 RtlCopyMemory(RxContext->PrefixClaim.SuppliedPathName.Buffer, &QueryRequest->FilePathName[0], QueryRequest->PathNameLength);
7474 RxContext->PrefixClaim.SuppliedPathName.Length = QueryRequest->PathNameLength;
7475 RxContext->PrefixClaim.SuppliedPathName.MaximumLength = QueryRequest->PathNameLength;
7476
7477 /* Zero the create parameters */
7478 RtlZeroMemory(&RxContext->Create.NtCreateParameters,
7479 FIELD_OFFSET(RX_CONTEXT, AlsoCanonicalNameBuffer) - FIELD_OFFSET(RX_CONTEXT, Create.NtCreateParameters));
7480 RxContext->Create.ThisIsATreeConnectOpen = TRUE;
7481 RxContext->Create.NtCreateParameters.SecurityContext = QueryRequest->SecurityContext;
7482 }
7483 else
7484 {
7485 /* If not devcontrol, it comes from open, name was already copied */
7486 ASSERT(RxContext->MajorFunction == IRP_MJ_CREATE);
7487 ASSERT(RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL);
7488 }
7489
7490 /* Canonilize name */
7491 NetRootType = NET_ROOT_WILD;
7492 RtlInitEmptyUnicodeString(&CanonicalName, NULL, 0);
7493 FileName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7494 FileName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7495 FileName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7496 NetRootName.Length = RxContext->PrefixClaim.SuppliedPathName.Length;
7497 NetRootName.MaximumLength = RxContext->PrefixClaim.SuppliedPathName.MaximumLength;
7498 NetRootName.Buffer = RxContext->PrefixClaim.SuppliedPathName.Buffer;
7499 Status = RxFirstCanonicalize(RxContext, &FileName, &CanonicalName, &NetRootType);
7500 /* It went fine, attempt to establish a connection (that way we know whether the prefix is accepted) */
7501 if (NT_SUCCESS(Status))
7502 {
7503 Status = RxFindOrConstructVirtualNetRoot(RxContext, &CanonicalName, NetRootType, &NetRootName);
7504 }
7505 if (Status == STATUS_PENDING)
7506 {
7507 return Status;
7508 }
7509 /* Reply to MUP */
7510 if (NT_SUCCESS(Status))
7511 {
7512 PQUERY_PATH_RESPONSE QueryResponse;
7513
7514 /* We accept the length that was canon (minus netroot) */
7515 QueryResponse = RxContext->CurrentIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
7516 QueryResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - NetRootName.Length;
7517 }
7518
7519 Leave:
7520 /* If we reach that point with MJ, reset everything and make IRP being a device control */
7521 if (RxContext->MajorFunction == IRP_MJ_CREATE)
7522 {
7523 if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
7524 {
7525 RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
7526 }
7527
7528 RxpPrepareCreateContextForReuse(RxContext);
7529
7530 RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
7531 }
7532
7533 return Status;
7534 }
7535
7536 NTSTATUS
7537 NTAPI
7538 RxPrepareToReparseSymbolicLink(
7539 PRX_CONTEXT RxContext,
7540 BOOLEAN SymbolicLinkEmbeddedInOldPath,
7541 PUNICODE_STRING NewPath,
7542 BOOLEAN NewPathIsAbsolute,
7543 PBOOLEAN ReparseRequired)
7544 {
7545 UNIMPLEMENTED;
7546 return STATUS_NOT_IMPLEMENTED;
7547 }
7548
7549 /*
7550 * @implemented
7551 */
7552 VOID
7553 RxPrePostIrp(
7554 IN PVOID Context,
7555 IN PIRP Irp)
7556 {
7557 LOCK_OPERATION Lock;
7558 PIO_STACK_LOCATION Stack;
7559 PRX_CONTEXT RxContext = Context;
7560
7561 /* NULL IRP is no option */
7562 if (Irp == NULL)
7563 {
7564 return;
7565 }
7566
7567 /* Check whether preparation was really needed */
7568 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED))
7569 {
7570 return;
7571 }
7572 /* Mark the context as prepared */
7573 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
7574
7575 /* Just lock the user buffer, with the correct length, depending on the MJ */
7576 Lock = IoReadAccess;
7577 Stack = RxContext->CurrentIrpSp;
7578 if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
7579 {
7580 if (!BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
7581 {
7582 if (RxContext->MajorFunction == IRP_MJ_READ)
7583 {
7584 Lock = IoWriteAccess;
7585 }
7586 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.Read.Length);
7587 }
7588 }
7589 else
7590 {
7591 if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) ||
7592 RxContext->MajorFunction == IRP_MJ_QUERY_EA)
7593 {
7594 Lock = IoWriteAccess;
7595 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.QueryDirectory.Length);
7596 }
7597 else if (RxContext->MajorFunction == IRP_MJ_SET_EA)
7598 {
7599 RxLockUserBuffer(RxContext, Lock, Stack->Parameters.SetEa.Length);
7600 }
7601 }
7602
7603 /* As it will be posted (async), mark the IRP pending */
7604 IoMarkIrpPending(Irp);
7605 }
7606
7607 /*
7608 * @implemented
7609 */
7610 NTSTATUS
7611 RxpSetInfoMiniRdr(
7612 PRX_CONTEXT RxContext,
7613 FILE_INFORMATION_CLASS Class)
7614 {
7615 PFCB Fcb;
7616 NTSTATUS Status;
7617
7618 /* Initialize parameters in RX_CONTEXT */
7619 RxContext->Info.FileInformationClass = Class;
7620 RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
7621 RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
7622
7623 /* And call mini-rdr */
7624 Fcb = (PFCB)RxContext->pFcb;
7625 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
7626
7627 return Status;
7628 }
7629
7630 VOID
7631 NTAPI
7632 RxpUnregisterMinirdr(
7633 IN PRDBSS_DEVICE_OBJECT RxDeviceObject)
7634 {
7635 UNIMPLEMENTED;
7636 }
7637
7638 /*
7639 * @implemented
7640 */
7641 VOID
7642 RxPurgeNetFcb(
7643 PFCB Fcb,
7644 PRX_CONTEXT LocalContext)
7645 {
7646 NTSTATUS Status;
7647
7648 PAGED_CODE();
7649
7650 /* First, flush */
7651 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
7652
7653 /* And force close */
7654 RxReleaseFcb(NULL, Fcb);
7655 MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
7656 Status = RxAcquireExclusiveFcb(NULL, Fcb);
7657 ASSERT(Status == STATUS_SUCCESS);
7658 }
7659
7660 NTSTATUS
7661 RxQueryAlternateNameInfo(
7662 PRX_CONTEXT RxContext,
7663 PFILE_NAME_INFORMATION AltNameInfo)
7664 {
7665 UNIMPLEMENTED;
7666 return STATUS_NOT_IMPLEMENTED;
7667 }
7668
7669 /*
7670 * @implemented
7671 */
7672 NTSTATUS
7673 RxQueryBasicInfo(
7674 PRX_CONTEXT RxContext,
7675 PFILE_BASIC_INFORMATION BasicInfo)
7676 {
7677 PAGED_CODE();
7678
7679 DPRINT("RxQueryBasicInfo(%p, %p)\n", RxContext, BasicInfo);
7680
7681 /* Simply zero and forward to mini-rdr */
7682 RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION));
7683 return RxpQueryInfoMiniRdr(RxContext, FileBasicInformation, BasicInfo);
7684 }
7685
7686 NTSTATUS
7687 RxQueryCompressedInfo(
7688 PRX_CONTEXT RxContext,
7689 PFILE_COMPRESSION_INFORMATION CompressionInfo)
7690 {
7691 UNIMPLEMENTED;
7692 return STATUS_NOT_IMPLEMENTED;
7693 }
7694
7695 /*
7696 * @implemented
7697 */
7698 NTSTATUS
7699 RxQueryDirectory(
7700 PRX_CONTEXT RxContext)
7701 {
7702 PIRP Irp;
7703 PFCB Fcb;
7704 PFOBX Fobx;
7705 UCHAR Flags;
7706 NTSTATUS Status;
7707 BOOLEAN LockNotGranted;
7708 ULONG Length, FileIndex;
7709 PUNICODE_STRING FileName;
7710 PIO_STACK_LOCATION Stack;
7711 FILE_INFORMATION_CLASS FileInfoClass;
7712
7713 PAGED_CODE();
7714
7715 DPRINT("RxQueryDirectory(%p)\n", RxContext);
7716
7717 /* Get parameters */
7718 Stack = RxContext->CurrentIrpSp;
7719 Length = Stack->Parameters.QueryDirectory.Length;
7720 FileName = Stack->Parameters.QueryDirectory.FileName;
7721 FileInfoClass = Stack->Parameters.QueryDirectory.FileInformationClass;
7722 DPRINT("Wait: %d, Length: %ld, FileName: %p, Class: %d\n",
7723 FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), Length,
7724 FileName, FileInfoClass);
7725
7726 Irp = RxContext->CurrentIrp;
7727 Flags = Stack->Flags;
7728 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
7729 DPRINT("Index: %d, Buffer: %p, Flags: %x\n", FileIndex, Irp->UserBuffer, Flags);
7730
7731 if (FileName != NULL)
7732 {
7733 DPRINT("FileName: %wZ\n", FileName);
7734 }
7735
7736 /* No FOBX: not a standard file/directory */
7737 Fobx = (PFOBX)RxContext->pFobx;
7738 if (Fobx == NULL)
7739 {
7740 return STATUS_OBJECT_NAME_INVALID;
7741 }
7742
7743 /* We can only deal with a disk */
7744 Fcb = (PFCB)RxContext->pFcb;
7745 if (Fcb->pNetRoot->Type != NET_ROOT_DISK)
7746 {
7747 DPRINT1("Not a disk! %x\n", Fcb->pNetRoot->Type);
7748 return STATUS_INVALID_DEVICE_REQUEST;
7749 }
7750
7751 /* Setup RX_CONTEXT related fields */
7752 RxContext->QueryDirectory.FileIndex = FileIndex;
7753 RxContext->QueryDirectory.RestartScan = BooleanFlagOn(Flags, SL_RESTART_SCAN);
7754 RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn(Flags, SL_RETURN_SINGLE_ENTRY);
7755 RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn(Flags, SL_INDEX_SPECIFIED);
7756 RxContext->QueryDirectory.InitialQuery = (Fobx->UnicodeQueryTemplate.Buffer == NULL) && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7757
7758 /* We don't support (yet?) a specific index being set */
7759 if (RxContext->QueryDirectory.IndexSpecified)
7760 {
7761 return STATUS_NOT_IMPLEMENTED;
7762 }
7763
7764 /* Try to lock FCB */
7765 LockNotGranted = TRUE;
7766 if (RxContext->QueryDirectory.InitialQuery)
7767 {
7768 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7769 if (Status != STATUS_LOCK_NOT_GRANTED)
7770 {
7771 if (!NT_SUCCESS(Status))
7772 {
7773 return Status;
7774 }
7775
7776 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7777 {
7778 RxContext->QueryDirectory.InitialQuery = FALSE;
7779 RxConvertToSharedFcb(RxContext, Fcb);
7780 }
7781
7782 LockNotGranted = FALSE;
7783 }
7784 }
7785 else
7786 {
7787 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
7788 if (Status != STATUS_LOCK_NOT_GRANTED)
7789 {
7790 if (!NT_SUCCESS(Status))
7791 {
7792 return Status;
7793 }
7794
7795 LockNotGranted = FALSE;
7796 }
7797 }
7798
7799 /* If it failed, post request */
7800 if (LockNotGranted)
7801 {
7802 return RxFsdPostRequest(RxContext);
7803 }
7804
7805 /* This cannot be done on a orphaned directory */
7806 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
7807 {
7808 RxReleaseFcb(RxContext, Fcb);
7809 return STATUS_FILE_CLOSED;
7810 }
7811
7812 _SEH2_TRY
7813 {
7814 /* Set index */
7815 if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan)
7816 {
7817 RxContext->QueryDirectory.FileIndex = 0;
7818 }
7819
7820 /* Assume success */
7821 Status = STATUS_SUCCESS;
7822 /* If initial query, prepare FOBX */
7823 if (RxContext->QueryDirectory.InitialQuery)
7824 {
7825 /* We cannot have a template already! */
7826 ASSERT(!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE));
7827
7828 /* If we have a file name and a correct one, duplicate it in the FOBX */
7829 if (FileName != NULL && FileName->Length != 0 && FileName->Buffer != NULL &&
7830 (FileName->Length != sizeof(WCHAR) || FileName->Buffer[0] != '*') &&
7831 (FileName->Length != 12 * sizeof(WCHAR) ||
7832 RtlCompareMemory(FileName->Buffer, Rx8QMdot3QM, 12 * sizeof(WCHAR)) != 12 * sizeof(WCHAR)))
7833 {
7834 Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
7835
7836 Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
7837 if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
7838 {
7839 /* UNICODE_STRING; length has to be even */
7840 if ((FileName->Length & 1) != 0)
7841 {
7842 Status = STATUS_INVALID_PARAMETER;
7843 RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
7844 }
7845 else
7846 {
7847 Fobx->UnicodeQueryTemplate.Length = FileName->Length;
7848 Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
7849 RtlMoveMemory(Fobx->UnicodeQueryTemplate.Buffer, FileName->Buffer, FileName->Length);
7850
7851 SetFlag(Fobx->Flags, FOBX_FLAG_FREE_UNICODE);
7852 }
7853 }
7854 else
7855 {
7856 Status = STATUS_INSUFFICIENT_RESOURCES;
7857 }
7858 }
7859 /* No name specified, or a match all wildcard? Match everything */
7860 else
7861 {
7862 Fobx->ContainsWildCards = TRUE;
7863
7864 Fobx->UnicodeQueryTemplate.Buffer = &RxStarForTemplate;
7865 Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
7866 Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
7867
7868 SetFlag(Fobx->Flags, FOBX_FLAG_MATCH_ALL);
7869 }
7870
7871 /* No need for exclusive any longer */
7872 if (NT_SUCCESS(Status))
7873 {
7874 RxConvertToSharedFcb(RxContext, Fcb);
7875 }
7876 }
7877
7878 /* Lock user buffer and forward to mini-rdr */
7879 if (NT_SUCCESS(Status))
7880 {
7881 RxLockUserBuffer(RxContext, IoModifyAccess, Length);
7882 RxContext->Info.FileInformationClass = FileInfoClass;
7883 RxContext->Info.Buffer = RxNewMapUserBuffer(RxContext);
7884 RxContext->Info.Length = Length;
7885
7886 if (RxContext->Info.Buffer != NULL)
7887 {
7888 MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxQueryDirectory, (RxContext));
7889 }
7890
7891 /* Post if mini-rdr asks to */
7892 if (RxContext->PostRequest)
7893 {
7894 RxFsdPostRequest(RxContext);
7895 }
7896 else
7897 {
7898 Irp->IoStatus.Information = Length - RxContext->Info.LengthRemaining;
7899 }
7900 }
7901 }
7902 _SEH2_FINALLY
7903 {
7904 RxReleaseFcb(RxContext, Fcb);
7905 }
7906 _SEH2_END;
7907
7908 return Status;
7909 }
7910
7911 NTSTATUS
7912 RxQueryEaInfo(
7913 PRX_CONTEXT RxContext,
7914 PFILE_EA_INFORMATION EaInfo)
7915 {
7916 UNIMPLEMENTED;
7917 return STATUS_NOT_IMPLEMENTED;
7918 }
7919
7920 NTSTATUS
7921 RxQueryInternalInfo(
7922 PRX_CONTEXT RxContext,
7923 PFILE_INTERNAL_INFORMATION InternalInfo)
7924 {
7925 UNIMPLEMENTED;
7926 return STATUS_NOT_IMPLEMENTED;
7927 }
7928
7929 NTSTATUS
7930 RxQueryNameInfo(
7931 PRX_CONTEXT RxContext,
7932 PFILE_NAME_INFORMATION NameInfo)
7933 {
7934 UNIMPLEMENTED;
7935 return STATUS_NOT_IMPLEMENTED;
7936 }
7937
7938 NTSTATUS
7939 RxQueryPipeInfo(
7940 PRX_CONTEXT RxContext,
7941 PFILE_PIPE_INFORMATION PipeInfo)
7942 {
7943 UNIMPLEMENTED;
7944 return STATUS_NOT_IMPLEMENTED;
7945 }
7946
7947 NTSTATUS
7948 RxQueryPositionInfo(
7949 PRX_CONTEXT RxContext,
7950 PFILE_POSITION_INFORMATION PositionInfo)
7951 {
7952 UNIMPLEMENTED;
7953 return STATUS_NOT_IMPLEMENTED;
7954 }
7955
7956 /*
7957 * @implemented
7958 */
7959 NTSTATUS
7960 RxQueryStandardInfo(
7961 PRX_CONTEXT RxContext,
7962 PFILE_STANDARD_INFORMATION StandardInfo)
7963 {
7964 PFCB Fcb;
7965 PFOBX Fobx;
7966 NTSTATUS Status;
7967
7968 PAGED_CODE();
7969
7970 DPRINT("RxQueryStandardInfo(%p, %p)\n", RxContext, StandardInfo);
7971
7972 /* Zero output buffer */
7973 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
7974
7975 Fcb = (PFCB)RxContext->pFcb;
7976 Fobx = (PFOBX)RxContext->pFobx;
7977 /* If not a standard file type, or opened for backup, immediately forward to mini-rdr */
7978 if ((NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) ||
7979 BooleanFlagOn(Fobx->pSrvOpen->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
7980 {
7981 return RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
7982 }
7983
7984 /* Otherwise, fill what we can already */
7985 Status = STATUS_SUCCESS;
7986 StandardInfo->NumberOfLinks = Fcb->NumberOfLinks;
7987 StandardInfo->DeletePending = BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
7988 StandardInfo->Directory = (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
7989 if (StandardInfo->NumberOfLinks == 0)
7990 {
7991 StandardInfo->NumberOfLinks = 1;
7992 }
7993
7994 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
7995 {
7996 StandardInfo->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
7997 RxGetFileSizeWithLock(Fcb, &StandardInfo->EndOfFile.QuadPart);
7998 }
7999
8000 /* If we are asked to forcefully forward to mini-rdr or if size isn't cached, do it */
8001 if (RxForceQFIPassThrough || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILESIZECACHEING_ENABLED))
8002 {
8003 Status = RxpQueryInfoMiniRdr(RxContext, FileStandardInformation, StandardInfo);
8004 }
8005 else
8006 {
8007 RxContext->IoStatusBlock.Information -= sizeof(FILE_STANDARD_INFORMATION);
8008 }
8009
8010 return Status;
8011 }
8012
8013 /*
8014 * @implemented
8015 */
8016 VOID
8017 NTAPI
8018 RxReadRegistryParameters(
8019 VOID)
8020 {
8021 NTSTATUS Status;
8022 HANDLE KeyHandle;
8023 ULONG ResultLength;
8024 UCHAR Buffer[0x40];
8025 UNICODE_STRING KeyName, ParamName;
8026 OBJECT_ATTRIBUTES ObjectAttributes;
8027 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
8028
8029 PAGED_CODE();
8030
8031 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters");
8032 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
8033 Status = ZwOpenKey(&KeyHandle, READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
8034 if (!NT_SUCCESS(Status))
8035 {
8036 return;
8037 }
8038
8039 PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
8040 RtlInitUnicodeString(&ParamName, L"DisableByteRangeLockingOnReadOnlyFiles");
8041 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8042 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8043 {
8044 DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
8045 }
8046
8047 RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
8048 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8049 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8050 {
8051 ULONG Granularity = *(PULONG)PartialInfo->Data;
8052
8053 if (Granularity > 16)
8054 {
8055 Granularity = 16;
8056 }
8057
8058 ReadAheadGranularity = Granularity << PAGE_SHIFT;
8059 }
8060
8061 RtlInitUnicodeString(&ParamName, L"DisableFlushOnCleanup");
8062 Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
8063 if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
8064 {
8065 DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
8066 }
8067
8068 ZwClose(KeyHandle);
8069 }
8070
8071 /*
8072 * @implemented
8073 */
8074 NTSTATUS
8075 NTAPI
8076 RxRegisterMinirdr(
8077 OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
8078 IN OUT PDRIVER_OBJECT DriverObject,
8079 IN PMINIRDR_DISPATCH MrdrDispatch,
8080 IN ULONG Controls,
8081 IN PUNICODE_STRING DeviceName,
8082 IN ULONG DeviceExtensionSize,
8083 IN DEVICE_TYPE DeviceType,
8084 IN ULONG DeviceCharacteristics)
8085 {
8086 NTSTATUS Status;
8087 PRDBSS_DEVICE_OBJECT RDBSSDevice;
8088
8089 PAGED_CODE();
8090
8091 if (!DeviceObject)
8092 {
8093 return STATUS_INVALID_PARAMETER;
8094 }
8095
8096 /* Create device object with provided parameters */
8097 Status = IoCreateDevice(DriverObject,
8098 DeviceExtensionSize + sizeof(RDBSS_DEVICE_OBJECT),
8099 DeviceName,
8100 DeviceType,
8101 DeviceCharacteristics,
8102 FALSE,
8103 (PDEVICE_OBJECT *)&RDBSSDevice);
8104 if (!NT_SUCCESS(Status))
8105 {
8106 return Status;
8107 }
8108
8109 if (!RxData.DriverObject)
8110 {
8111 return STATUS_UNSUCCESSFUL;
8112 }
8113
8114 /* Initialize our DO extension */
8115 RDBSSDevice->RDBSSDeviceObject = NULL;
8116 ++RxFileSystemDeviceObject->ReferenceCount;
8117 *DeviceObject = RDBSSDevice;
8118 RDBSSDevice->RdbssExports = &RxExports;
8119 RDBSSDevice->Dispatch = MrdrDispatch;
8120 RDBSSDevice->RegistrationControls = Controls;
8121 RDBSSDevice->DeviceName = *DeviceName;
8122 RDBSSDevice->RegisterUncProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
8123 RDBSSDevice->RegisterMailSlotProvider = !BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
8124 InitializeListHead(&RDBSSDevice->OverflowQueue[0]);
8125 InitializeListHead(&RDBSSDevice->OverflowQueue[1]);
8126 InitializeListHead(&RDBSSDevice->OverflowQueue[2]);
8127 KeInitializeSpinLock(&RDBSSDevice->OverflowQueueSpinLock);
8128 RDBSSDevice->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
8129
8130 DPRINT("Registered MiniRdr %wZ (prio: %x)\n", DeviceName, RDBSSDevice->NetworkProviderPriority);
8131
8132 ExAcquireFastMutex(&RxData.MinirdrRegistrationMutex);
8133 InsertTailList(&RxData.RegisteredMiniRdrs, &RDBSSDevice->MiniRdrListLinks);
8134 ExReleaseFastMutex(&RxData.MinirdrRegistrationMutex);
8135
8136 /* Unless mini-rdr explicitly asked not to, initialize dispatch table */
8137 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH))
8138 {
8139 RxInitializeMinirdrDispatchTable(DriverObject);
8140 }
8141
8142 /* Unless mini-rdr explicitly asked not to, initialize prefix scavenger */
8143 if (!BooleanFlagOn(Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER))
8144 {
8145 LARGE_INTEGER ScavengerTimeLimit;
8146
8147 RDBSSDevice->pRxNetNameTable = &RDBSSDevice->RxNetNameTableInDeviceObject;
8148 RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
8149 RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
8150 ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
8151 RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
8152 RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
8153 }
8154
8155 RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
8156
8157 return STATUS_SUCCESS;
8158 }
8159
8160 VOID
8161 NTAPI
8162 RxReleaseFcbFromLazyWrite(
8163 PVOID Context)
8164 {
8165 UNIMPLEMENTED;
8166 }
8167
8168 VOID
8169 NTAPI
8170 RxReleaseFcbFromReadAhead(
8171 PVOID Context)
8172 {
8173 UNIMPLEMENTED;
8174 }
8175
8176 VOID
8177 NTAPI
8178 RxReleaseFileForNtCreateSection(
8179 PFILE_OBJECT FileObject)
8180 {
8181 UNIMPLEMENTED;
8182 }
8183
8184 NTSTATUS
8185 NTAPI
8186 RxReleaseForCcFlush(
8187 PFILE_OBJECT FileObject,
8188 PDEVICE_OBJECT DeviceObject)
8189 {
8190 UNIMPLEMENTED;
8191 return STATUS_NOT_IMPLEMENTED;
8192 }
8193
8194 /*
8195 * @implemented
8196 */
8197 VOID
8198 RxRemoveFromTopLevelIrpAllocatedContextsList(
8199 PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
8200 {
8201 KIRQL OldIrql;
8202
8203 /* Make sure this is a TLC and that it was allocated (otherwise, it is not in the list */
8204 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
8205 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
8206
8207 KeAcquireSpinLock(&TopLevelIrpSpinLock, &OldIrql);
8208 RemoveEntryList(&TopLevelContext->ListEntry);
8209 KeReleaseSpinLock(&TopLevelIrpSpinLock, OldIrql);
8210 }
8211
8212 /*
8213 * @implemented
8214 */
8215 PRX_CONTEXT
8216 RxRemoveOverflowEntry(
8217 PRDBSS_DEVICE_OBJECT DeviceObject,
8218 WORK_QUEUE_TYPE Queue)
8219 {
8220 KIRQL OldIrql;
8221 PRX_CONTEXT Context;
8222
8223 KeAcquireSpinLock(&DeviceObject->OverflowQueueSpinLock, &OldIrql);
8224 if (DeviceObject->OverflowQueueCount[Queue] <= 0)
8225 {
8226 /* No entries left, nothing to return */
8227 InterlockedDecrement(&DeviceObject->PostedRequestCount[Queue]);
8228 Context = NULL;
8229 }
8230 else
8231 {
8232 PLIST_ENTRY Entry;
8233
8234 /* Decrement count */
8235 --DeviceObject->OverflowQueueCount[Queue];
8236
8237 /* Return head */
8238 Entry = RemoveHeadList(&DeviceObject->OverflowQueue[Queue]);
8239 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, OverflowListEntry);
8240 ClearFlag(Context->Flags, ~(RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE));
8241 Context->OverflowListEntry.Flink = NULL;
8242 }
8243 KeReleaseSpinLock(&DeviceObject->OverflowQueueSpinLock, OldIrql);
8244
8245 return Context;
8246 }
8247
8248 /*
8249 * @implemented
8250 */
8251 VOID
8252 RxRemoveShareAccess(
8253 _Inout_ PFILE_OBJECT FileObject,
8254 _Inout_ PSHARE_ACCESS ShareAccess,
8255 _In_ PSZ where,
8256 _In_ PSZ wherelogtag)
8257 {
8258 PAGED_CODE();
8259
8260 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8261 IoRemoveShareAccess(FileObject, ShareAccess);
8262 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8263 }
8264
8265 /*
8266 * @implemented
8267 */
8268 VOID
8269 RxRemoveShareAccessPerSrvOpens(
8270 IN OUT PSRV_OPEN SrvOpen)
8271 {
8272 ACCESS_MASK DesiredAccess;
8273 BOOLEAN ReadAccess;
8274 BOOLEAN WriteAccess;
8275 BOOLEAN DeleteAccess;
8276
8277 PAGED_CODE();
8278
8279 /* Get access that were granted to SRV_OPEN */
8280 DesiredAccess = SrvOpen->DesiredAccess;
8281 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
8282 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
8283 DeleteAccess = (DesiredAccess & DELETE) != 0;
8284
8285 /* If any, drop them */
8286 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
8287 {
8288 BOOLEAN SharedRead;
8289 BOOLEAN SharedWrite;
8290 BOOLEAN SharedDelete;
8291 ULONG DesiredShareAccess;
8292 PSHARE_ACCESS ShareAccess;
8293
8294 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
8295 DesiredShareAccess = SrvOpen->ShareAccess;
8296
8297 ShareAccess->Readers -= ReadAccess;
8298 ShareAccess->Writers -= WriteAccess;
8299 ShareAccess->Deleters -= DeleteAccess;
8300
8301 ShareAccess->OpenCount--;
8302
8303 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
8304 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
8305 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
8306 ShareAccess->SharedRead -= SharedRead;
8307 ShareAccess->SharedWrite -= SharedWrite;
8308 ShareAccess->SharedDelete -= SharedDelete;
8309 }
8310 }
8311
8312 NTSTATUS
8313 RxSearchForCollapsibleOpen(
8314 PRX_CONTEXT RxContext,
8315 ACCESS_MASK DesiredAccess,
8316 ULONG ShareAccess)
8317 {
8318 PFCB Fcb;
8319 NTSTATUS Status;
8320 PLIST_ENTRY ListEntry;
8321 BOOLEAN ShouldTry, Purged, Scavenged;
8322
8323 PAGED_CODE();
8324
8325 DPRINT("RxSearchForCollapsibleOpen(%p, %x, %x)\n", RxContext, DesiredAccess, ShareAccess);
8326
8327 Fcb = (PFCB)RxContext->pFcb;
8328
8329 /* If we're asked to open for backup, don't allow SRV_OPEN reuse */
8330 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
8331 {
8332 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8333
8334 RxScavengeRelatedFobxs(Fcb);
8335 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8336
8337 return STATUS_NOT_FOUND;
8338 }
8339
8340 /* If basic open, ask the mini-rdr if we should try to collapse */
8341 if (RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN ||
8342 RxContext->Create.NtCreateParameters.Disposition == FILE_OPEN_IF)
8343 {
8344 ShouldTry = TRUE;
8345
8346 if (Fcb->MRxDispatch != NULL)
8347 {
8348 ASSERT(RxContext->pRelevantSrvOpen == NULL);
8349 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8350
8351 ShouldTry = NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext));
8352 }
8353 }
8354 else
8355 {
8356 ShouldTry = FALSE;
8357 }
8358
8359 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE))
8360 {
8361 ShouldTry = FALSE;
8362 }
8363
8364 /* If we shouldn't try, ask the caller to allocate a new SRV_OPEN */
8365 if (!ShouldTry)
8366 {
8367 if (NT_SUCCESS(RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess)))
8368 {
8369 return STATUS_NOT_FOUND;
8370 }
8371
8372 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8373
8374 RxScavengeRelatedFobxs(Fcb);
8375 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8376
8377 return STATUS_NOT_FOUND;
8378 }
8379
8380 /* Only collapse for matching NET_ROOT & disks */
8381 if (Fcb->pNetRoot != RxContext->Create.pNetRoot ||
8382 Fcb->pNetRoot->Type != NET_ROOT_DISK)
8383 {
8384 return STATUS_NOT_FOUND;
8385 }
8386
8387 Purged = FALSE;
8388 Scavenged = FALSE;
8389 Status = STATUS_NOT_FOUND;
8390 TryAgain:
8391 /* Browse all our SRV_OPEN to find the matching one */
8392 for (ListEntry = Fcb->SrvOpenList.Flink;
8393 ListEntry != &Fcb->SrvOpenList;
8394 ListEntry = ListEntry->Flink)
8395 {
8396 PSRV_OPEN SrvOpen;
8397
8398 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
8399 /* Not the same VNET_ROOT, move to the next one */
8400 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8401 {
8402 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8403 continue;
8404 }
8405
8406 /* Is there a sharing violation? */
8407 if (SrvOpen->DesiredAccess != DesiredAccess || SrvOpen->ShareAccess != ShareAccess ||
8408 BooleanFlagOn(SrvOpen->Flags, (SRVOPEN_FLAG_CLOSED | SRVOPEN_FLAG_COLLAPSING_DISABLED | SRVOPEN_FLAG_FILE_DELETED | SRVOPEN_FLAG_FILE_RENAMED)))
8409 {
8410 if (SrvOpen->pVNetRoot != RxContext->Create.pVNetRoot)
8411 {
8412 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8413 continue;
8414 }
8415
8416 /* Check against the SRV_OPEN */
8417 Status = RxCheckShareAccessPerSrvOpens(Fcb, DesiredAccess, ShareAccess);
8418 if (!NT_SUCCESS(Status))
8419 {
8420 break;
8421 }
8422 }
8423 else
8424 {
8425 /* Don't allow collaspse for reparse point opening */
8426 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions ^ SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT))
8427 {
8428 Purged = TRUE;
8429 Scavenged = TRUE;
8430 Status = STATUS_NOT_FOUND;
8431 break;
8432 }
8433
8434 /* Not readonly? Or bytereange lock disabled? Try to collapse! */
8435 if (DisableByteRangeLockingOnReadOnlyFiles || !BooleanFlagOn(SrvOpen->pFcb->Attributes, FILE_ATTRIBUTE_READONLY))
8436 {
8437 RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
8438
8439 ASSERT(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL);
8440 if (NT_SUCCESS(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen(RxContext)))
8441 {
8442 /* Is close delayed - great reuse*/
8443 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
8444 {
8445 DPRINT("Delayed close successfull, reusing %p\n", SrvOpen);
8446 InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
8447 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
8448 }
8449
8450 return STATUS_SUCCESS;
8451 }
8452
8453 Status = STATUS_NOT_FOUND;
8454 break;
8455 }
8456 }
8457 }
8458 /* We browse the whole list and didn't find any matching? NOT_FOUND */
8459 if (ListEntry == &Fcb->SrvOpenList)
8460 {
8461 Status = STATUS_NOT_FOUND;
8462 }
8463
8464 /* Only required access: read attributes? Don't reuse */
8465 if ((DesiredAccess & 0xFFEFFFFF) == FILE_READ_ATTRIBUTES)
8466 {
8467 return STATUS_NOT_FOUND;
8468 }
8469
8470 /* Not found? Scavenge and retry to look for collaspile SRV_OPEN */
8471 if (!Scavenged)
8472 {
8473 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
8474 Scavenged = TRUE;
8475 RxScavengeRelatedFobxs(Fcb);
8476 goto TryAgain;
8477 }
8478
8479 /* Not found? Purgeable? Purge and retry to look for collaspile SRV_OPEN */
8480 if (!Purged && RxIsOkToPurgeFcb(Fcb))
8481 {
8482 RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
8483 Purged = TRUE;
8484 goto TryAgain;
8485 }
8486
8487 /* If sharing violation, keep track of it */
8488 if (Status == STATUS_SHARING_VIOLATION)
8489 {
8490 RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
8491 }
8492
8493 DPRINT("Status: %x\n", Status);
8494 return Status;
8495 }
8496
8497 NTSTATUS
8498 RxSetAllocationInfo(
8499 PRX_CONTEXT RxContext)
8500 {
8501 UNIMPLEMENTED;
8502 return STATUS_NOT_IMPLEMENTED;
8503 }
8504
8505 /*
8506 * @implemented
8507 */
8508 NTSTATUS
8509 RxSetBasicInfo(
8510 PRX_CONTEXT RxContext)
8511 {
8512 NTSTATUS Status;
8513
8514 PAGED_CODE();
8515
8516 #define FILE_ATTRIBUTE_VOLUME 0x8
8517 #define VALID_FILE_ATTRIBUTES ( \
8518 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
8519 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
8520 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
8521 FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
8522 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
8523 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
8524 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
8525 #define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
8526
8527 /* First of all, call the mini-rdr */
8528 Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation);
8529 /* If it succeed, perform last bits */
8530 if (NT_SUCCESS(Status))
8531 {
8532 PIRP Irp;
8533 PFCB Fcb;
8534 PFOBX Fobx;
8535 PFILE_OBJECT FileObject;
8536 ULONG Attributes, CleanAttr;
8537 PFILE_BASIC_INFORMATION BasicInfo;
8538
8539 Fcb = (PFCB)RxContext->pFcb;
8540 Fobx = (PFOBX)RxContext->pFobx;
8541 Irp = RxContext->CurrentIrp;
8542 BasicInfo = Irp->AssociatedIrp.SystemBuffer;
8543 FileObject = RxContext->CurrentIrpSp->FileObject;
8544
8545 /* If caller provided flags, handle the change */
8546 Attributes = BasicInfo->FileAttributes;
8547 if (Attributes != 0)
8548 {
8549 /* Clean our flags first, with only stuff we support */
8550 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
8551 {
8552 CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY;
8553 }
8554 else
8555 {
8556 CleanAttr = Attributes & VALID_FILE_ATTRIBUTES;
8557 }
8558
8559 /* Handle the temporary mark (set/unset depending on caller) */
8560 if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY))
8561 {
8562 SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8563 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8564 }
8565 else
8566 {
8567 ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
8568 ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
8569 }
8570
8571 /* And set new attributes */
8572 Fcb->Attributes = CleanAttr;
8573 }
8574
8575 /* If caller provided a creation time, set it */
8576 if (BasicInfo->CreationTime.QuadPart != 0LL)
8577 {
8578 Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
8579 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION);
8580 }
8581
8582 /* If caller provided a last access time, set it */
8583 if (BasicInfo->LastAccessTime.QuadPart != 0LL)
8584 {
8585 Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
8586 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS);
8587 }
8588
8589 /* If caller provided a last write time, set it */
8590 if (BasicInfo->LastWriteTime.QuadPart != 0LL)
8591 {
8592 Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
8593 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
8594 }
8595
8596 /* If caller provided a last change time, set it */
8597 if (BasicInfo->ChangeTime.QuadPart != 0LL)
8598 {
8599 Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
8600 SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
8601 }
8602 }
8603
8604 /* Done */
8605 return Status;
8606 }
8607
8608 NTSTATUS
8609 RxSetDispositionInfo(
8610 PRX_CONTEXT RxContext)
8611 {
8612 UNIMPLEMENTED;
8613 return STATUS_NOT_IMPLEMENTED;
8614 }
8615
8616 NTSTATUS
8617 RxSetEndOfFileInfo(
8618 PRX_CONTEXT RxContext)
8619 {
8620 UNIMPLEMENTED;
8621 return STATUS_NOT_IMPLEMENTED;
8622 }
8623
8624 NTSTATUS
8625 RxSetPipeInfo(
8626 PRX_CONTEXT RxContext)
8627 {
8628 UNIMPLEMENTED;
8629 return STATUS_NOT_IMPLEMENTED;
8630 }
8631
8632 NTSTATUS
8633 RxSetPositionInfo(
8634 PRX_CONTEXT RxContext)
8635 {
8636 UNIMPLEMENTED;
8637 return STATUS_NOT_IMPLEMENTED;
8638 }
8639
8640 NTSTATUS
8641 RxSetRenameInfo(
8642 PRX_CONTEXT RxContext)
8643 {
8644 UNIMPLEMENTED;
8645 return STATUS_NOT_IMPLEMENTED;
8646 }
8647
8648 /*
8649 * @implemented
8650 */
8651 VOID
8652 RxSetShareAccess(
8653 _In_ ACCESS_MASK DesiredAccess,
8654 _In_ ULONG DesiredShareAccess,
8655 _Inout_ PFILE_OBJECT FileObject,
8656 _Out_ PSHARE_ACCESS ShareAccess,
8657 _In_ PSZ where,
8658 _In_ PSZ wherelogtag)
8659 {
8660 PAGED_CODE();
8661
8662 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8663 IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
8664 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8665 }
8666
8667 NTSTATUS
8668 RxSetSimpleInfo(
8669 PRX_CONTEXT RxContext)
8670 {
8671 UNIMPLEMENTED;
8672 return STATUS_NOT_IMPLEMENTED;
8673 }
8674
8675 /*
8676 * @implemented
8677 */
8678 VOID
8679 RxSetupNetFileObject(
8680 PRX_CONTEXT RxContext)
8681 {
8682 PFCB Fcb;
8683 PFOBX Fobx;
8684 PFILE_OBJECT FileObject;
8685 PIO_STACK_LOCATION Stack;
8686
8687 PAGED_CODE();
8688
8689 /* Assert FOBX is FOBX or NULL */
8690 Fobx = (PFOBX)RxContext->pFobx;
8691 ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
8692
8693 Fcb = (PFCB)RxContext->pFcb;
8694 Stack = RxContext->CurrentIrpSp;
8695 FileObject = Stack->FileObject;
8696 /* If it's temporary mark FO as such */
8697 if (Fcb != NULL && NodeType(Fcb) != RDBSS_NTC_VCB &&
8698 BooleanFlagOn(Fcb->FcbState, FCB_STATE_TEMPORARY))
8699 {
8700 if (FileObject == NULL)
8701 {
8702 return;
8703 }
8704
8705 FileObject->Flags |= FO_TEMPORARY_FILE;
8706 }
8707
8708 /* No FO, nothing to setup */
8709 if (FileObject == NULL)
8710 {
8711 return;
8712 }
8713
8714 /* Assign FCB & CCB (FOBX) to FO */
8715 FileObject->FsContext = Fcb;
8716 FileObject->FsContext2 = Fobx;
8717 if (Fobx != NULL)
8718 {
8719 ULONG_PTR StackTop, StackBottom;
8720
8721 /* If FO is allocated on pool, keep track of it */
8722 IoGetStackLimits(&StackTop, &StackBottom);
8723 if ((ULONG_PTR)FileObject <= StackBottom || (ULONG_PTR)FileObject >= StackTop)
8724 {
8725 Fobx->AssociatedFileObject = FileObject;
8726 }
8727 else
8728 {
8729 Fobx->AssociatedFileObject = NULL;
8730 }
8731
8732 /* Make sure to mark FOBX if it's a DFS open */
8733 if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))
8734 {
8735 SetFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8736 }
8737 else
8738 {
8739 ClearFlag(Fobx->Flags, FOBX_FLAG_DFS_OPEN);
8740 }
8741 }
8742
8743 /* Set Cc pointers */
8744 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
8745
8746 /* Update access state */
8747 if (Stack->Parameters.Create.SecurityContext != NULL)
8748 {
8749 PACCESS_STATE AccessState;
8750
8751 AccessState = Stack->Parameters.Create.SecurityContext->AccessState;
8752 AccessState->PreviouslyGrantedAccess |= AccessState->RemainingDesiredAccess;
8753 AccessState->RemainingDesiredAccess = 0;
8754 }
8755 }
8756
8757 /*
8758 * @implemented
8759 */
8760 NTSTATUS
8761 NTAPI
8762 RxStartMinirdr(
8763 IN PRX_CONTEXT RxContext,
8764 OUT PBOOLEAN PostToFsp)
8765 {
8766 NTSTATUS Status;
8767 BOOLEAN Wait, AlreadyStarted;
8768 PRDBSS_DEVICE_OBJECT DeviceObject;
8769
8770 /* If we've not been post, then, do it */
8771 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
8772 {
8773 SECURITY_SUBJECT_CONTEXT SubjectContext;
8774
8775 SeCaptureSubjectContext(&SubjectContext);
8776 RxContext->FsdUid = RxGetUid(&SubjectContext);
8777 SeReleaseSubjectContext(&SubjectContext);
8778
8779 *PostToFsp = TRUE;
8780 return STATUS_PENDING;
8781 }
8782
8783 /* Acquire all the required locks */
8784 Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
8785 if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait))
8786 {
8787 *PostToFsp = TRUE;
8788 return STATUS_PENDING;
8789 }
8790
8791 if (!RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, Wait))
8792 {
8793 ExReleaseResourceLite(&RxData.Resource);
8794 *PostToFsp = TRUE;
8795 return STATUS_PENDING;
8796 }
8797
8798 AlreadyStarted = FALSE;
8799 DeviceObject = RxContext->RxDeviceObject;
8800 _SEH2_TRY
8801 {
8802 /* MUP handle set, means already registered */
8803 if (DeviceObject->MupHandle != NULL)
8804 {
8805 AlreadyStarted = TRUE;
8806 Status = STATUS_REDIRECTOR_STARTED;
8807 _SEH2_LEAVE;
8808 }
8809
8810 /* If we're asked to register to MUP, then do it */
8811 Status = STATUS_SUCCESS;
8812 if (DeviceObject->RegisterUncProvider)
8813 {
8814 Status = FsRtlRegisterUncProvider(&DeviceObject->MupHandle,
8815 &DeviceObject->DeviceName,
8816 DeviceObject->RegisterMailSlotProvider);
8817 }
8818 if (!NT_SUCCESS(Status))
8819 {
8820 DeviceObject->MupHandle = NULL;
8821 _SEH2_LEAVE;
8822 }
8823
8824 /* Register as file system */
8825 IoRegisterFileSystem(&DeviceObject->DeviceObject);
8826 DeviceObject->RegisteredAsFileSystem = TRUE;
8827
8828 /* Inform mini-rdr it has to start */
8829 MINIRDR_CALL(Status, RxContext, DeviceObject->Dispatch, MRxStart, (RxContext, DeviceObject));
8830 if (NT_SUCCESS(Status))
8831 {
8832 ++DeviceObject->StartStopContext.Version;
8833 RxSetRdbssState(DeviceObject, RDBSS_STARTED);
8834 InterlockedExchangeAdd(&RxData.NumberOfMinirdrsStarted, 1);
8835
8836 Status = RxInitializeMRxDispatcher(DeviceObject);
8837 }
8838 }
8839 _SEH2_FINALLY
8840 {
8841 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Status))
8842 {
8843 if (!AlreadyStarted)
8844 {
8845 RxUnstart(RxContext, DeviceObject);
8846 }
8847 }
8848
8849 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
8850 ExReleaseResourceLite(&RxData.Resource);
8851 }
8852 _SEH2_END;
8853
8854 return Status;
8855 }
8856
8857 NTSTATUS
8858 NTAPI
8859 RxStopMinirdr(
8860 IN PRX_CONTEXT RxContext,
8861 OUT PBOOLEAN PostToFsp)
8862 {
8863 UNIMPLEMENTED;
8864 return STATUS_NOT_IMPLEMENTED;
8865 }
8866
8867 NTSTATUS
8868 RxSystemControl(
8869 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
8870 IN PIRP Irp)
8871 {
8872 UNIMPLEMENTED;
8873 return STATUS_NOT_IMPLEMENTED;
8874 }
8875
8876 /*
8877 * @implemented
8878 */
8879 BOOLEAN
8880 RxTryToBecomeTheTopLevelIrp(
8881 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
8882 IN PIRP Irp,
8883 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
8884 IN BOOLEAN ForceTopLevel
8885 )
8886 {
8887 BOOLEAN FromPool = FALSE;
8888
8889 PAGED_CODE();
8890
8891 /* If not top level, and not have to be, quit */
8892 if (IoGetTopLevelIrp() && !ForceTopLevel)
8893 {
8894 return FALSE;
8895 }
8896
8897 /* If not TLC provider, allocate one */
8898 if (TopLevelContext == NULL)
8899 {
8900 TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
8901 if (TopLevelContext == NULL)
8902 {
8903 return FALSE;
8904 }
8905
8906 FromPool = TRUE;
8907 }
8908
8909 /* Init it */
8910 __RxInitializeTopLevelIrpContext(TopLevelContext, Irp, RxDeviceObject, FromPool);
8911
8912 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
8913 if (FromPool)
8914 {
8915 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
8916 }
8917
8918 /* Make it top level IRP */
8919 IoSetTopLevelIrp((PIRP)TopLevelContext);
8920 return TRUE;
8921 }
8922
8923 /*
8924 * @implemented
8925 */
8926 VOID
8927 RxUpdateShareAccess(
8928 _Inout_ PFILE_OBJECT FileObject,
8929 _Inout_ PSHARE_ACCESS ShareAccess,
8930 _In_ PSZ where,
8931 _In_ PSZ wherelogtag)
8932 {
8933 PAGED_CODE();
8934
8935 RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
8936 IoUpdateShareAccess(FileObject, ShareAccess);
8937 RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
8938 }
8939
8940 /*
8941 * @implemented
8942 */
8943 VOID
8944 RxUninitializeCacheMap(
8945 PRX_CONTEXT RxContext,
8946 PFILE_OBJECT FileObject,
8947 PLARGE_INTEGER TruncateSize)
8948 {
8949 PFCB Fcb;
8950 NTSTATUS Status;
8951 CACHE_UNINITIALIZE_EVENT UninitEvent;
8952
8953 PAGED_CODE();
8954
8955 Fcb = FileObject->FsContext;
8956 ASSERT(NodeTypeIsFcb(Fcb));
8957 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
8958
8959 KeInitializeEvent(&UninitEvent.Event, SynchronizationEvent, FALSE);
8960 CcUninitializeCacheMap(FileObject, TruncateSize, &UninitEvent);
8961
8962 /* Always release the FCB before waiting for the uninit event */
8963 RxReleaseFcb(RxContext, Fcb);
8964
8965 KeWaitForSingleObject(&UninitEvent.Event, Executive, KernelMode, FALSE, NULL);
8966
8967 /* Re-acquire it afterwards */
8968 Status = RxAcquireExclusiveFcb(RxContext, Fcb);
8969 ASSERT(NT_SUCCESS(Status));
8970 }
8971
8972 VOID
8973 NTAPI
8974 RxUnload(
8975 IN PDRIVER_OBJECT DriverObject)
8976 {
8977 UNIMPLEMENTED;
8978 }
8979
8980 VOID
8981 NTAPI
8982 RxUnlockOperation(
8983 IN PVOID Context,
8984 IN PFILE_LOCK_INFO LockInfo)
8985 {
8986 UNIMPLEMENTED;
8987 }
8988
8989 VOID
8990 RxUnstart(
8991 PRX_CONTEXT Context,
8992 PRDBSS_DEVICE_OBJECT DeviceObject)
8993 {
8994 UNIMPLEMENTED;
8995 }
8996
8997 /*
8998 * @implemented
8999 */
9000 VOID
9001 RxUnwindTopLevelIrp(
9002 IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext)
9003 {
9004 DPRINT("RxUnwindTopLevelIrp(%p)\n", TopLevelContext);
9005
9006 /* No TLC provided? Ask the system for ours! */
9007 if (TopLevelContext == NULL)
9008 {
9009 TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
9010 if (TopLevelContext == NULL)
9011 {
9012 return;
9013 }
9014
9015 /* In that case, just assert it's really ours */
9016 ASSERT(RxIsThisAnRdbssTopLevelContext(TopLevelContext));
9017 ASSERT(BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL));
9018 }
9019
9020 ASSERT(TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE);
9021 ASSERT(TopLevelContext->Thread == PsGetCurrentThread());
9022 /* Restore the previous top level IRP */
9023 IoSetTopLevelIrp(TopLevelContext->Previous);
9024 /* If TLC was allocated from pool, remove it from list and release it */
9025 if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
9026 {
9027 RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
9028 RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
9029 }
9030 }
9031
9032 /*
9033 * @implemented
9034 */
9035 VOID
9036 RxUpdateShareAccessPerSrvOpens(
9037 IN PSRV_OPEN SrvOpen)
9038 {
9039 ACCESS_MASK DesiredAccess;
9040 BOOLEAN ReadAccess;
9041 BOOLEAN WriteAccess;
9042 BOOLEAN DeleteAccess;
9043
9044 PAGED_CODE();
9045
9046 /* If already updated, no need to continue */
9047 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED))
9048 {
9049 return;
9050 }
9051
9052 /* Check if any access wanted */
9053 DesiredAccess = SrvOpen->DesiredAccess;
9054 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
9055 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
9056 DeleteAccess = (DesiredAccess & DELETE) != 0;
9057
9058 /* In that case, update it */
9059 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
9060 {
9061 BOOLEAN SharedRead;
9062 BOOLEAN SharedWrite;
9063 BOOLEAN SharedDelete;
9064 ULONG DesiredShareAccess;
9065 PSHARE_ACCESS ShareAccess;
9066
9067 ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
9068 DesiredShareAccess = SrvOpen->ShareAccess;
9069
9070 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
9071 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
9072 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
9073
9074 ShareAccess->OpenCount++;
9075
9076 ShareAccess->Readers += ReadAccess;
9077 ShareAccess->Writers += WriteAccess;
9078 ShareAccess->Deleters += DeleteAccess;
9079 ShareAccess->SharedRead += SharedRead;
9080 ShareAccess->SharedWrite += SharedWrite;
9081 ShareAccess->SharedDelete += SharedDelete;
9082 }
9083
9084 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED);
9085 }
9086
9087 /*
9088 * @implemented
9089 */
9090 NTSTATUS
9091 RxXXXControlFileCallthru(
9092 PRX_CONTEXT Context)
9093 {
9094 NTSTATUS Status;
9095
9096 PAGED_CODE();
9097
9098 DPRINT("RxXXXControlFileCallthru(%p)\n", Context);
9099
9100 /* No dispatch table? Nothing to dispatch */
9101 if (Context->RxDeviceObject->Dispatch == NULL)
9102 {
9103 Context->pFobx = NULL;
9104 return STATUS_INVALID_DEVICE_REQUEST;
9105 }
9106
9107 /* Init the lowio context */
9108 Status = RxLowIoPopulateFsctlInfo(Context);
9109 if (!NT_SUCCESS(Status))
9110 {
9111 return Status;
9112 }
9113
9114 /* Check whether we're consistent: a length means a buffer */
9115 if ((Context->LowIoContext.ParamsFor.FsCtl.InputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pInputBuffer == NULL) ||
9116 (Context->LowIoContext.ParamsFor.FsCtl.OutputBufferLength > 0 && Context->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL))
9117 {
9118 return STATUS_INVALID_PARAMETER;
9119 }
9120
9121 /* Forward the call to the mini-rdr */
9122 DPRINT("Calling: %p\n", Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile);
9123 Status = Context->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile(Context);
9124 if (Status != STATUS_PENDING)
9125 {
9126 Context->CurrentIrp->IoStatus.Information = Context->InformationToReturn;
9127 }
9128
9129 DPRINT("RxXXXControlFileCallthru: %x, %ld\n", Context->CurrentIrp->IoStatus.Status, Context->CurrentIrp->IoStatus.Information);
9130 return Status;
9131 }