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