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