1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/fsrtl/fastio.c 5 * PURPOSE: Provides Fast I/O entrypoints to the Cache Manager 6 * PROGRAMMERS: Dominique Cote (buzdelabuz2@gmail.com) 7 * Alex Ionescu (alex.ionescu@reactos.org) 8 * Aleksey Bragin (aleksey@reactos.org) 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* PUBLIC FUNCTIONS **********************************************************/ 18 19 /* 20 * @implemented 21 */ 22 VOID 23 NTAPI 24 FsRtlIncrementCcFastReadResourceMiss(VOID) 25 { 26 CcFastReadResourceMiss++; 27 } 28 29 /* 30 * @implemented 31 */ 32 VOID 33 NTAPI 34 FsRtlIncrementCcFastReadNotPossible(VOID) 35 { 36 CcFastReadNotPossible++; 37 } 38 39 /* 40 * @implemented 41 */ 42 VOID 43 NTAPI 44 FsRtlIncrementCcFastReadWait(VOID) 45 { 46 CcFastReadWait++; 47 } 48 49 /* 50 * @implemented 51 */ 52 VOID 53 NTAPI 54 FsRtlIncrementCcFastReadNoWait(VOID) 55 { 56 CcFastReadNoWait++; 57 } 58 59 /* 60 * @implemented 61 */ 62 BOOLEAN 63 NTAPI 64 FsRtlCopyRead(IN PFILE_OBJECT FileObject, 65 IN PLARGE_INTEGER FileOffset, 66 IN ULONG Length, 67 IN BOOLEAN Wait, 68 IN ULONG LockKey, 69 OUT PVOID Buffer, 70 OUT PIO_STATUS_BLOCK IoStatus, 71 IN PDEVICE_OBJECT DeviceObject) 72 { 73 74 PFSRTL_COMMON_FCB_HEADER FcbHeader; 75 LARGE_INTEGER Offset; 76 PFAST_IO_DISPATCH FastIoDispatch; 77 PDEVICE_OBJECT Device; 78 BOOLEAN Result = TRUE; 79 ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset, Length); 80 81 PAGED_CODE(); 82 ASSERT(FileObject); 83 ASSERT(FileObject->FsContext); 84 85 /* No actual read */ 86 if (!Length) 87 { 88 /* Return success */ 89 IoStatus->Status = STATUS_SUCCESS; 90 IoStatus->Information = 0; 91 return TRUE; 92 } 93 94 if (Length > MAXLONGLONG - FileOffset->QuadPart) 95 { 96 IoStatus->Status = STATUS_INVALID_PARAMETER; 97 IoStatus->Information = 0; 98 return FALSE; 99 } 100 101 /* Get the offset and FCB header */ 102 Offset.QuadPart = FileOffset->QuadPart + Length; 103 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 104 105 if (Wait) 106 { 107 /* Use a Resource Acquire */ 108 FsRtlEnterFileSystem(); 109 CcFastReadWait++; 110 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); 111 } 112 else 113 { 114 /* Acquire the resource without blocking. Return false and the I/O manager 115 * will retry using the standard IRP method. Use a Resource Acquire. 116 */ 117 FsRtlEnterFileSystem(); 118 if (!ExAcquireResourceSharedLite(FcbHeader->Resource, FALSE)) 119 { 120 FsRtlExitFileSystem(); 121 FsRtlIncrementCcFastReadResourceMiss(); 122 return FALSE; 123 } 124 } 125 126 /* Check if this is a fast I/O cached file */ 127 if (!(FileObject->PrivateCacheMap) || 128 (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) 129 { 130 /* It's not, so fail */ 131 Result = FALSE; 132 goto Cleanup; 133 } 134 135 /* Check if we need to find out if fast I/O is available */ 136 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) 137 { 138 /* Sanity check */ 139 ASSERT(!KeIsExecutingDpc()); 140 141 /* Get the Fast I/O table */ 142 Device = IoGetRelatedDeviceObject(FileObject); 143 FastIoDispatch = Device->DriverObject->FastIoDispatch; 144 145 /* Sanity check */ 146 ASSERT(FastIoDispatch != NULL); 147 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 148 149 /* Ask the driver if we can do it */ 150 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, 151 FileOffset, 152 Length, 153 TRUE, 154 LockKey, 155 TRUE, 156 IoStatus, 157 Device)) 158 { 159 /* It's not, fail */ 160 Result = FALSE; 161 goto Cleanup; 162 } 163 } 164 165 /* Check if we read too much */ 166 if (Offset.QuadPart > FcbHeader->FileSize.QuadPart) 167 { 168 /* We did, check if the file offset is past the end */ 169 if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart) 170 { 171 /* Set end of file */ 172 IoStatus->Status = STATUS_END_OF_FILE; 173 IoStatus->Information = 0; 174 goto Cleanup; 175 } 176 177 /* Otherwise, just normalize the length */ 178 Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); 179 } 180 181 /* Set this as top-level IRP */ 182 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 183 184 _SEH2_TRY 185 { 186 /* Make sure the IO and file size is below 4GB */ 187 if (Wait && !(Offset.HighPart | FcbHeader->FileSize.HighPart)) 188 { 189 190 /* Call the cache controller */ 191 CcFastCopyRead(FileObject, 192 FileOffset->LowPart, 193 Length, 194 PageCount, 195 Buffer, 196 IoStatus); 197 198 /* File was accessed */ 199 FileObject->Flags |= FO_FILE_FAST_IO_READ; 200 201 if (IoStatus->Status != STATUS_END_OF_FILE) 202 { 203 ASSERT((ULONGLONG)FcbHeader->FileSize.QuadPart >= 204 ((ULONGLONG)FileOffset->QuadPart + IoStatus->Information)); 205 } 206 } 207 else 208 { 209 210 /* Call the cache controller */ 211 Result = CcCopyRead(FileObject, 212 FileOffset, 213 Length, 214 Wait, 215 Buffer, 216 IoStatus); 217 218 /* File was accessed */ 219 FileObject->Flags |= FO_FILE_FAST_IO_READ; 220 221 if (Result != FALSE) 222 { 223 ASSERT((IoStatus->Status == STATUS_END_OF_FILE) || 224 (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= 225 (ULONGLONG)FcbHeader->FileSize.QuadPart)); 226 } 227 } 228 229 /* Update the current file offset */ 230 if (Result != FALSE) 231 { 232 FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information; 233 } 234 } 235 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 236 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 237 { 238 Result = FALSE; 239 } 240 _SEH2_END; 241 242 PsGetCurrentThread()->TopLevelIrp = 0; 243 244 /* Return to caller */ 245 Cleanup: 246 247 ExReleaseResourceLite(FcbHeader->Resource); 248 FsRtlExitFileSystem(); 249 250 if (Result == FALSE) 251 { 252 CcFastReadNotPossible += 1; 253 } 254 255 return Result; 256 } 257 258 259 /* 260 * @implemented 261 */ 262 BOOLEAN 263 NTAPI 264 FsRtlCopyWrite(IN PFILE_OBJECT FileObject, 265 IN PLARGE_INTEGER FileOffset, 266 IN ULONG Length, 267 IN BOOLEAN Wait, 268 IN ULONG LockKey, 269 OUT PVOID Buffer, 270 OUT PIO_STATUS_BLOCK IoStatus, 271 IN PDEVICE_OBJECT DeviceObject) 272 { 273 BOOLEAN Result = TRUE; 274 PFAST_IO_DISPATCH FastIoDispatch; 275 PDEVICE_OBJECT Device; 276 PFSRTL_COMMON_FCB_HEADER FcbHeader; 277 PSHARED_CACHE_MAP SharedCacheMap; 278 279 /* WDK doc. 280 * Offset == 0xffffffffffffffff indicates append to the end of file. 281 */ 282 BOOLEAN FileOffsetAppend = (FileOffset->HighPart == (LONG)0xffffffff) && 283 (FileOffset->LowPart == 0xffffffff); 284 285 BOOLEAN ResourceAcquiredShared = FALSE; 286 BOOLEAN b_4GB = FALSE; 287 BOOLEAN FileSizeModified = FALSE; 288 LARGE_INTEGER OldFileSize; 289 LARGE_INTEGER OldValidDataLength; 290 LARGE_INTEGER NewSize; 291 LARGE_INTEGER Offset; 292 293 PAGED_CODE(); 294 295 ASSERT(FileObject); 296 ASSERT(FileObject->FsContext); 297 298 /* Initialize some of the vars and pointers */ 299 NewSize.QuadPart = 0; 300 Offset.QuadPart = FileOffset->QuadPart + Length; 301 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 302 303 /* Nagar p.544. 304 * Check with Cc if we can write and check if the IO > 64kB (WDK macro). 305 */ 306 if ((CcCanIWrite(FileObject, Length, Wait, FALSE) == FALSE) || 307 (CcCopyWriteWontFlush(FileObject, FileOffset, Length) == FALSE) || 308 ((FileObject->Flags & FO_WRITE_THROUGH))) 309 { 310 return FALSE; 311 } 312 313 /* Already init IO_STATUS_BLOCK */ 314 IoStatus->Status = STATUS_SUCCESS; 315 IoStatus->Information = Length; 316 317 /* No actual read */ 318 if (!Length) 319 { 320 return TRUE; 321 } 322 323 FsRtlEnterFileSystem(); 324 325 /* Nagar p.544/545. 326 * The CcFastCopyWrite doesn't deal with filesize beyond 4GB. 327 */ 328 if (Wait && (FcbHeader->AllocationSize.HighPart == 0)) 329 { 330 /* If the file offset is not past the file size, 331 * then we can acquire the lock shared. 332 */ 333 if ((FileOffsetAppend == FALSE) && 334 (Offset.LowPart <= FcbHeader->ValidDataLength.LowPart)) 335 { 336 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); 337 ResourceAcquiredShared = TRUE; 338 } 339 else 340 { 341 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 342 } 343 344 /* Nagar p.544/545. 345 * If we append, use the file size as offset. 346 * Also, check that we aren't crossing the 4GB boundary. 347 */ 348 if (FileOffsetAppend != FALSE) 349 { 350 Offset.LowPart = FcbHeader->FileSize.LowPart; 351 NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; 352 b_4GB = (NewSize.LowPart < FcbHeader->FileSize.LowPart); 353 354 } 355 else 356 { 357 Offset.LowPart = FileOffset->LowPart; 358 NewSize.LowPart = FileOffset->LowPart + Length; 359 b_4GB = (NewSize.LowPart < FileOffset->LowPart) || 360 (FileOffset->HighPart != 0); 361 } 362 363 /* Nagar p.544/545. 364 * Make sure that caching is initated. 365 * That fast are allowed for this file stream. 366 * That we are not extending past the allocated size. 367 * That we are not creating a hole bigger than 8k. 368 * That we are not crossing the 4GB boundary. 369 */ 370 if ((FileObject->PrivateCacheMap != NULL) && 371 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && 372 (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && 373 (Offset.LowPart < FcbHeader->ValidDataLength.LowPart + 0x2000) && 374 !b_4GB) 375 { 376 /* If we are extending past the file size, we need to 377 * release the lock and acquire it exclusively, because 378 * we are going to need to update the FcbHeader. 379 */ 380 if (ResourceAcquiredShared && 381 (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart + 0x2000)) 382 { 383 /* Then we need to acquire the resource exclusive */ 384 ExReleaseResourceLite(FcbHeader->Resource); 385 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 386 if (FileOffsetAppend != FALSE) 387 { 388 Offset.LowPart = FcbHeader->FileSize.LowPart; // ?? 389 NewSize.LowPart = FcbHeader->FileSize.LowPart + Length; 390 391 /* Make sure we don't cross the 4GB boundary */ 392 b_4GB = (NewSize.LowPart < Offset.LowPart); 393 } 394 395 /* Recheck some of the conditions since we let the lock go */ 396 if ((FileObject->PrivateCacheMap != NULL) && 397 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && 398 (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) && 399 (FcbHeader->AllocationSize.HighPart == 0) && 400 !b_4GB) 401 { 402 /* Do nothing? */ 403 } 404 else 405 { 406 goto FailAndCleanup; 407 } 408 } 409 410 } 411 else 412 { 413 goto FailAndCleanup; 414 } 415 416 /* Check if we need to find out if fast I/O is available */ 417 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) 418 { 419 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; 420 421 /* Sanity check */ 422 ASSERT(!KeIsExecutingDpc()); 423 424 /* Get the Fast I/O table */ 425 Device = IoGetRelatedDeviceObject(FileObject); 426 FastIoDispatch = Device->DriverObject->FastIoDispatch; 427 428 /* Sanity check */ 429 ASSERT(FastIoDispatch != NULL); 430 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 431 432 /* Ask the driver if we can do it */ 433 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, 434 FileOffsetAppend ? 435 &FcbHeader->FileSize : 436 FileOffset, 437 Length, 438 TRUE, 439 LockKey, 440 FALSE, 441 &FastIoCheckIfPossibleStatus, 442 Device)) 443 { 444 /* It's not, fail */ 445 goto FailAndCleanup; 446 } 447 } 448 449 /* If we are going to extend the file then save 450 * the old file size in case the operation fails. 451 */ 452 if (NewSize.LowPart > FcbHeader->FileSize.LowPart) 453 { 454 FileSizeModified = TRUE; 455 OldFileSize.LowPart = FcbHeader->FileSize.LowPart; 456 OldValidDataLength.LowPart = FcbHeader->ValidDataLength.LowPart; 457 FcbHeader->FileSize.LowPart = NewSize.LowPart; 458 } 459 460 /* Set this as top-level IRP */ 461 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 462 463 _SEH2_TRY 464 { 465 if (Offset.LowPart > FcbHeader->ValidDataLength.LowPart) 466 { 467 LARGE_INTEGER OffsetVar; 468 OffsetVar.LowPart = Offset.LowPart; 469 OffsetVar.HighPart = 0; 470 CcZeroData(FileObject, &FcbHeader->ValidDataLength, &OffsetVar, TRUE); 471 } 472 473 /* Call the cache manager */ 474 CcFastCopyWrite(FileObject, Offset.LowPart, Length, Buffer); 475 } 476 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 477 EXCEPTION_EXECUTE_HANDLER : 478 EXCEPTION_CONTINUE_SEARCH) 479 { 480 Result = FALSE; 481 } 482 _SEH2_END; 483 484 /* Remove ourselves at the top level component after the IO is done */ 485 PsGetCurrentThread()->TopLevelIrp = 0; 486 487 /* Did the operation succeed? */ 488 if (Result != FALSE) 489 { 490 /* Update the valid file size if necessary */ 491 if (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart) 492 { 493 FcbHeader->ValidDataLength.LowPart = NewSize.LowPart; 494 } 495 496 /* Flag the file as modified */ 497 FileObject->Flags |= FO_FILE_MODIFIED; 498 499 /* Update the strucutres if the file size changed */ 500 if (FileSizeModified) 501 { 502 SharedCacheMap = 503 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; 504 SharedCacheMap->FileSize.LowPart = NewSize.LowPart; 505 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 506 } 507 508 /* Update the file object current file offset */ 509 FileObject->CurrentByteOffset.QuadPart = NewSize.LowPart; 510 511 } 512 else 513 { 514 /* Result == FALSE if we get here */ 515 if (FileSizeModified) 516 { 517 /* If the file size was modified then restore the old file size */ 518 if (FcbHeader->PagingIoResource != NULL) 519 { 520 /* Nagar P.544. 521 * Restore the old file size if operation didn't succeed. 522 */ 523 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 524 FcbHeader->FileSize.LowPart = OldFileSize.LowPart; 525 FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; 526 ExReleaseResourceLite(FcbHeader->PagingIoResource); 527 } 528 else 529 { 530 /* If there is no lock and do it without */ 531 FcbHeader->FileSize.LowPart = OldFileSize.LowPart; 532 FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart; 533 } 534 } 535 else 536 { 537 /* Do nothing? */ 538 } 539 } 540 541 goto Cleanup; 542 } 543 else 544 { 545 LARGE_INTEGER OldFileSize; 546 547 /* Sanity check */ 548 ASSERT(!KeIsExecutingDpc()); 549 550 /* Nagar P.544. 551 * Check if we need to acquire the resource exclusive. 552 */ 553 if ((FileOffsetAppend == FALSE) && 554 (FileOffset->QuadPart + Length <= FcbHeader->ValidDataLength.QuadPart)) 555 { 556 /* Acquire the resource shared */ 557 if (!ExAcquireResourceSharedLite(FcbHeader->Resource, Wait)) 558 { 559 goto LeaveCriticalAndFail; 560 } 561 ResourceAcquiredShared = TRUE; 562 } 563 else 564 { 565 /* Acquire the resource exclusive */ 566 if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource, Wait)) 567 { 568 goto LeaveCriticalAndFail; 569 } 570 } 571 572 /* Check if we are appending */ 573 if (FileOffsetAppend != FALSE) 574 { 575 Offset.QuadPart = FcbHeader->FileSize.QuadPart; 576 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; 577 } 578 else 579 { 580 Offset.QuadPart = FileOffset->QuadPart; 581 NewSize.QuadPart += FileOffset->QuadPart + Length; 582 } 583 584 /* Nagar p.544/545. 585 * Make sure that caching is initated. 586 * That fast are allowed for this file stream. 587 * That we are not extending past the allocated size. 588 * That we are not creating a hole bigger than 8k. 589 */ 590 if ((FileObject->PrivateCacheMap != NULL) && 591 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && 592 (FcbHeader->ValidDataLength.QuadPart + 0x2000 > Offset.QuadPart) && 593 (Length <= MAXLONGLONG - Offset.QuadPart) && 594 (FcbHeader->AllocationSize.QuadPart >= NewSize.QuadPart)) 595 { 596 /* Check if we can keep the lock shared */ 597 if (ResourceAcquiredShared && 598 (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart)) 599 { 600 ExReleaseResourceLite(FcbHeader->Resource); 601 if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource, Wait)) 602 { 603 goto LeaveCriticalAndFail; 604 } 605 606 /* Compute the offset and the new filesize */ 607 if (FileOffsetAppend) 608 { 609 Offset.QuadPart = FcbHeader->FileSize.QuadPart; 610 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; 611 } 612 613 /* Recheck the above points since we released and reacquire the lock */ 614 if ((FileObject->PrivateCacheMap != NULL) && 615 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && 616 (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart)) 617 { 618 /* Do nothing */ 619 } 620 else 621 { 622 goto FailAndCleanup; 623 } 624 } 625 626 /* Check if we need to find out if fast I/O is available */ 627 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) 628 { 629 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus; 630 631 /* Sanity check */ 632 ASSERT(!KeIsExecutingDpc()); 633 634 /* Get the Fast I/O table */ 635 Device = IoGetRelatedDeviceObject(FileObject); 636 FastIoDispatch = Device->DriverObject->FastIoDispatch; 637 638 /* Sanity check */ 639 ASSERT(FastIoDispatch != NULL); 640 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 641 642 /* Ask the driver if we can do it */ 643 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, 644 FileOffsetAppend ? 645 &FcbHeader->FileSize : 646 FileOffset, 647 Length, 648 Wait, 649 LockKey, 650 FALSE, 651 &FastIoCheckIfPossibleStatus, 652 Device)) 653 { 654 /* It's not, fail */ 655 goto FailAndCleanup; 656 } 657 } 658 659 /* If we are going to modify the filesize, 660 * save the old fs in case the operation fails. 661 */ 662 if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) 663 { 664 FileSizeModified = TRUE; 665 OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; 666 OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; 667 668 /* If the high part of the filesize is going 669 * to change, grab the Paging IoResouce. 670 */ 671 if (NewSize.HighPart != FcbHeader->FileSize.HighPart && 672 FcbHeader->PagingIoResource) 673 { 674 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 675 FcbHeader->FileSize.QuadPart = NewSize.QuadPart; 676 ExReleaseResourceLite(FcbHeader->PagingIoResource); 677 } 678 else 679 { 680 FcbHeader->FileSize.QuadPart = NewSize.QuadPart; 681 } 682 } 683 684 /* Nagar p.544. 685 * Set ourselves as top component. 686 */ 687 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 688 689 _SEH2_TRY 690 { 691 BOOLEAN CallCc = TRUE; 692 693 /* Check if there is a gap between the end of the file 694 * and the offset. If yes, then we have to zero the data. 695 */ 696 if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) 697 { 698 if (!(Result = CcZeroData(FileObject, 699 &FcbHeader->ValidDataLength, 700 &Offset, 701 Wait))) 702 { 703 /* If this operation fails, then we have to exit. We can't jump 704 * outside the SEH, so I am using a variable to exit normally. 705 */ 706 CallCc = FALSE; 707 } 708 } 709 710 /* Unless the CcZeroData failed, call the cache manager */ 711 if (CallCc) 712 { 713 Result = CcCopyWrite(FileObject, &Offset, Length, Wait, Buffer); 714 } 715 } 716 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 717 EXCEPTION_EXECUTE_HANDLER : 718 EXCEPTION_CONTINUE_SEARCH) 719 { 720 Result = FALSE; 721 } 722 _SEH2_END; 723 724 /* Reset the top component */ 725 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 726 727 /* Did the operation suceeded */ 728 if (Result) 729 { 730 /* Check if we need to update the filesize */ 731 if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) 732 { 733 if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && 734 FcbHeader->PagingIoResource) 735 { 736 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 737 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; 738 ExReleaseResourceLite(FcbHeader->PagingIoResource); 739 } 740 else 741 { 742 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; 743 } 744 } 745 746 /* Flag the file as modified */ 747 FileObject->Flags |= FO_FILE_MODIFIED; 748 749 /* Check if the filesize has changed */ 750 if (FileSizeModified) 751 { 752 /* Update the file sizes */ 753 SharedCacheMap = 754 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; 755 SharedCacheMap->FileSize.QuadPart = NewSize.QuadPart; 756 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 757 } 758 759 /* Update the current FO byte offset */ 760 FileObject->CurrentByteOffset.QuadPart = NewSize.QuadPart; 761 } 762 else 763 { 764 /* The operation did not succeed. 765 * Reset the file size to what it should be. 766 */ 767 if (FileSizeModified) 768 { 769 if (FcbHeader->PagingIoResource) 770 { 771 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 772 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; 773 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; 774 ExReleaseResourceLite(FcbHeader->PagingIoResource); 775 } 776 else 777 { 778 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; 779 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; 780 } 781 } 782 } 783 784 goto Cleanup; 785 } 786 else 787 { 788 goto FailAndCleanup; 789 } 790 } 791 792 LeaveCriticalAndFail: 793 794 FsRtlExitFileSystem(); 795 return FALSE; 796 797 FailAndCleanup: 798 799 ExReleaseResourceLite(FcbHeader->Resource); 800 FsRtlExitFileSystem(); 801 return FALSE; 802 803 Cleanup: 804 805 ExReleaseResourceLite(FcbHeader->Resource); 806 FsRtlExitFileSystem(); 807 return Result; 808 } 809 810 /* 811 * @implemented 812 */ 813 NTSTATUS 814 NTAPI 815 FsRtlGetFileSize(IN PFILE_OBJECT FileObject, 816 IN OUT PLARGE_INTEGER FileSize) 817 { 818 FILE_STANDARD_INFORMATION Info; 819 NTSTATUS Status; 820 IO_STATUS_BLOCK IoStatus; 821 PDEVICE_OBJECT DeviceObject; 822 PFAST_IO_DISPATCH FastDispatch; 823 KEVENT Event; 824 PIO_STACK_LOCATION IoStackLocation; 825 PIRP Irp; 826 BOOLEAN OldHardError; 827 828 PAGED_CODE(); 829 830 /* Get Device Object and Fast Calls */ 831 DeviceObject = IoGetRelatedDeviceObject(FileObject); 832 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 833 834 /* Check if we support Fast Calls, and check FastIoQueryStandardInfo. 835 * Call the function and see if it succeeds. 836 */ 837 if (!FastDispatch || 838 !FastDispatch->FastIoQueryStandardInfo || 839 !FastDispatch->FastIoQueryStandardInfo(FileObject, 840 TRUE, 841 &Info, 842 &IoStatus, 843 DeviceObject)) 844 { 845 /* If any of the above failed, then we are going to send an 846 * IRP to the device object. Initialize the event for the IO. 847 */ 848 KeInitializeEvent(&Event, NotificationEvent, FALSE); 849 850 /* Allocate the IRP */ 851 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 852 853 if (Irp == NULL) 854 { 855 return STATUS_INSUFFICIENT_RESOURCES; 856 } 857 858 /* Don't process hard error */ 859 OldHardError = IoSetThreadHardErrorMode(FALSE); 860 861 /* Setup the IRP */ 862 Irp->UserIosb = &IoStatus; 863 Irp->UserEvent = &Event; 864 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 865 Irp->Flags = IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO; 866 Irp->RequestorMode = KernelMode; 867 Irp->Tail.Overlay.OriginalFileObject = FileObject; 868 Irp->AssociatedIrp.SystemBuffer = &Info; 869 870 /* Setup out stack location */ 871 IoStackLocation = Irp->Tail.Overlay.CurrentStackLocation; 872 IoStackLocation--; 873 IoStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION; 874 IoStackLocation->FileObject = FileObject; 875 IoStackLocation->DeviceObject = DeviceObject; 876 IoStackLocation->Parameters.QueryFile.Length = 877 sizeof(FILE_STANDARD_INFORMATION); 878 IoStackLocation->Parameters.QueryFile.FileInformationClass = 879 FileStandardInformation; 880 881 /* Send the IRP to the related device object */ 882 Status = IoCallDriver(DeviceObject, Irp); 883 884 /* Standard DDK IRP result processing */ 885 if (Status == STATUS_PENDING) 886 { 887 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 888 } 889 890 /* If there was a synchronous error, signal it */ 891 if (!NT_SUCCESS(Status)) 892 { 893 IoStatus.Status = Status; 894 } 895 896 IoSetThreadHardErrorMode(OldHardError); 897 } 898 899 /* Check the sync/async IO result */ 900 if (NT_SUCCESS(IoStatus.Status)) 901 { 902 /* Was the request for a directory? */ 903 if (Info.Directory) 904 { 905 IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY; 906 } 907 else 908 { 909 FileSize->QuadPart = Info.EndOfFile.QuadPart; 910 } 911 } 912 913 return IoStatus.Status; 914 } 915 916 /* 917 * @implemented 918 */ 919 BOOLEAN 920 NTAPI 921 FsRtlMdlRead(IN PFILE_OBJECT FileObject, 922 IN PLARGE_INTEGER FileOffset, 923 IN ULONG Length, 924 IN ULONG LockKey, 925 OUT PMDL *MdlChain, 926 OUT PIO_STATUS_BLOCK IoStatus) 927 { 928 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 929 PFAST_IO_DISPATCH FastDispatch; 930 931 /* Get Device Object and Fast Calls */ 932 DeviceObject = IoGetRelatedDeviceObject(FileObject); 933 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 934 935 /* Check if we support Fast Calls, and check this one */ 936 if (FastDispatch && FastDispatch->MdlRead) 937 { 938 /* Use the fast path */ 939 return FastDispatch->MdlRead(FileObject, 940 FileOffset, 941 Length, 942 LockKey, 943 MdlChain, 944 IoStatus, 945 DeviceObject); 946 } 947 948 /* Get the Base File System (Volume) and Fast Calls */ 949 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 950 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; 951 952 /* If the Base Device Object has its own FastDispatch Routine, fail */ 953 if (FastDispatch && FastDispatch->MdlRead && BaseDeviceObject != DeviceObject) 954 { 955 return FALSE; 956 } 957 958 /* No fast path, use slow path */ 959 return FsRtlMdlReadDev(FileObject, 960 FileOffset, 961 Length, 962 LockKey, 963 MdlChain, 964 IoStatus, 965 DeviceObject); 966 } 967 968 /* 969 * @implemented 970 */ 971 BOOLEAN 972 NTAPI 973 FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject, 974 IN OUT PMDL MdlChain) 975 { 976 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 977 PFAST_IO_DISPATCH FastDispatch; 978 979 /* Get Device Object and Fast Calls */ 980 DeviceObject = IoGetRelatedDeviceObject(FileObject); 981 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 982 983 /* Check if we support Fast Calls, and check this one */ 984 if (FastDispatch && FastDispatch->MdlReadComplete) 985 { 986 /* Use the fast path */ 987 return FastDispatch->MdlReadComplete(FileObject, MdlChain, DeviceObject); 988 } 989 990 /* Get the Base File System (Volume) and Fast Calls */ 991 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 992 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; 993 994 /* If the Base Device Object has its own FastDispatch Routine, fail */ 995 if ((BaseDeviceObject != DeviceObject) && 996 FastDispatch && 997 FastDispatch->MdlReadComplete) 998 { 999 return FALSE; 1000 } 1001 1002 /* No fast path, use slow path */ 1003 return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject); 1004 } 1005 1006 /* 1007 * @implemented 1008 */ 1009 BOOLEAN 1010 NTAPI 1011 FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject, 1012 IN PMDL MemoryDescriptorList, 1013 IN PDEVICE_OBJECT DeviceObject) 1014 { 1015 /* Call the Cache Manager */ 1016 CcMdlReadComplete2(FileObject, MemoryDescriptorList); 1017 return TRUE; 1018 } 1019 1020 /* 1021 * @implemented 1022 */ 1023 BOOLEAN 1024 NTAPI 1025 FsRtlMdlReadDev(IN PFILE_OBJECT FileObject, 1026 IN PLARGE_INTEGER FileOffset, 1027 IN ULONG Length, 1028 IN ULONG LockKey, 1029 OUT PMDL *MdlChain, 1030 OUT PIO_STATUS_BLOCK IoStatus, 1031 IN PDEVICE_OBJECT DeviceObject) 1032 { 1033 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1034 BOOLEAN Result = TRUE; 1035 LARGE_INTEGER Offset; 1036 PFAST_IO_DISPATCH FastIoDispatch; 1037 PDEVICE_OBJECT Device; 1038 PAGED_CODE(); 1039 1040 /* No actual read */ 1041 if (!Length) 1042 { 1043 /* Return success */ 1044 IoStatus->Status = STATUS_SUCCESS; 1045 IoStatus->Information = 0; 1046 return TRUE; 1047 } 1048 1049 /* Sanity check */ 1050 ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length); 1051 1052 /* Get the offset and FCB header */ 1053 Offset.QuadPart = FileOffset->QuadPart + Length; 1054 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1055 1056 /* Enter the FS */ 1057 FsRtlEnterFileSystem(); 1058 CcFastMdlReadWait++; 1059 1060 /* Lock the FCB */ 1061 ExAcquireResourceShared(FcbHeader->Resource, TRUE); 1062 1063 /* Check if this is a fast I/O cached file */ 1064 if (!(FileObject->PrivateCacheMap) || 1065 (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) 1066 { 1067 /* It's not, so fail */ 1068 CcFastMdlReadNotPossible += 1; 1069 Result = FALSE; 1070 goto Cleanup; 1071 } 1072 1073 /* Check if we need to find out if fast I/O is available */ 1074 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) 1075 { 1076 /* Get the Fast I/O table */ 1077 Device = IoGetRelatedDeviceObject(FileObject); 1078 FastIoDispatch = Device->DriverObject->FastIoDispatch; 1079 1080 /* Sanity check */ 1081 ASSERT(!KeIsExecutingDpc()); 1082 ASSERT(FastIoDispatch != NULL); 1083 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 1084 1085 /* Ask the driver if we can do it */ 1086 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, 1087 FileOffset, 1088 Length, 1089 TRUE, 1090 LockKey, 1091 TRUE, 1092 IoStatus, 1093 Device)) 1094 { 1095 /* It's not, fail */ 1096 CcFastMdlReadNotPossible += 1; 1097 Result = FALSE; 1098 goto Cleanup; 1099 } 1100 } 1101 1102 /* Check if we read too much */ 1103 if (Offset.QuadPart > FcbHeader->FileSize.QuadPart) 1104 { 1105 /* We did, check if the file offset is past the end */ 1106 if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart) 1107 { 1108 /* Set end of file */ 1109 IoStatus->Status = STATUS_END_OF_FILE; 1110 IoStatus->Information = 0; 1111 goto Cleanup; 1112 } 1113 1114 /* Otherwise, just normalize the length */ 1115 Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); 1116 } 1117 1118 /* Set this as top-level IRP */ 1119 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 1120 1121 _SEH2_TRY 1122 { 1123 /* Attempt a read */ 1124 CcMdlRead(FileObject, FileOffset, Length, MdlChain, IoStatus); 1125 FileObject->Flags |= FO_FILE_FAST_IO_READ; 1126 } 1127 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 1128 EXCEPTION_EXECUTE_HANDLER : 1129 EXCEPTION_CONTINUE_SEARCH) 1130 { 1131 Result = FALSE; 1132 } 1133 _SEH2_END; 1134 1135 1136 /* Remove the top-level IRP flag */ 1137 PsGetCurrentThread()->TopLevelIrp = 0; 1138 1139 /* Return to caller */ 1140 Cleanup: 1141 1142 ExReleaseResourceLite(FcbHeader->Resource); 1143 FsRtlExitFileSystem(); 1144 1145 return Result; 1146 } 1147 1148 /* 1149 * @implemented 1150 */ 1151 BOOLEAN 1152 NTAPI 1153 FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject, 1154 IN PLARGE_INTEGER FileOffset, 1155 IN PMDL MdlChain) 1156 { 1157 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1158 PFAST_IO_DISPATCH FastDispatch; 1159 1160 /* Get Device Object and Fast Calls */ 1161 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1162 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1163 1164 /* Check if we support Fast Calls, and check this one */ 1165 if (FastDispatch && FastDispatch->MdlWriteComplete) 1166 { 1167 /* Use the fast path */ 1168 return FastDispatch->MdlWriteComplete(FileObject, 1169 FileOffset, 1170 MdlChain, 1171 DeviceObject); 1172 } 1173 1174 /* Get the Base File System (Volume) and Fast Calls */ 1175 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1176 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; 1177 1178 /* If the Base Device Object has its own FastDispatch Routine, fail */ 1179 if (FastDispatch && 1180 FastDispatch->MdlWriteComplete && 1181 BaseDeviceObject != DeviceObject) 1182 { 1183 return FALSE; 1184 } 1185 1186 /* No fast path, use slow path */ 1187 return FsRtlMdlWriteCompleteDev(FileObject, 1188 FileOffset, 1189 MdlChain, 1190 DeviceObject); 1191 } 1192 1193 /* 1194 * @implemented 1195 */ 1196 BOOLEAN 1197 NTAPI 1198 FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject, 1199 IN PLARGE_INTEGER FileOffset, 1200 IN PMDL MdlChain, 1201 IN PDEVICE_OBJECT DeviceObject) 1202 { 1203 if (FileObject->Flags & FO_WRITE_THROUGH) 1204 { 1205 return FALSE; 1206 } 1207 1208 /* Call the Cache Manager */ 1209 CcMdlWriteComplete2(FileObject, FileOffset, MdlChain); 1210 return TRUE; 1211 } 1212 1213 /* 1214 * @implemented 1215 */ 1216 BOOLEAN 1217 NTAPI 1218 FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject, 1219 IN PLARGE_INTEGER FileOffset, 1220 IN ULONG Length, 1221 IN ULONG LockKey, 1222 OUT PMDL *MdlChain, 1223 OUT PIO_STATUS_BLOCK IoStatus) 1224 { 1225 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1226 PFAST_IO_DISPATCH FastDispatch; 1227 1228 /* Get Device Object and Fast Calls */ 1229 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1230 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1231 1232 /* Check if we support Fast Calls, and check this one */ 1233 if (FastDispatch && FastDispatch->PrepareMdlWrite) 1234 { 1235 /* Use the fast path */ 1236 return FastDispatch->PrepareMdlWrite(FileObject, 1237 FileOffset, 1238 Length, 1239 LockKey, 1240 MdlChain, 1241 IoStatus, 1242 DeviceObject); 1243 } 1244 1245 /* Get the Base File System (Volume) and Fast Calls */ 1246 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1247 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch; 1248 1249 /* If the Base Device Object has its own FastDispatch Routine, fail */ 1250 if (FastDispatch && 1251 FastDispatch->PrepareMdlWrite && 1252 BaseDeviceObject != DeviceObject) 1253 { 1254 return FALSE; 1255 } 1256 1257 /* No fast path, use slow path */ 1258 return FsRtlPrepareMdlWriteDev(FileObject, 1259 FileOffset, 1260 Length, 1261 LockKey, 1262 MdlChain, 1263 IoStatus, 1264 DeviceObject); 1265 } 1266 1267 /* 1268 * @implemented 1269 */ 1270 BOOLEAN 1271 NTAPI 1272 FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject, 1273 IN PLARGE_INTEGER FileOffset, 1274 IN ULONG Length, 1275 IN ULONG LockKey, 1276 OUT PMDL *MdlChain, 1277 OUT PIO_STATUS_BLOCK IoStatus, 1278 IN PDEVICE_OBJECT DeviceObject) 1279 { 1280 BOOLEAN Result = TRUE; 1281 PFAST_IO_DISPATCH FastIoDispatch; 1282 PDEVICE_OBJECT Device; 1283 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1284 PSHARED_CACHE_MAP SharedCacheMap; 1285 1286 LARGE_INTEGER OldFileSize; 1287 LARGE_INTEGER OldValidDataLength; 1288 LARGE_INTEGER NewSize; 1289 LARGE_INTEGER Offset; 1290 1291 /* WDK doc. 1292 * Offset == 0xffffffffffffffff indicates append to the end of file. 1293 */ 1294 BOOLEAN FileOffsetAppend = (FileOffset->HighPart == (LONG)0xffffffff) && 1295 (FileOffset->LowPart == 0xffffffff); 1296 1297 BOOLEAN FileSizeModified = FALSE; 1298 BOOLEAN ResourceAcquiredShared = FALSE; 1299 1300 /* Initialize some of the vars and pointers */ 1301 OldFileSize.QuadPart = 0; 1302 OldValidDataLength.QuadPart = 0; 1303 1304 PAGED_CODE(); 1305 1306 Offset.QuadPart = FileOffset->QuadPart + Length; 1307 1308 /* Nagar p.544. 1309 * Check with Cc if we can write. 1310 */ 1311 if (!CcCanIWrite(FileObject, Length, TRUE, FALSE) || 1312 (FileObject->Flags & FO_WRITE_THROUGH)) 1313 { 1314 return FALSE; 1315 } 1316 1317 IoStatus->Status = STATUS_SUCCESS; 1318 1319 /* No actual read */ 1320 if (!Length) 1321 { 1322 return TRUE; 1323 } 1324 1325 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1326 FsRtlEnterFileSystem(); 1327 1328 /* Check we are going to extend the file */ 1329 if ((FileOffsetAppend == FALSE) && 1330 (FileOffset->QuadPart + Length <= FcbHeader->ValidDataLength.QuadPart)) 1331 { 1332 /* Acquire the resource shared */ 1333 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); 1334 ResourceAcquiredShared = TRUE; 1335 } 1336 else 1337 { 1338 /* Acquire the resource exclusive */ 1339 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 1340 } 1341 1342 /* Check if we are appending */ 1343 if (FileOffsetAppend != FALSE) 1344 { 1345 Offset.QuadPart = FcbHeader->FileSize.QuadPart; 1346 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; 1347 } 1348 else 1349 { 1350 Offset.QuadPart = FileOffset->QuadPart; 1351 NewSize.QuadPart = FileOffset->QuadPart + Length; 1352 } 1353 1354 if ((FileObject->PrivateCacheMap) && 1355 (FcbHeader->IsFastIoPossible) && 1356 (Length <= MAXLONGLONG - FileOffset->QuadPart) && 1357 (NewSize.QuadPart <= FcbHeader->AllocationSize.QuadPart)) 1358 { 1359 /* Check if we can keep the lock shared */ 1360 if (ResourceAcquiredShared && 1361 (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart)) 1362 { 1363 ExReleaseResourceLite(FcbHeader->Resource); 1364 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 1365 1366 /* Compute the offset and the new filesize */ 1367 if (FileOffsetAppend) 1368 { 1369 Offset.QuadPart = FcbHeader->FileSize.QuadPart; 1370 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length; 1371 } 1372 1373 /* Recheck the above points since we released and reacquire the lock */ 1374 if ((FileObject->PrivateCacheMap != NULL) && 1375 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) && 1376 (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart)) 1377 { 1378 /* Do nothing */ 1379 } 1380 else 1381 { 1382 goto FailAndCleanup; 1383 } 1384 } 1385 1386 /* Check if we need to find out if fast I/O is available */ 1387 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) 1388 { 1389 /* Sanity check */ 1390 /* ASSERT(!KeIsExecutingDpc()); */ 1391 1392 /* Get the Fast I/O table */ 1393 Device = IoGetRelatedDeviceObject(FileObject); 1394 FastIoDispatch = Device->DriverObject->FastIoDispatch; 1395 1396 /* Sanity check */ 1397 ASSERT(FastIoDispatch != NULL); 1398 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 1399 1400 /* Ask the driver if we can do it */ 1401 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, 1402 FileOffset, 1403 Length, 1404 TRUE, 1405 LockKey, 1406 FALSE, 1407 IoStatus, 1408 Device)) 1409 { 1410 /* It's not, fail */ 1411 goto FailAndCleanup; 1412 } 1413 } 1414 1415 /* If we are going to modify the filesize, 1416 * save the old fs in case the operation fails. 1417 */ 1418 if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart) 1419 { 1420 FileSizeModified = TRUE; 1421 OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart; 1422 OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart; 1423 1424 /* If the high part of the filesize is going 1425 * to change, grab the Paging IoResouce. 1426 */ 1427 if (NewSize.HighPart != FcbHeader->FileSize.HighPart && 1428 FcbHeader->PagingIoResource) 1429 { 1430 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 1431 FcbHeader->FileSize.QuadPart = NewSize.QuadPart; 1432 ExReleaseResourceLite(FcbHeader->PagingIoResource); 1433 } 1434 else 1435 { 1436 FcbHeader->FileSize.QuadPart = NewSize.QuadPart; 1437 } 1438 } 1439 1440 1441 /* Nagar p.544. 1442 * Set ourselves as top component. 1443 */ 1444 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 1445 _SEH2_TRY 1446 { 1447 /* Check if there is a gap between the end of the file and the offset. 1448 * If yes, then we have to zero the data. 1449 */ 1450 if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart) 1451 { 1452 Result = CcZeroData(FileObject, 1453 &FcbHeader->ValidDataLength, 1454 &Offset, 1455 TRUE); 1456 if (Result) 1457 { 1458 CcPrepareMdlWrite(FileObject, 1459 &Offset, 1460 Length, 1461 MdlChain, 1462 IoStatus); 1463 } 1464 } 1465 else 1466 { 1467 CcPrepareMdlWrite(FileObject, &Offset, Length, MdlChain, IoStatus); 1468 } 1469 1470 } 1471 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 1472 EXCEPTION_EXECUTE_HANDLER : 1473 EXCEPTION_CONTINUE_SEARCH) 1474 { 1475 Result = FALSE; 1476 } 1477 _SEH2_END; 1478 1479 /* Reset the top component */ 1480 PsGetCurrentThread()->TopLevelIrp = 0; 1481 1482 /* Did the operation suceeded */ 1483 if (Result) 1484 { 1485 /* Check if we need to update the filesize */ 1486 if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart) 1487 { 1488 if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart && 1489 FcbHeader->PagingIoResource) 1490 { 1491 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 1492 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; 1493 ExReleaseResourceLite(FcbHeader->PagingIoResource); 1494 } 1495 else 1496 { 1497 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart; 1498 } 1499 } 1500 1501 /* Flag the file as modified */ 1502 FileObject->Flags |= FO_FILE_MODIFIED; 1503 1504 /* Check if the filesize has changed */ 1505 if (FileSizeModified) 1506 { 1507 SharedCacheMap = 1508 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; 1509 SharedCacheMap->FileSize.QuadPart = NewSize.QuadPart; 1510 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 1511 } 1512 } 1513 else 1514 { 1515 /* The operation did not succeed. 1516 * Reset the file size to what it should be. 1517 */ 1518 if (FileSizeModified) 1519 { 1520 if (FcbHeader->PagingIoResource) 1521 { 1522 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE); 1523 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; 1524 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; 1525 ExReleaseResourceLite(FcbHeader->PagingIoResource); 1526 } 1527 else 1528 { 1529 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart; 1530 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart; 1531 } 1532 } 1533 } 1534 1535 goto Cleanup; 1536 } 1537 else 1538 { 1539 goto FailAndCleanup; 1540 } 1541 1542 FailAndCleanup: 1543 1544 ExReleaseResourceLite(FcbHeader->Resource); 1545 FsRtlExitFileSystem(); 1546 return FALSE; 1547 1548 Cleanup: 1549 1550 ExReleaseResourceLite(FcbHeader->Resource); 1551 FsRtlExitFileSystem(); 1552 return Result; 1553 } 1554 1555 NTSTATUS 1556 NTAPI 1557 FsRtlAcquireFileExclusiveCommon(IN PFILE_OBJECT FileObject, 1558 IN FS_FILTER_SECTION_SYNC_TYPE SyncType, 1559 IN ULONG Reserved) 1560 { 1561 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1562 PDEVICE_OBJECT DeviceObject; 1563 PFAST_IO_DISPATCH FastDispatch; 1564 1565 /* Get Device Object and Fast Calls */ 1566 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1567 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1568 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1569 1570 /* Get master FsRtl lock */ 1571 FsRtlEnterFileSystem(); 1572 1573 /* Check if Fast Calls are supported, and check AcquireFileForNtCreateSection */ 1574 if (FastDispatch && 1575 FastDispatch->AcquireFileForNtCreateSection) 1576 { 1577 /* Call the AcquireFileForNtCreateSection FastIo handler */ 1578 FastDispatch->AcquireFileForNtCreateSection(FileObject); 1579 } 1580 else 1581 { 1582 /* No FastIo handler, acquire file's resource exclusively */ 1583 if (FcbHeader && FcbHeader->Resource) ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 1584 } 1585 1586 return STATUS_SUCCESS; 1587 } 1588 1589 /* 1590 * @implemented 1591 */ 1592 VOID 1593 NTAPI 1594 FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject) 1595 { 1596 PAGED_CODE(); 1597 1598 /* Call the common routine. Don't care about the result */ 1599 (VOID)FsRtlAcquireFileExclusiveCommon(FileObject, SyncTypeOther, 0); 1600 } 1601 1602 /* 1603 * @implemented 1604 */ 1605 VOID 1606 NTAPI 1607 FsRtlReleaseFile(IN PFILE_OBJECT FileObject) 1608 { 1609 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1610 PDEVICE_OBJECT DeviceObject; 1611 PFAST_IO_DISPATCH FastDispatch; 1612 1613 /* Get Device Object and Fast Calls */ 1614 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1615 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1616 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1617 1618 /* Check if Fast Calls are supported and check ReleaseFileForNtCreateSection */ 1619 if (FastDispatch && 1620 FastDispatch->ReleaseFileForNtCreateSection) 1621 { 1622 /* Call the ReleaseFileForNtCreateSection FastIo handler */ 1623 FastDispatch->ReleaseFileForNtCreateSection(FileObject); 1624 } 1625 else 1626 { 1627 /* No FastIo handler, release file's resource */ 1628 if (FcbHeader && FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource); 1629 } 1630 1631 /* Release master FsRtl lock */ 1632 FsRtlExitFileSystem(); 1633 } 1634 1635 /* 1636 * @implemented 1637 */ 1638 NTSTATUS 1639 NTAPI 1640 FsRtlAcquireFileForCcFlushEx(IN PFILE_OBJECT FileObject) 1641 { 1642 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1643 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1644 PFAST_IO_DISPATCH FastDispatch; 1645 NTSTATUS Status; 1646 1647 /* Get the Base File System (Volume) and Fast Calls */ 1648 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1649 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1650 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1651 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1652 1653 /* Get master FsRtl lock */ 1654 FsRtlEnterFileSystem(); 1655 1656 /* Check if Fast Calls are supported, and check AcquireForCcFlush */ 1657 if (FastDispatch && 1658 FastDispatch->AcquireForCcFlush) 1659 { 1660 /* Call the AcquireForCcFlush FastIo handler */ 1661 Status = FastDispatch->AcquireForCcFlush(FileObject, BaseDeviceObject); 1662 1663 /* Return either success or inability to wait. 1664 In case of other failure - fall through */ 1665 if (Status == STATUS_SUCCESS || 1666 Status == STATUS_CANT_WAIT) 1667 { 1668 return Status; 1669 } 1670 } 1671 1672 /* No FastIo handler (or it failed). Acquire Main resource */ 1673 if (FcbHeader->Resource) 1674 { 1675 /* Acquire it - either shared if it's already acquired 1676 or exclusively if we are the first */ 1677 if (ExIsResourceAcquiredSharedLite(FcbHeader->Resource)) 1678 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE); 1679 else 1680 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE); 1681 } 1682 1683 /* Also acquire its PagingIO resource */ 1684 if (FcbHeader->PagingIoResource) 1685 ExAcquireResourceSharedLite(FcbHeader->PagingIoResource, TRUE); 1686 1687 return STATUS_SUCCESS; 1688 } 1689 1690 /* 1691 * @implemented 1692 */ 1693 VOID 1694 NTAPI 1695 FsRtlAcquireFileForCcFlush(IN PFILE_OBJECT FileObject) 1696 { 1697 PAGED_CODE(); 1698 1699 /* Call the common routine. Don't care about the result */ 1700 (VOID)FsRtlAcquireFileForCcFlushEx(FileObject); 1701 } 1702 1703 1704 /* 1705 * @implemented 1706 */ 1707 VOID 1708 NTAPI 1709 FsRtlReleaseFileForCcFlush(IN PFILE_OBJECT FileObject) 1710 { 1711 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1712 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1713 PFAST_IO_DISPATCH FastDispatch; 1714 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; 1715 1716 /* Get Device Object and Fast Calls */ 1717 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1718 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1719 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1720 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1721 1722 /* Check if Fast Calls are supported, and check ReleaseForCcFlush */ 1723 if (FastDispatch && 1724 FastDispatch->ReleaseForCcFlush) 1725 { 1726 /* Call the ReleaseForCcFlush FastIo handler */ 1727 Status = FastDispatch->ReleaseForCcFlush(FileObject, BaseDeviceObject); 1728 } 1729 1730 if (!NT_SUCCESS(Status)) 1731 { 1732 /* No FastIo handler (or it failed). Release PagingIO resource and 1733 then Main resource */ 1734 if (FcbHeader->PagingIoResource) ExReleaseResourceLite(FcbHeader->PagingIoResource); 1735 if (FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource); 1736 } 1737 1738 /* Release master FsRtl lock */ 1739 FsRtlExitFileSystem(); 1740 } 1741 1742 /* 1743 * @implemented 1744 */ 1745 NTSTATUS 1746 NTAPI 1747 FsRtlAcquireFileForModWriteEx(IN PFILE_OBJECT FileObject, 1748 IN PLARGE_INTEGER EndingOffset, 1749 IN PERESOURCE *ResourceToRelease) 1750 { 1751 PFSRTL_COMMON_FCB_HEADER FcbHeader; 1752 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1753 PFAST_IO_DISPATCH FastDispatch; 1754 PERESOURCE ResourceToAcquire = NULL; 1755 BOOLEAN Exclusive = FALSE; 1756 BOOLEAN Result; 1757 NTSTATUS Status = STATUS_SUCCESS; 1758 1759 /* Get Device Object and Fast Calls */ 1760 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 1761 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1762 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1763 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1764 1765 /* Check if Fast Calls are supported, and check AcquireForModWrite */ 1766 if (FastDispatch && 1767 FastDispatch->AcquireForModWrite) 1768 { 1769 /* Call the AcquireForModWrite FastIo handler */ 1770 Status = FastDispatch->AcquireForModWrite(FileObject, 1771 EndingOffset, 1772 ResourceToRelease, 1773 BaseDeviceObject); 1774 1775 /* Return either success or inability to wait. 1776 In case of other failure - fall through */ 1777 if (Status == STATUS_SUCCESS || 1778 Status == STATUS_CANT_WAIT) 1779 { 1780 return Status; 1781 } 1782 } 1783 1784 Status = STATUS_SUCCESS; 1785 1786 /* No FastIo handler, use algorithm from Nagar p.550. */ 1787 if (!FcbHeader->Resource) 1788 { 1789 *ResourceToRelease = NULL; 1790 return STATUS_SUCCESS; 1791 } 1792 1793 /* Default condition - shared acquiring of Paging IO Resource */ 1794 ResourceToAcquire = FcbHeader->PagingIoResource; 1795 1796 /* Decide on type of locking and type of resource based on historical magic 1797 well explain by Nagar in p. 550-551 */ 1798 if ((EndingOffset->QuadPart > FcbHeader->ValidDataLength.QuadPart && 1799 FcbHeader->FileSize.QuadPart != FcbHeader->ValidDataLength.QuadPart) || 1800 (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX)) 1801 { 1802 /* Either exclusive flag is set or write operation is extending 1803 the valid data length. Prefer exclusive acquire then */ 1804 Exclusive = TRUE; 1805 ResourceToAcquire = FcbHeader->Resource; 1806 } 1807 else if (!FcbHeader->PagingIoResource || 1808 (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH)) 1809 { 1810 /* Acquire main resource shared if flag is specified or 1811 if PagingIo resource is missing */ 1812 Exclusive = FALSE; 1813 ResourceToAcquire = FcbHeader->Resource; 1814 } 1815 1816 /* Acquire the resource in the loop, since the above code is unsafe */ 1817 while (TRUE) 1818 { 1819 Result = FALSE; 1820 1821 if (Exclusive) 1822 Result = ExAcquireResourceExclusiveLite(ResourceToAcquire, FALSE); 1823 else 1824 Result = ExAcquireSharedWaitForExclusive(ResourceToAcquire, FALSE); 1825 1826 if (!Result) { 1827 Status = STATUS_CANT_WAIT; 1828 break; 1829 } 1830 1831 /* Do the magic ifs again */ 1832 if ((EndingOffset->QuadPart > FcbHeader->ValidDataLength.QuadPart) || 1833 (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX)) 1834 { 1835 /* Check what we have */ 1836 if (Exclusive) 1837 { 1838 /* Asked for exclusive, got exclusive! */ 1839 break; 1840 } 1841 else 1842 { 1843 /* Asked for exclusive, got shared. Release it and retry. */ 1844 ExReleaseResourceLite(ResourceToAcquire); 1845 Exclusive = TRUE; 1846 ResourceToAcquire = FcbHeader->Resource; 1847 } 1848 } 1849 else if (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH) 1850 { 1851 if (Exclusive) 1852 { 1853 /* Asked for shared, got exclusive - convert */ 1854 ExConvertExclusiveToSharedLite(ResourceToAcquire); 1855 break; 1856 } 1857 else if (ResourceToAcquire != FcbHeader->Resource) 1858 { 1859 /* Asked for main resource, got something else */ 1860 ExReleaseResourceLite(ResourceToAcquire); 1861 ResourceToAcquire = FcbHeader->Resource; 1862 Exclusive = TRUE; 1863 } 1864 } 1865 else if (FcbHeader->PagingIoResource && 1866 ResourceToAcquire != FcbHeader->PagingIoResource) 1867 { 1868 /* There is PagingIo resource, but other resource was acquired */ 1869 ResourceToAcquire = FcbHeader->PagingIoResource; 1870 if (!ExAcquireSharedWaitForExclusive(ResourceToAcquire, FALSE)) 1871 { 1872 Status = STATUS_CANT_WAIT; 1873 ExReleaseResourceLite(FcbHeader->Resource); 1874 } 1875 1876 break; 1877 } 1878 else if (Exclusive) 1879 { 1880 /* Asked for shared got exclusive - convert */ 1881 ExConvertExclusiveToSharedLite(ResourceToAcquire); 1882 break; 1883 } 1884 } 1885 1886 /* If the resource was acquired successfully - pass it to the caller */ 1887 if (NT_SUCCESS(Status)) 1888 *ResourceToRelease = ResourceToAcquire; 1889 1890 return Status; 1891 } 1892 1893 /* 1894 * @implemented 1895 */ 1896 VOID 1897 NTAPI 1898 FsRtlReleaseFileForModWrite(IN PFILE_OBJECT FileObject, 1899 IN PERESOURCE ResourceToRelease) 1900 { 1901 PDEVICE_OBJECT DeviceObject, BaseDeviceObject; 1902 PFAST_IO_DISPATCH FastDispatch; 1903 NTSTATUS Status = STATUS_SUCCESS; 1904 1905 /* Get Device Object and Fast Calls */ 1906 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1907 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); 1908 FastDispatch = DeviceObject->DriverObject->FastIoDispatch; 1909 1910 /* Check if Fast Calls are supported and check ReleaseFileForNtCreateSection */ 1911 if (FastDispatch && 1912 FastDispatch->ReleaseForModWrite) 1913 { 1914 /* Call the ReleaseForModWrite FastIo handler */ 1915 Status = FastDispatch->ReleaseForModWrite(FileObject, 1916 ResourceToRelease, 1917 BaseDeviceObject); 1918 } 1919 1920 /* Just release the resource if previous op failed */ 1921 if (!NT_SUCCESS(Status)) 1922 { 1923 ExReleaseResourceLite(ResourceToRelease); 1924 } 1925 } 1926 1927 1928 /*++ 1929 * @name FsRtlRegisterFileSystemFilterCallbacks 1930 * @unimplemented 1931 * 1932 * FILLME 1933 * 1934 * @param FilterDriverObject 1935 * FILLME 1936 * 1937 * @param Callbacks 1938 * FILLME 1939 * 1940 * @return None 1941 * 1942 * @remarks None 1943 * 1944 *--*/ 1945 NTSTATUS 1946 NTAPI 1947 FsRtlRegisterFileSystemFilterCallbacks( 1948 PDRIVER_OBJECT FilterDriverObject, 1949 PFS_FILTER_CALLBACKS Callbacks) 1950 { 1951 PFS_FILTER_CALLBACKS NewCallbacks; 1952 PEXTENDED_DRIVER_EXTENSION DriverExtension; 1953 PAGED_CODE(); 1954 1955 /* Verify parameters */ 1956 if ((FilterDriverObject == NULL) || (Callbacks == NULL)) 1957 { 1958 return STATUS_INVALID_PARAMETER; 1959 } 1960 1961 /* Allocate a buffer for a copy of the callbacks */ 1962 NewCallbacks = ExAllocatePoolWithTag(NonPagedPool, 1963 Callbacks->SizeOfFsFilterCallbacks, 1964 'gmSF'); 1965 if (NewCallbacks == NULL) 1966 { 1967 return STATUS_INSUFFICIENT_RESOURCES; 1968 } 1969 1970 /* Copy the callbacks */ 1971 RtlCopyMemory(NewCallbacks, Callbacks, Callbacks->SizeOfFsFilterCallbacks); 1972 1973 /* Set the callbacks in the driver extension */ 1974 DriverExtension = (PEXTENDED_DRIVER_EXTENSION)FilterDriverObject->DriverExtension; 1975 DriverExtension->FsFilterCallbacks = NewCallbacks; 1976 1977 return STATUS_SUCCESS; 1978 } 1979