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