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