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