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