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