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