1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 DevIoSup.c 8 9 Abstract: 10 11 This module implements the low lever disk read/write support for Cdfs. 12 13 14 --*/ 15 16 #include "cdprocs.h" 17 18 // 19 // The Bug check file id for this module 20 // 21 22 #define BugCheckFileId (CDFS_BUG_CHECK_DEVIOSUP) 23 24 // 25 // Local structure definitions 26 // 27 28 // 29 // An array of these structures is passed to CdMultipleAsync describing 30 // a set of runs to execute in parallel. 31 // 32 33 typedef struct _IO_RUN { 34 35 // 36 // Disk offset to read from and number of bytes to read. These 37 // must be a multiple of 2048 and the disk offset is also a 38 // multiple of 2048. 39 // 40 41 LONGLONG DiskOffset; 42 ULONG DiskByteCount; 43 44 // 45 // Current position in user buffer. This is the final destination for 46 // this portion of the Io transfer. 47 // 48 49 PVOID UserBuffer; 50 51 // 52 // Buffer to perform the transfer to. If this is the same as the 53 // user buffer above then we are using the user's buffer. Otherwise 54 // we either allocated a temporary buffer or are using a different portion 55 // of the user's buffer. 56 // 57 // TransferBuffer - Read full sectors into this location. This can 58 // be a pointer into the user's buffer at the exact location the 59 // data should go. It can also be an earlier point in the user's 60 // buffer if the complete I/O doesn't start on a sector boundary. 61 // It may also be a pointer into an allocated buffer. 62 // 63 // TransferByteCount - Count of bytes to transfer to user's buffer. A 64 // value of zero indicates that we did do the transfer into the 65 // user's buffer directly. 66 // 67 // TransferBufferOffset - Offset in this buffer to begin the transfer 68 // to the user's buffer. 69 // 70 71 PVOID TransferBuffer; 72 ULONG TransferByteCount; 73 ULONG TransferBufferOffset; 74 75 // 76 // This is the Mdl describing the locked pages in memory. It may 77 // be allocated to describe the allocated buffer. Or it may be 78 // the Mdl in the originating Irp. The MdlOffset is the offset of 79 // the current buffer from the beginning of the buffer described by 80 // the Mdl below. If the TransferMdl is not the same as the Mdl 81 // in the user's Irp then we know we have allocated it. 82 // 83 84 PMDL TransferMdl; 85 PVOID TransferVirtualAddress; 86 87 // 88 // Associated Irp used to perform the Io. 89 // 90 91 PIRP SavedIrp; 92 93 } IO_RUN; 94 typedef IO_RUN *PIO_RUN; 95 96 #define MAX_PARALLEL_IOS 5 97 98 // 99 // Local support routines 100 // 101 102 _Requires_lock_held_(_Global_critical_region_) 103 BOOLEAN 104 CdPrepareBuffers ( 105 _In_ PIRP_CONTEXT IrpContext, 106 _In_ PIRP Irp, 107 _In_ PFCB Fcb, 108 _In_reads_bytes_(ByteCount) PVOID UserBuffer, 109 _In_ ULONG UserBufferOffset, 110 _In_ LONGLONG StartingOffset, 111 _In_ ULONG ByteCount, 112 _Out_ PIO_RUN IoRuns, 113 _Out_ PULONG RunCount, 114 _Out_ PULONG ThisByteCount 115 ); 116 117 _Requires_lock_held_(_Global_critical_region_) 118 VOID 119 CdPrepareXABuffers ( 120 _In_ PIRP_CONTEXT IrpContext, 121 _In_ PIRP Irp, 122 _In_ PFCB Fcb, 123 _In_reads_bytes_(ByteCount) PVOID UserBuffer, 124 _In_ ULONG UserBufferOffset, 125 _In_ LONGLONG StartingOffset, 126 _In_ ULONG ByteCount, 127 _Out_ PIO_RUN IoRuns, 128 _Out_ PULONG RunCount, 129 _Out_ PULONG ThisByteCount 130 ); 131 132 BOOLEAN 133 CdFinishBuffers ( 134 _In_ PIRP_CONTEXT IrpContext, 135 _Inout_ PIO_RUN IoRuns, 136 _In_ ULONG RunCount, 137 _In_ BOOLEAN FinalCleanup, 138 _In_ BOOLEAN SaveXABuffer 139 ); 140 141 _Requires_lock_held_(_Global_critical_region_) 142 VOID 143 CdMultipleAsync ( 144 _In_ PIRP_CONTEXT IrpContext, 145 _In_ PFCB Fcb, 146 _In_ ULONG RunCount, 147 _Inout_ PIO_RUN IoRuns 148 ); 149 150 VOID 151 CdMultipleXAAsync ( 152 _In_ PIRP_CONTEXT IrpContext, 153 _In_ ULONG RunCount, 154 _Inout_ PIO_RUN IoRuns, 155 _In_ PRAW_READ_INFO RawReads, 156 _In_ TRACK_MODE_TYPE TrackMode 157 ); 158 159 _Requires_lock_held_(_Global_critical_region_) 160 VOID 161 CdSingleAsync ( 162 _In_ PIRP_CONTEXT IrpContext, 163 _In_ PIO_RUN Run, 164 _In_ PFCB Fcb 165 ); 166 167 VOID 168 CdWaitSync ( 169 _In_ PIRP_CONTEXT IrpContext 170 ); 171 172 // Tell prefast this is a completion routine. 173 IO_COMPLETION_ROUTINE CdMultiSyncCompletionRoutine; 174 175 // Tell prefast this is a completion routine 176 IO_COMPLETION_ROUTINE CdMultiAsyncCompletionRoutine; 177 178 // Tell prefast this is a completion routine 179 IO_COMPLETION_ROUTINE CdSingleSyncCompletionRoutine; 180 181 // Tell prefast this is a completion routine 182 IO_COMPLETION_ROUTINE CdSingleAsyncCompletionRoutine; 183 184 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT)))) 185 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE))) 186 VOID 187 CdReadAudioSystemFile ( 188 _In_ PIRP_CONTEXT IrpContext, 189 _In_ PFCB Fcb, 190 _In_ LONGLONG StartingOffset, 191 _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount, 192 _Out_writes_bytes_(ByteCount) PVOID SystemBuffer 193 ); 194 195 _Requires_lock_held_(_Global_critical_region_) 196 BOOLEAN 197 CdReadDirDataThroughCache ( 198 _In_ PIRP_CONTEXT IrpContext, 199 _In_ PIO_RUN Run 200 ); 201 202 #ifdef ALLOC_PRAGMA 203 #pragma alloc_text(PAGE, CdCreateUserMdl) 204 #pragma alloc_text(PAGE, CdMultipleAsync) 205 #pragma alloc_text(PAGE, CdMultipleXAAsync) 206 #pragma alloc_text(PAGE, CdNonCachedRead) 207 #pragma alloc_text(PAGE, CdNonCachedXARead) 208 #pragma alloc_text(PAGE, CdVolumeDasdWrite) 209 #pragma alloc_text(PAGE, CdFinishBuffers) 210 #pragma alloc_text(PAGE, CdPerformDevIoCtrl) 211 #pragma alloc_text(PAGE, CdPerformDevIoCtrlEx) 212 #pragma alloc_text(PAGE, CdPrepareBuffers) 213 #pragma alloc_text(PAGE, CdPrepareXABuffers) 214 #pragma alloc_text(PAGE, CdReadAudioSystemFile) 215 #pragma alloc_text(PAGE, CdReadSectors) 216 #pragma alloc_text(PAGE, CdSingleAsync) 217 #pragma alloc_text(PAGE, CdWaitSync) 218 #pragma alloc_text(PAGE, CdReadDirDataThroughCache) 219 #pragma alloc_text(PAGE, CdFreeDirCache) 220 #pragma alloc_text(PAGE, CdLbnToMmSsFf) 221 #pragma alloc_text(PAGE, CdHijackIrpAndFlushDevice) 222 #endif 223 224 225 VOID 226 CdLbnToMmSsFf ( 227 _In_ ULONG Blocks, 228 _Out_writes_(3) PUCHAR Msf 229 ) 230 231 /*++ 232 233 Routine Description: 234 235 Convert Lbn to MSF format. 236 237 Arguments: 238 239 Msf - on output, set to 0xMmSsFf representation of blocks. 240 241 --*/ 242 243 { 244 PAGED_CODE(); 245 246 Blocks += 150; // Lbn 0 == 00:02:00, 1sec == 75 frames. 247 248 Msf[0] = (UCHAR)(Blocks % 75); // Frames 249 Blocks /= 75; // -> Seconds 250 Msf[1] = (UCHAR)(Blocks % 60); // Seconds 251 Blocks /= 60; // -> Minutes 252 Msf[2] = (UCHAR)Blocks; // Minutes 253 } 254 255 256 __inline 257 TRACK_MODE_TYPE 258 CdFileTrackMode ( 259 _In_ PFCB Fcb 260 ) 261 262 /*++ 263 264 Routine Description: 265 266 This routine converts FCB XA file type flags to the track mode 267 used by the device drivers. 268 269 Arguments: 270 271 Fcb - Fcb representing the file to read. 272 273 Return Value: 274 275 TrackMode of the file represented by the Fcb. 276 277 --*/ 278 { 279 NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE | 280 FCB_STATE_MODE2_FILE | 281 FCB_STATE_DA_FILE )); 282 283 if (FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) { 284 285 return XAForm2; 286 287 } else if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) { 288 289 return CDDA; 290 291 } 292 293 // 294 // FCB_STATE_MODE2_FILE 295 // 296 297 return YellowMode2; 298 } 299 300 301 _Requires_lock_held_(_Global_critical_region_) 302 NTSTATUS 303 CdNonCachedRead ( 304 _In_ PIRP_CONTEXT IrpContext, 305 _In_ PFCB Fcb, 306 _In_ LONGLONG StartingOffset, 307 _In_ ULONG ByteCount 308 ) 309 310 /*++ 311 312 Routine Description: 313 314 This routine performs the non-cached reads to 'cooked' sectors (2048 bytes 315 per sector). This is done by performing the following in a loop. 316 317 Fill in the IoRuns array for the next block of Io. 318 Send the Io to the device. 319 Perform any cleanup on the Io runs array. 320 321 We will not do async Io to any request that generates non-aligned Io. 322 Also we will not perform async Io if it will exceed the size of our 323 IoRuns array. These should be the unusual cases but we will raise 324 or return CANT_WAIT in this routine if we detect this case. 325 326 Arguments: 327 328 Fcb - Fcb representing the file to read. 329 330 StartingOffset - Logical offset in the file to read from. 331 332 ByteCount - Number of bytes to read. 333 334 Return Value: 335 336 NTSTATUS - Status indicating the result of the operation. 337 338 --*/ 339 340 { 341 NTSTATUS Status = STATUS_SUCCESS; 342 343 IO_RUN IoRuns[MAX_PARALLEL_IOS]; 344 ULONG RunCount = 0; 345 ULONG CleanupRunCount = 0; 346 347 PVOID UserBuffer; 348 ULONG UserBufferOffset = 0; 349 LONGLONG CurrentOffset = StartingOffset; 350 ULONG RemainingByteCount = ByteCount; 351 ULONG ThisByteCount; 352 353 BOOLEAN Unaligned; 354 BOOLEAN FlushIoBuffers = FALSE; 355 BOOLEAN FirstPass = TRUE; 356 357 PAGED_CODE(); 358 359 // 360 // We want to make sure the user's buffer is locked in all cases. 361 // 362 363 if (IrpContext->Irp->MdlAddress == NULL) { 364 365 CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess ); 366 } 367 368 CdMapUserBuffer( IrpContext, &UserBuffer); 369 370 // 371 // Special case the root directory and path table for a music volume. 372 // 373 374 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK ) && 375 ((SafeNodeType( Fcb ) == CDFS_NTC_FCB_INDEX) || 376 (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE))) { 377 378 CdReadAudioSystemFile( IrpContext, 379 Fcb, 380 StartingOffset, 381 ByteCount, 382 UserBuffer ); 383 384 return STATUS_SUCCESS; 385 } 386 387 // 388 // If we're going to use the sector cache for this request, then 389 // mark the request waitable. 390 // 391 392 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) && 393 (NULL != Fcb->Vcb->SectorCacheBuffer) && 394 (VcbMounted == IrpContext->Vcb->VcbCondition)) { 395 396 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { 397 398 KeInitializeEvent( &IrpContext->IoContext->SyncEvent, 399 NotificationEvent, 400 FALSE ); 401 402 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 403 } 404 } 405 406 // 407 // Use a try-finally to perform the final cleanup. 408 // 409 410 _SEH2_TRY { 411 412 // 413 // Loop while there are more bytes to transfer. 414 // 415 416 do { 417 418 // 419 // Call prepare buffers to set up the next entries 420 // in the IoRuns array. Remember if there are any 421 // unaligned entries. This routine will raise CANT_WAIT 422 // if there are unaligned entries for an async request. 423 // 424 425 RtlZeroMemory( IoRuns, sizeof( IoRuns )); 426 427 Unaligned = CdPrepareBuffers( IrpContext, 428 IrpContext->Irp, 429 Fcb, 430 UserBuffer, 431 UserBufferOffset, 432 CurrentOffset, 433 RemainingByteCount, 434 IoRuns, 435 &CleanupRunCount, 436 &ThisByteCount ); 437 438 439 RunCount = CleanupRunCount; 440 441 // 442 // If this is an async request and there aren't enough entries 443 // in the Io array then post the request. 444 // 445 446 if ((ThisByteCount < RemainingByteCount) && 447 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 448 449 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); 450 } 451 452 // 453 // If the entire Io is contained in a single run then 454 // we can pass the Io down to the driver. Send the driver down 455 // and wait on the result if this is synchronous. 456 // 457 458 if ((RunCount == 1) && !Unaligned && FirstPass) { 459 460 CdSingleAsync( IrpContext,&IoRuns[0], Fcb ); 461 462 // 463 // No cleanup needed for the IoRuns array here. 464 // 465 466 CleanupRunCount = 0; 467 468 // 469 // Wait if we are synchronous, otherwise return 470 // 471 472 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 473 474 CdWaitSync( IrpContext ); 475 476 Status = IrpContext->Irp->IoStatus.Status; 477 478 // 479 // Our completion routine will free the Io context but 480 // we do want to return STATUS_PENDING. 481 // 482 483 } else { 484 485 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 486 Status = STATUS_PENDING; 487 } 488 489 try_return( NOTHING ); 490 } 491 492 // 493 // Otherwise we will perform multiple Io to read in the data. 494 // 495 496 CdMultipleAsync( IrpContext, Fcb, RunCount, IoRuns ); 497 498 // 499 // If this is a synchronous request then perform any necessary 500 // post-processing. 501 // 502 503 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 504 505 // 506 // Wait for the request to complete. 507 // 508 509 CdWaitSync( IrpContext ); 510 511 Status = IrpContext->Irp->IoStatus.Status; 512 513 // 514 // Exit this loop if there is an error. 515 // 516 517 if (!NT_SUCCESS( Status )) { 518 519 try_return( NOTHING ); 520 } 521 522 // 523 // Perform post read operations on the IoRuns if 524 // necessary. 525 // 526 527 if (Unaligned && 528 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, FALSE )) { 529 530 FlushIoBuffers = TRUE; 531 } 532 533 CleanupRunCount = 0; 534 535 // 536 // Exit this loop if there are no more bytes to transfer 537 // or we have any error. 538 // 539 540 RemainingByteCount -= ThisByteCount; 541 CurrentOffset += ThisByteCount; 542 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID ); 543 UserBufferOffset += ThisByteCount; 544 545 // 546 // Otherwise this is an asynchronous request. Always return 547 // STATUS_PENDING. 548 // 549 550 } else { 551 552 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 553 CleanupRunCount = 0; 554 try_return( Status = STATUS_PENDING ); 555 break; 556 } 557 558 FirstPass = FALSE; 559 } while (RemainingByteCount != 0); 560 561 // 562 // Flush the hardware cache if we performed any copy operations. 563 // 564 565 if (FlushIoBuffers) { 566 567 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE ); 568 } 569 570 try_exit: NOTHING; 571 } _SEH2_FINALLY { 572 573 // 574 // Perform final cleanup on the IoRuns if necessary. 575 // 576 577 if (CleanupRunCount != 0) { 578 579 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE ); 580 } 581 } _SEH2_END; 582 583 return Status; 584 } 585 586 587 588 _Requires_lock_held_(_Global_critical_region_) 589 NTSTATUS 590 CdNonCachedXARead ( 591 _In_ PIRP_CONTEXT IrpContext, 592 _In_ PFCB Fcb, 593 _In_ LONGLONG StartingOffset, 594 _In_ ULONG ByteCount 595 ) 596 597 /*++ 598 599 Routine Description: 600 601 This routine performs the non-cached reads for 'raw' sectors (2352 bytes 602 per sector). We also prepend a hard-coded RIFF header of 44 bytes to the file. 603 All of this is already reflected in the file size. 604 605 We start by checking whether to prepend any portion of the RIFF header. Then we check 606 if the last raw sector read was from the beginning portion of this file, deallocating 607 that buffer if necessary. Finally we do the following in a loop. 608 609 Fill the IoRuns array for the next block of Io. 610 Send the Io to the device driver. 611 Perform any cleanup necessary on the IoRuns array. 612 613 We will not do any async request in this path. The request would have been 614 posted to a worker thread before getting to this point. 615 616 Arguments: 617 618 Fcb - Fcb representing the file to read. 619 620 StartingOffset - Logical offset in the file to read from. 621 622 ByteCount - Number of bytes to read. 623 624 Return Value: 625 626 NTSTATUS - Status indicating the result of the operation. 627 628 --*/ 629 630 { 631 NTSTATUS Status = STATUS_SUCCESS; 632 633 RIFF_HEADER LocalRiffHeader; 634 PRIFF_HEADER RiffHeader; 635 636 RAW_READ_INFO RawReads[MAX_PARALLEL_IOS]; 637 IO_RUN IoRuns[MAX_PARALLEL_IOS]; 638 ULONG RunCount = 0; 639 ULONG CleanupRunCount = 0; 640 641 PVOID UserBuffer; 642 ULONG UserBufferOffset = 0; 643 LONGLONG CurrentOffset = StartingOffset; 644 ULONG RemainingByteCount = ByteCount; 645 ULONG ThisByteCount = 0; 646 ULONG Address = 0; 647 648 BOOLEAN TryingYellowbookMode2 = FALSE; 649 650 TRACK_MODE_TYPE TrackMode; 651 652 PAGED_CODE(); 653 654 // 655 // We want to make sure the user's buffer is locked in all cases. 656 // 657 658 if (IrpContext->Irp->MdlAddress == NULL) { 659 660 CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess ); 661 } 662 663 // 664 // The byte count was rounded up to a logical sector boundary. It has 665 // nothing to do with the raw sectors on disk. Limit the remaining 666 // byte count to file size. 667 // 668 669 if (CurrentOffset + RemainingByteCount > Fcb->FileSize.QuadPart) { 670 671 RemainingByteCount = (ULONG) (Fcb->FileSize.QuadPart - CurrentOffset); 672 } 673 674 CdMapUserBuffer( IrpContext, &UserBuffer); 675 676 // 677 // Use a try-finally to perform the final cleanup. 678 // 679 680 _SEH2_TRY { 681 682 // 683 // If the initial offset lies within the RIFF header then copy the 684 // necessary bytes to the user's buffer. 685 // 686 687 if (CurrentOffset < sizeof( RIFF_HEADER )) { 688 689 // 690 // Copy the appropriate RIFF header. 691 // 692 693 if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) { 694 695 // 696 // Create the pseudo entries for a music disk. 697 // 698 699 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK )) { 700 701 PAUDIO_PLAY_HEADER AudioPlayHeader; 702 PTRACK_DATA TrackData; 703 704 AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader; 705 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber]; 706 707 // 708 // Copy the data header into our local buffer. 709 // 710 711 RtlCopyMemory( AudioPlayHeader, 712 CdAudioPlayHeader, 713 sizeof( AUDIO_PLAY_HEADER )); 714 715 // 716 // Copy the serial number into the Id field. Also 717 // the track number in the TOC. 718 // 719 720 AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber; 721 AudioPlayHeader->TrackNumber = TrackData->TrackNumber; 722 723 // 724 // One frame == One sector. 725 // One second == 75 frames (winds up being a 44.1khz sample) 726 // 727 // Note: LBN 0 == 0:2:0 (MSF) 728 // 729 730 // 731 // Fill in the address (both MSF and Lbn format) and length fields. 732 // 733 734 SwapCopyUchar4( &Address, TrackData->Address); 735 CdLbnToMmSsFf( Address, AudioPlayHeader->TrackAddress); 736 737 SwapCopyUchar4( &AudioPlayHeader->StartingSector, TrackData->Address); 738 739 // 740 // Go to the next track and find the starting point. 741 // 742 743 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1]; 744 745 SwapCopyUchar4( &AudioPlayHeader->SectorCount, TrackData->Address); 746 747 // 748 // Now compute the difference. If there is an error then use 749 // a length of zero. 750 // 751 752 if (AudioPlayHeader->SectorCount < AudioPlayHeader->StartingSector) { 753 754 AudioPlayHeader->SectorCount = 0; 755 756 } else { 757 758 AudioPlayHeader->SectorCount -= AudioPlayHeader->StartingSector; 759 } 760 761 // 762 // Use the sector count to determine the MSF length. Bias by 150 to make 763 // it an "lbn" since the conversion routine corrects for Lbn 0 == 0:2:0; 764 // 765 766 Address = AudioPlayHeader->SectorCount - 150; 767 CdLbnToMmSsFf( Address, AudioPlayHeader->TrackLength); 768 769 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset; 770 771 RtlCopyMemory( UserBuffer, 772 Add2Ptr( AudioPlayHeader, 773 sizeof( RIFF_HEADER ) - ThisByteCount, 774 PCHAR ), 775 ThisByteCount ); 776 777 // 778 // CD-XA CDDA 779 // 780 781 } else { 782 783 // 784 // The WAVE header format is actually much closer to an audio play 785 // header in format but we only need to modify the filesize fields. 786 // 787 788 RiffHeader = &LocalRiffHeader; 789 790 // 791 // Copy the data header into our local buffer and add the file size to it. 792 // 793 794 RtlCopyMemory( RiffHeader, 795 CdXAAudioPhileHeader, 796 sizeof( RIFF_HEADER )); 797 798 RiffHeader->ChunkSize += Fcb->FileSize.LowPart; 799 RiffHeader->RawSectors += Fcb->FileSize.LowPart; 800 801 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset; 802 RtlCopyMemory( UserBuffer, 803 Add2Ptr( RiffHeader, 804 sizeof( RIFF_HEADER ) - ThisByteCount, 805 PCHAR ), 806 ThisByteCount ); 807 } 808 809 // 810 // CD-XA non-audio 811 // 812 813 } else { 814 815 NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE )); 816 817 RiffHeader = &LocalRiffHeader; 818 819 // 820 // Copy the data header into our local buffer and add the file size to it. 821 // 822 823 RtlCopyMemory( RiffHeader, 824 CdXAFileHeader, 825 sizeof( RIFF_HEADER )); 826 827 RiffHeader->ChunkSize += Fcb->FileSize.LowPart; 828 RiffHeader->RawSectors += Fcb->FileSize.LowPart; 829 830 RiffHeader->Attributes = (USHORT) Fcb->XAAttributes; 831 RiffHeader->FileNumber = (UCHAR) Fcb->XAFileNumber; 832 833 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset; 834 RtlCopyMemory( UserBuffer, 835 Add2Ptr( RiffHeader, 836 sizeof( RIFF_HEADER ) - ThisByteCount, 837 PCHAR ), 838 ThisByteCount ); 839 } 840 841 // 842 // Adjust the starting offset and byte count to reflect that 843 // we copied over the RIFF bytes. 844 // 845 846 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID ); 847 UserBufferOffset += ThisByteCount; 848 CurrentOffset += ThisByteCount; 849 RemainingByteCount -= ThisByteCount; 850 } 851 852 // 853 // Set up the appropriate trackmode 854 // 855 856 TrackMode = CdFileTrackMode(Fcb); 857 858 // 859 // Loop while there are more bytes to transfer. 860 // 861 862 while (RemainingByteCount != 0) { 863 864 // 865 // Call prepare buffers to set up the next entries 866 // in the IoRuns array. Remember if there are any 867 // unaligned entries. If we're just retrying the previous 868 // runs with a different track mode, then don't do anything here. 869 // 870 871 if (!TryingYellowbookMode2) { 872 873 RtlZeroMemory( IoRuns, sizeof( IoRuns )); 874 RtlZeroMemory( RawReads, sizeof( RawReads )); 875 876 CdPrepareXABuffers( IrpContext, 877 IrpContext->Irp, 878 Fcb, 879 UserBuffer, 880 UserBufferOffset, 881 CurrentOffset, 882 RemainingByteCount, 883 IoRuns, 884 &CleanupRunCount, 885 &ThisByteCount ); 886 } 887 888 // 889 // Perform multiple Io to read in the data. Note that 890 // there may be no Io to do if we were able to use an 891 // existing buffer from the Vcb. 892 // 893 894 if (CleanupRunCount != 0) { 895 896 RunCount = CleanupRunCount; 897 898 CdMultipleXAAsync( IrpContext, 899 RunCount, 900 IoRuns, 901 RawReads, 902 TrackMode ); 903 // 904 // Wait for the request to complete. 905 // 906 907 CdWaitSync( IrpContext ); 908 909 Status = IrpContext->Irp->IoStatus.Status; 910 911 // 912 // Exit this loop if there is an error. 913 // 914 915 if (!NT_SUCCESS( Status )) { 916 917 if (!TryingYellowbookMode2 && 918 FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) { 919 920 // 921 // There are wacky cases where someone has mastered as CD-XA 922 // but the sectors they claim are Mode2Form2 are really, according 923 // to ATAPI devices, Yellowbook Mode2. We will try once more 924 // with these. Kodak PHOTO-CD has been observed to do this. 925 // 926 927 TryingYellowbookMode2 = TRUE; 928 TrackMode = YellowMode2; 929 930 // 931 // Clear our 'cumulative' error status value 932 // 933 934 IrpContext->IoContext->Status = STATUS_SUCCESS; 935 936 continue; 937 } 938 939 try_return( NOTHING ); 940 } 941 942 CleanupRunCount = 0; 943 944 if (TryingYellowbookMode2) { 945 946 // 947 // We succesfully got data when we tried switching the trackmode, 948 // so change the state of the FCB to remember that. 949 // 950 951 SetFlag( Fcb->FcbState, FCB_STATE_MODE2_FILE ); 952 ClearFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE ); 953 954 TryingYellowbookMode2 = FALSE; 955 } 956 957 // 958 // Perform post read operations on the IoRuns if 959 // necessary. 960 // 961 962 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, TRUE ); 963 } 964 965 // 966 // Adjust our loop variants. 967 // 968 969 RemainingByteCount -= ThisByteCount; 970 CurrentOffset += ThisByteCount; 971 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID ); 972 UserBufferOffset += ThisByteCount; 973 } 974 975 // 976 // Always flush the hardware cache. 977 // 978 979 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE ); 980 981 try_exit: NOTHING; 982 } _SEH2_FINALLY { 983 984 // 985 // Perform final cleanup on the IoRuns if necessary. 986 // 987 988 if (CleanupRunCount != 0) { 989 990 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE ); 991 } 992 } _SEH2_END; 993 994 return Status; 995 } 996 997 _Requires_lock_held_(_Global_critical_region_) 998 NTSTATUS 999 CdVolumeDasdWrite ( 1000 _In_ PIRP_CONTEXT IrpContext, 1001 _In_ PFCB Fcb, 1002 _In_ LONGLONG StartingOffset, 1003 _In_ ULONG ByteCount 1004 ) 1005 1006 /*++ 1007 1008 Routine Description: 1009 1010 This routine performs the non-cached writes to 'cooked' sectors (2048 bytes 1011 per sector). This is done by filling the IoRun for the desired request 1012 and send it down to the device. 1013 1014 Arguments: 1015 1016 Fcb - Fcb representing the file to read. 1017 1018 StartingOffset - Logical offset in the file to read from. 1019 1020 ByteCount - Number of bytes to read. 1021 1022 Return Value: 1023 1024 NTSTATUS - Status indicating the result of the operation. 1025 1026 --*/ 1027 1028 { 1029 NTSTATUS Status; 1030 IO_RUN IoRun; 1031 1032 PAGED_CODE(); 1033 1034 // 1035 // We want to make sure the user's buffer is locked in all cases. 1036 // 1037 1038 CdLockUserBuffer( IrpContext, ByteCount, IoReadAccess ); 1039 1040 // 1041 // The entire Io can be contained in a single run, just pass 1042 // the Io down to the driver. Send the driver down 1043 // and wait on the result if this is synchronous. 1044 // 1045 1046 RtlZeroMemory( &IoRun, sizeof( IoRun ) ); 1047 1048 IoRun.DiskOffset = StartingOffset; 1049 IoRun.DiskByteCount = ByteCount; 1050 1051 CdSingleAsync( IrpContext, &IoRun, Fcb ); 1052 1053 // 1054 // Wait if we are synchronous, otherwise return 1055 // 1056 1057 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 1058 1059 CdWaitSync( IrpContext ); 1060 1061 Status = IrpContext->Irp->IoStatus.Status; 1062 1063 // 1064 // Our completion routine will free the Io context but 1065 // we do want to return STATUS_PENDING. 1066 // 1067 1068 } else { 1069 1070 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 1071 Status = STATUS_PENDING; 1072 } 1073 1074 return Status; 1075 } 1076 1077 1078 1079 BOOLEAN 1080 CdReadSectors ( 1081 _In_ PIRP_CONTEXT IrpContext, 1082 _In_ LONGLONG StartingOffset, 1083 _In_ ULONG ByteCount, 1084 _In_ BOOLEAN ReturnError, 1085 _Out_writes_bytes_(ByteCount) PVOID Buffer, 1086 _In_ PDEVICE_OBJECT TargetDeviceObject 1087 ) 1088 1089 /*++ 1090 1091 Routine Description: 1092 1093 This routine is called to transfer sectors from the disk to a 1094 specified buffer. It is used for mount and volume verify operations. 1095 1096 This routine is synchronous, it will not return until the operation 1097 is complete or until the operation fails. 1098 1099 The routine allocates an IRP and then passes this IRP to a lower 1100 level driver. Errors may occur in the allocation of this IRP or 1101 in the operation of the lower driver. 1102 1103 Arguments: 1104 1105 StartingOffset - Logical offset on the disk to start the read. This 1106 must be on a sector boundary, no check is made here. 1107 1108 ByteCount - Number of bytes to read. This is an integral number of 1109 2K sectors, no check is made here to confirm this. 1110 1111 ReturnError - Indicates whether we should return TRUE or FALSE 1112 to indicate an error or raise an error condition. This only applies 1113 to the result of the IO. Any other error may cause a raise. 1114 1115 Buffer - Buffer to transfer the disk data into. 1116 1117 TargetDeviceObject - The device object for the volume to be read. 1118 1119 Return Value: 1120 1121 BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation 1122 succeeded, FALSE otherwise. 1123 1124 --*/ 1125 1126 { 1127 NTSTATUS Status; 1128 KEVENT Event; 1129 PIRP Irp; 1130 1131 PAGED_CODE(); 1132 1133 // 1134 // Initialize the event. 1135 // 1136 1137 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 1138 1139 // 1140 // Attempt to allocate the IRP. If unsuccessful, raise 1141 // STATUS_INSUFFICIENT_RESOURCES. 1142 // 1143 1144 Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 1145 TargetDeviceObject, 1146 Buffer, 1147 ByteCount, 1148 (PLARGE_INTEGER) &StartingOffset, 1149 &Event, 1150 &IrpContext->Irp->IoStatus ); 1151 1152 if (Irp == NULL) { 1153 1154 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 1155 } 1156 1157 // 1158 // Ignore the change line (verify) for mount and verify requests 1159 // 1160 1161 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); 1162 1163 // 1164 // Send the request down to the driver. If an error occurs return 1165 // it to the caller. 1166 // 1167 1168 Status = IoCallDriver( TargetDeviceObject, Irp ); 1169 1170 // 1171 // If the status was STATUS_PENDING then wait on the event. 1172 // 1173 1174 if (Status == STATUS_PENDING) { 1175 1176 Status = KeWaitForSingleObject( &Event, 1177 Executive, 1178 KernelMode, 1179 FALSE, 1180 NULL ); 1181 1182 // 1183 // On a successful wait pull the status out of the IoStatus block. 1184 // 1185 1186 if (NT_SUCCESS( Status )) { 1187 1188 Status = IrpContext->Irp->IoStatus.Status; 1189 } 1190 } 1191 1192 // 1193 // Check whether we should raise in the error case. 1194 // 1195 1196 if (!NT_SUCCESS( Status )) { 1197 1198 if (!ReturnError) { 1199 1200 CdNormalizeAndRaiseStatus( IrpContext, Status ); 1201 } 1202 1203 // 1204 // We don't raise, but return FALSE to indicate an error. 1205 // 1206 1207 return FALSE; 1208 1209 // 1210 // The operation completed successfully. 1211 // 1212 1213 } else { 1214 1215 return TRUE; 1216 } 1217 } 1218 1219 1220 NTSTATUS 1221 CdCreateUserMdl ( 1222 _In_ PIRP_CONTEXT IrpContext, 1223 _In_ ULONG BufferLength, 1224 _In_ BOOLEAN RaiseOnError, 1225 _In_ LOCK_OPERATION Operation 1226 ) 1227 1228 /*++ 1229 1230 Routine Description: 1231 1232 This routine locks the specified buffer for read access (we only write into 1233 the buffer). The file system requires this routine since it does not 1234 ask the I/O system to lock its buffers for direct I/O. This routine 1235 may only be called from the Fsd while still in the user context. 1236 1237 This routine is only called if there is not already an Mdl. 1238 1239 Arguments: 1240 1241 BufferLength - Length of user buffer. 1242 1243 RaiseOnError - Indicates if our caller wants this routine to raise on 1244 an error condition. 1245 1246 Operation - IoWriteAccess or IoReadAccess 1247 1248 Return Value: 1249 1250 NTSTATUS - Status from this routine. Error status only returned if 1251 RaiseOnError is FALSE. 1252 1253 --*/ 1254 1255 { 1256 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 1257 PMDL Mdl; 1258 1259 PAGED_CODE(); 1260 1261 UNREFERENCED_PARAMETER( Operation ); 1262 UNREFERENCED_PARAMETER( IrpContext ); 1263 1264 ASSERT_IRP_CONTEXT( IrpContext ); 1265 ASSERT_IRP( IrpContext->Irp ); 1266 NT_ASSERT( IrpContext->Irp->MdlAddress == NULL ); 1267 1268 // 1269 // Allocate the Mdl, and Raise if we fail. 1270 // 1271 1272 Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer, 1273 BufferLength, 1274 FALSE, 1275 FALSE, 1276 IrpContext->Irp ); 1277 1278 if (Mdl != NULL) { 1279 1280 // 1281 // Now probe the buffer described by the Irp. If we get an exception, 1282 // deallocate the Mdl and return the appropriate "expected" status. 1283 // 1284 1285 _SEH2_TRY { 1286 1287 MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess ); 1288 1289 Status = STATUS_SUCCESS; 1290 1291 #ifdef _MSC_VER 1292 #pragma warning(suppress: 6320) 1293 #endif 1294 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1295 1296 Status = _SEH2_GetExceptionCode(); 1297 1298 IoFreeMdl( Mdl ); 1299 IrpContext->Irp->MdlAddress = NULL; 1300 1301 if (!FsRtlIsNtstatusExpected( Status )) { 1302 1303 Status = STATUS_INVALID_USER_BUFFER; 1304 } 1305 } _SEH2_END; 1306 } 1307 1308 // 1309 // Check if we are to raise or return 1310 // 1311 1312 if (Status != STATUS_SUCCESS) { 1313 1314 if (RaiseOnError) { 1315 1316 CdRaiseStatus( IrpContext, Status ); 1317 } 1318 } 1319 1320 // 1321 // Return the status code. 1322 // 1323 1324 return Status; 1325 } 1326 1327 1328 NTSTATUS 1329 CdPerformDevIoCtrlEx ( 1330 _In_ PIRP_CONTEXT IrpContext, 1331 _In_ ULONG IoControlCode, 1332 _In_ PDEVICE_OBJECT Device, 1333 _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, 1334 _In_ ULONG InputBufferLength, 1335 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, 1336 _In_ ULONG OutputBufferLength, 1337 _In_ BOOLEAN InternalDeviceIoControl, 1338 _In_ BOOLEAN OverrideVerify, 1339 _Out_opt_ PIO_STATUS_BLOCK Iosb 1340 ) 1341 1342 /*++ 1343 1344 Routine Description: 1345 1346 This routine is called to perform DevIoCtrl functions internally within 1347 the filesystem. We take the status from the driver and return it to our 1348 caller. 1349 1350 Arguments: 1351 1352 IoControlCode - Code to send to driver. 1353 1354 Device - This is the device to send the request to. 1355 1356 OutPutBuffer - Pointer to output buffer. 1357 1358 OutputBufferLength - Length of output buffer above. 1359 1360 InternalDeviceIoControl - Indicates if this is an internal or external 1361 Io control code. 1362 1363 OverrideVerify - Indicates if we should tell the driver not to return 1364 STATUS_VERIFY_REQUIRED for mount and verify. 1365 1366 Iosb - If specified, we return the results of the operation here. 1367 1368 Return Value: 1369 1370 NTSTATUS - Status returned by next lower driver. 1371 1372 --*/ 1373 1374 { 1375 NTSTATUS Status; 1376 PIRP Irp; 1377 KEVENT Event; 1378 IO_STATUS_BLOCK LocalIosb; 1379 PIO_STATUS_BLOCK IosbToUse = &LocalIosb; 1380 1381 PAGED_CODE(); 1382 1383 UNREFERENCED_PARAMETER( IrpContext ); 1384 1385 // 1386 // Check if the user gave us an Iosb. 1387 // 1388 1389 if (ARGUMENT_PRESENT( Iosb )) { 1390 1391 IosbToUse = Iosb; 1392 } 1393 1394 IosbToUse->Status = 0; 1395 IosbToUse->Information = 0; 1396 1397 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 1398 1399 Irp = IoBuildDeviceIoControlRequest( IoControlCode, 1400 Device, 1401 InputBuffer, 1402 InputBufferLength, 1403 OutputBuffer, 1404 OutputBufferLength, 1405 InternalDeviceIoControl, 1406 &Event, 1407 IosbToUse ); 1408 1409 if (Irp == NULL) { 1410 1411 return STATUS_INSUFFICIENT_RESOURCES; 1412 } 1413 1414 if (OverrideVerify) { 1415 1416 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); 1417 } 1418 1419 Status = IoCallDriver( Device, Irp ); 1420 1421 // 1422 // We check for device not ready by first checking Status 1423 // and then if status pending was returned, the Iosb status 1424 // value. 1425 // 1426 1427 if (Status == STATUS_PENDING) { 1428 1429 (VOID) KeWaitForSingleObject( &Event, 1430 Executive, 1431 KernelMode, 1432 FALSE, 1433 (PLARGE_INTEGER)NULL ); 1434 1435 Status = IosbToUse->Status; 1436 } 1437 1438 NT_ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status))); 1439 1440 return Status; 1441 } 1442 1443 1444 NTSTATUS 1445 FASTCALL 1446 CdPerformDevIoCtrl ( 1447 _In_ PIRP_CONTEXT IrpContext, 1448 _In_ ULONG IoControlCode, 1449 _In_ PDEVICE_OBJECT Device, 1450 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, 1451 _In_ ULONG OutputBufferLength, 1452 _In_ BOOLEAN InternalDeviceIoControl, 1453 _In_ BOOLEAN OverrideVerify, 1454 _Out_opt_ PIO_STATUS_BLOCK Iosb 1455 ) 1456 { 1457 PAGED_CODE(); 1458 1459 return CdPerformDevIoCtrlEx( IrpContext, 1460 IoControlCode, 1461 Device, 1462 NULL, 1463 0, 1464 OutputBuffer, 1465 OutputBufferLength, 1466 InternalDeviceIoControl, 1467 OverrideVerify, 1468 Iosb); 1469 } 1470 1471 1472 1473 // 1474 // Local support routine 1475 // 1476 1477 _Requires_lock_held_(_Global_critical_region_) 1478 BOOLEAN 1479 CdPrepareBuffers ( 1480 _In_ PIRP_CONTEXT IrpContext, 1481 _In_ PIRP Irp, 1482 _In_ PFCB Fcb, 1483 _In_reads_bytes_(ByteCount) PVOID UserBuffer, 1484 _In_ ULONG UserBufferOffset, 1485 _In_ LONGLONG StartingOffset, 1486 _In_ ULONG ByteCount, 1487 _Out_ PIO_RUN IoRuns, 1488 _Out_ PULONG RunCount, 1489 _Out_ PULONG ThisByteCount 1490 ) 1491 1492 /*++ 1493 1494 Routine Description: 1495 1496 This routine is the worker routine which looks up each run of an IO 1497 request and stores an entry for it in the IoRuns array. If the run 1498 begins on an unaligned disk boundary then we will allocate a buffer 1499 and Mdl for the unaligned portion and put it in the IoRuns entry. 1500 1501 This routine will raise CANT_WAIT if an unaligned transfer is encountered 1502 and this request can't wait. 1503 1504 Arguments: 1505 1506 Irp - Originating Irp for this request. 1507 1508 Fcb - This is the Fcb for this data stream. It may be a file, directory, 1509 path table or the volume file. 1510 1511 UserBuffer - Current position in the user's buffer. 1512 1513 UserBufferOffset - Offset from the start of the original user buffer. 1514 1515 StartingOffset - Offset in the stream to begin the read. 1516 1517 ByteCount - Number of bytes to read. We will fill the IoRuns array up 1518 to this point. We will stop early if we exceed the maximum number 1519 of parallel Ios we support. 1520 1521 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when 1522 this routine is called. 1523 1524 RunCount - Number of entries in the IoRuns array filled here. 1525 1526 ThisByteCount - Number of bytes described by the IoRun entries. Will 1527 not exceed the ByteCount passed in. 1528 1529 Return Value: 1530 1531 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided 1532 this is synchronous). FALSE otherwise. 1533 1534 --*/ 1535 1536 { 1537 BOOLEAN FoundUnaligned = FALSE; 1538 PIO_RUN ThisIoRun = IoRuns; 1539 1540 // 1541 // Following indicate where we are in the current transfer. Current 1542 // position in the file and number of bytes yet to transfer from 1543 // this position. 1544 // 1545 1546 ULONG RemainingByteCount = ByteCount; 1547 LONGLONG CurrentFileOffset = StartingOffset; 1548 1549 // 1550 // Following indicate the state of the user's buffer. We have 1551 // the destination of the next transfer and its offset in the 1552 // buffer. We also have the next available position in the buffer 1553 // available for a scratch buffer. We will align this up to a sector 1554 // boundary. 1555 // 1556 1557 PVOID CurrentUserBuffer = UserBuffer; 1558 ULONG CurrentUserBufferOffset = UserBufferOffset; 1559 1560 // 1561 // The following is the next contiguous bytes on the disk to 1562 // transfer. Read from the allocation package. 1563 // 1564 1565 LONGLONG DiskOffset = 0; 1566 ULONG CurrentByteCount = RemainingByteCount; 1567 1568 PAGED_CODE(); 1569 1570 // 1571 // Initialize the RunCount and ByteCount. 1572 // 1573 1574 *RunCount = 0; 1575 *ThisByteCount = 0; 1576 1577 // 1578 // Loop while there are more bytes to process or there are 1579 // available entries in the IoRun array. 1580 // 1581 1582 while (TRUE) { 1583 1584 *RunCount += 1; 1585 1586 // 1587 // Initialize the current position in the IoRuns array. 1588 // Find the user's buffer for this portion of the transfer. 1589 // 1590 1591 ThisIoRun->UserBuffer = CurrentUserBuffer; 1592 1593 // 1594 // Find the allocation information for the current offset in the 1595 // stream. 1596 // 1597 1598 CdLookupAllocation( IrpContext, 1599 Fcb, 1600 CurrentFileOffset, 1601 &DiskOffset, 1602 &CurrentByteCount ); 1603 1604 // 1605 // Limit ourselves to the data requested. 1606 // 1607 1608 if (CurrentByteCount > RemainingByteCount) { 1609 1610 CurrentByteCount = RemainingByteCount; 1611 } 1612 1613 // 1614 // Handle the case where this is an unaligned transfer. The 1615 // following must all be true for this to be an aligned transfer. 1616 // 1617 // Disk offset on a 2048 byte boundary (Start of transfer) 1618 // 1619 // Byte count is a multiple of 2048 (Length of transfer) 1620 // 1621 // If the ByteCount is at least one sector then do the 1622 // unaligned transfer only for the tail. We can use the 1623 // user's buffer for the aligned portion. 1624 // 1625 1626 if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) || 1627 (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) && 1628 (CurrentByteCount < SECTOR_SIZE))) { 1629 1630 NT_ASSERT( SafeNodeType(Fcb) != CDFS_NTC_FCB_INDEX); 1631 1632 // 1633 // If we can't wait then raise. 1634 // 1635 1636 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 1637 1638 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); 1639 } 1640 1641 // 1642 // Remember the offset and the number of bytes out of 1643 // the transfer buffer to copy into the user's buffer. 1644 // We will truncate the current read to end on a sector 1645 // boundary. 1646 // 1647 1648 ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset ); 1649 1650 // 1651 // Make sure this transfer ends on a sector boundary. 1652 // 1653 1654 ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset ); 1655 1656 // 1657 // We need to allocate an auxilary buffer for the next sector. 1658 // Read up to a page containing the partial data. 1659 // 1660 1661 ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount ); 1662 1663 if (ThisIoRun->DiskByteCount > PAGE_SIZE) { 1664 1665 ThisIoRun->DiskByteCount = PAGE_SIZE; 1666 } 1667 1668 if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) { 1669 1670 CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset; 1671 } 1672 1673 ThisIoRun->TransferByteCount = CurrentByteCount; 1674 1675 // 1676 // Allocate a buffer for the non-aligned transfer. 1677 // 1678 1679 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER ); 1680 1681 // 1682 // Allocate and build the Mdl to describe this buffer. 1683 // 1684 1685 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer, 1686 PAGE_SIZE, 1687 FALSE, 1688 FALSE, 1689 NULL ); 1690 1691 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer; 1692 1693 if (ThisIoRun->TransferMdl == NULL) { 1694 1695 IrpContext->Irp->IoStatus.Information = 0; 1696 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 1697 } 1698 1699 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl ); 1700 1701 // 1702 // Remember we found an unaligned transfer. 1703 // 1704 1705 FoundUnaligned = TRUE; 1706 1707 // 1708 // Otherwise we use the buffer and Mdl from the original request. 1709 // 1710 1711 } else { 1712 1713 // 1714 // Truncate the read length to a sector-aligned value. We know 1715 // the length must be at least one sector or we wouldn't be 1716 // here now. 1717 // 1718 1719 CurrentByteCount = SectorTruncate( CurrentByteCount ); 1720 1721 // 1722 // Read these sectors from the disk. 1723 // 1724 1725 ThisIoRun->DiskOffset = DiskOffset; 1726 ThisIoRun->DiskByteCount = CurrentByteCount; 1727 1728 // 1729 // Use the user's buffer and Mdl as our transfer buffer 1730 // and Mdl. 1731 // 1732 1733 ThisIoRun->TransferBuffer = CurrentUserBuffer; 1734 ThisIoRun->TransferMdl = Irp->MdlAddress; 1735 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer, 1736 CurrentUserBufferOffset, 1737 PVOID ); 1738 } 1739 1740 // 1741 // Update our position in the transfer and the RunCount and 1742 // ByteCount for the user. 1743 // 1744 1745 RemainingByteCount -= CurrentByteCount; 1746 1747 // 1748 // Break out if no more positions in the IoRuns array or 1749 // we have all of the bytes accounted for. 1750 // 1751 1752 *ThisByteCount += CurrentByteCount; 1753 1754 if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) { 1755 1756 break; 1757 } 1758 1759 // 1760 // Update our pointers for the user's buffer. 1761 // 1762 1763 ThisIoRun += 1; 1764 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID ); 1765 CurrentUserBufferOffset += CurrentByteCount; 1766 CurrentFileOffset += CurrentByteCount; 1767 } 1768 1769 return FoundUnaligned; 1770 } 1771 1772 1773 // 1774 // Local support routine 1775 // 1776 1777 _Requires_lock_held_(_Global_critical_region_) 1778 VOID 1779 CdPrepareXABuffers ( 1780 _In_ PIRP_CONTEXT IrpContext, 1781 _In_ PIRP Irp, 1782 _In_ PFCB Fcb, 1783 _In_reads_bytes_(ByteCount) PVOID UserBuffer, 1784 _In_ ULONG UserBufferOffset, 1785 _In_ LONGLONG StartingOffset, 1786 _In_ ULONG ByteCount, 1787 _Out_ PIO_RUN IoRuns, 1788 _Out_ PULONG RunCount, 1789 _Out_ PULONG ThisByteCount 1790 ) 1791 1792 /*++ 1793 1794 Routine Description: 1795 1796 This routine is the worker routine which looks up the individual runs 1797 of an IO request and stores an entry for it in the IoRuns array. The 1798 worker routine is for XA files where we need to convert the raw offset 1799 in the file to logical cooked sectors. We store one raw sector in 1800 the Vcb. If the current read is to that sector then we can simply copy 1801 whatever bytes are needed from that sector. 1802 1803 Arguments: 1804 1805 Irp - Originating Irp for this request. 1806 1807 Fcb - This is the Fcb for this data stream. It must be a data stream. 1808 1809 UserBuffer - Current position in the user's buffer. 1810 1811 UserBufferOffset - Offset of this buffer from the beginning of the user's 1812 buffer for the original request. 1813 1814 StartingOffset - Offset in the stream to begin the read. 1815 1816 ByteCount - Number of bytes to read. We will fill the IoRuns array up 1817 to this point. We will stop early if we exceed the maximum number 1818 of parallel Ios we support. 1819 1820 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when 1821 this routine is called. 1822 1823 RunCount - Number of entries in the IoRuns array filled here. 1824 1825 ThisByteCount - Number of bytes described by the IoRun entries. Will 1826 not exceed the ByteCount passed in. 1827 1828 Return Value: 1829 1830 None 1831 1832 --*/ 1833 1834 { 1835 PIO_RUN ThisIoRun = IoRuns; 1836 BOOLEAN PerformedCopy; 1837 1838 // 1839 // The following deal with where we are in the range of raw sectors. 1840 // Note that we will bias the input file offset by the RIFF header 1841 // to deal directly with the raw sectors. 1842 // 1843 1844 ULONG RawSectorOffset; 1845 ULONG RemainingRawByteCount = ByteCount; 1846 LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER ); 1847 1848 // 1849 // The following is the offset into the cooked sectors for the file. 1850 // 1851 1852 LONGLONG CurrentCookedOffset; 1853 ULONG RemainingCookedByteCount; 1854 1855 // 1856 // Following indicate the state of the user's buffer. We have 1857 // the destination of the next transfer and its offset in the 1858 // buffer. We also have the next available position in the buffer 1859 // available for a scratch buffer. 1860 // 1861 1862 PVOID CurrentUserBuffer = UserBuffer; 1863 ULONG CurrentUserBufferOffset = UserBufferOffset; 1864 1865 // 1866 // The following is the next contiguous bytes on the disk to 1867 // transfer. These are represented by cooked byte offset and length. 1868 // We also compute the number of raw bytes in the current transfer. 1869 // 1870 1871 LONGLONG DiskOffset = 0; 1872 ULONG CurrentCookedByteCount = 0; 1873 ULONG CurrentRawByteCount; 1874 1875 PAGED_CODE(); 1876 1877 // 1878 // We need to maintain our position as we walk through the sectors on the disk. 1879 // We keep separate values for the cooked offset as well as the raw offset. 1880 // These are initialized on sector boundaries and we move through these 1881 // the file sector-by-sector. 1882 // 1883 // Try to do 32-bit math. 1884 // 1885 1886 if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) { 1887 1888 // 1889 // Prefix/fast: Note that the following are safe since we only 1890 // take this path for 32bit offsets. 1891 // 1892 1893 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE); 1894 1895 #ifdef _MSC_VER 1896 #pragma prefast( suppress: __WARNING_RESULTOFSHIFTCASTTOLARGERSIZE, "This is fine beacuse raw sector size > sector shift" ) 1897 #endif 1898 CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT ); 1899 1900 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE); 1901 1902 // 1903 // Otherwise we need to do 64-bit math (sigh). 1904 // 1905 1906 } else { 1907 1908 CurrentRawOffset /= RAW_SECTOR_SIZE; 1909 1910 CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT; 1911 1912 CurrentRawOffset *= RAW_SECTOR_SIZE; 1913 } 1914 1915 // 1916 // Now compute the full number of sectors to be read. Count all of the raw 1917 // sectors that need to be read and convert to cooked bytes. 1918 // 1919 1920 RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER ); 1921 CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE; 1922 1923 RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT; 1924 1925 // 1926 // Initialize the RunCount and ByteCount. 1927 // 1928 1929 *RunCount = 0; 1930 *ThisByteCount = 0; 1931 1932 // 1933 // Loop while there are more bytes to process or there are 1934 // available entries in the IoRun array. 1935 // 1936 1937 while (TRUE) { 1938 1939 PerformedCopy = FALSE; 1940 *RunCount += 1; 1941 1942 // 1943 // Initialize the current position in the IoRuns array. Find the 1944 // eventual destination in the user's buffer for this portion of the transfer. 1945 // 1946 1947 ThisIoRun->UserBuffer = CurrentUserBuffer; 1948 1949 // 1950 // Find the allocation information for the current offset in the 1951 // stream. 1952 // 1953 1954 CdLookupAllocation( IrpContext, 1955 Fcb, 1956 CurrentCookedOffset, 1957 &DiskOffset, 1958 &CurrentCookedByteCount ); 1959 // 1960 // Maybe we got lucky and this is the same sector as in the 1961 // Vcb. 1962 // 1963 1964 if (DiskOffset == Fcb->Vcb->XADiskOffset) { 1965 1966 // 1967 // We will perform safe synchronization. Check again that 1968 // this is the correct sector. 1969 // 1970 1971 CdLockVcb( IrpContext, Fcb->Vcb ); 1972 1973 if ((DiskOffset == Fcb->Vcb->XADiskOffset) && 1974 (Fcb->Vcb->XASector != NULL)) { 1975 1976 // 1977 // Copy any bytes we can from the current sector. 1978 // 1979 1980 CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset; 1981 1982 // 1983 // Check whether we don't go to the end of the sector. 1984 // 1985 1986 if (CurrentRawByteCount > RemainingRawByteCount) { 1987 1988 CurrentRawByteCount = RemainingRawByteCount; 1989 } 1990 1991 RtlCopyMemory( CurrentUserBuffer, 1992 Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ), 1993 CurrentRawByteCount ); 1994 1995 CdUnlockVcb( IrpContext, Fcb->Vcb ); 1996 1997 // 1998 // Adjust the run count and pointer in the IoRuns array 1999 // to show that we didn't use a position. 2000 // 2001 2002 *RunCount -= 1; 2003 ThisIoRun -= 1; 2004 2005 // 2006 // Remember that we performed a copy operation. 2007 // 2008 2009 PerformedCopy = TRUE; 2010 2011 CurrentCookedByteCount = SECTOR_SIZE; 2012 2013 } else { 2014 2015 // 2016 // The safe test showed no available buffer. Drop down to common code to 2017 // perform the Io. 2018 // 2019 2020 CdUnlockVcb( IrpContext, Fcb->Vcb ); 2021 } 2022 } 2023 2024 // 2025 // No work in this pass if we did a copy operation. 2026 // 2027 2028 if (!PerformedCopy) { 2029 2030 // 2031 // Limit ourselves by the number of remaining cooked bytes. 2032 // 2033 2034 if (CurrentCookedByteCount > RemainingCookedByteCount) { 2035 2036 CurrentCookedByteCount = RemainingCookedByteCount; 2037 } 2038 2039 ThisIoRun->DiskOffset = DiskOffset; 2040 ThisIoRun->TransferBufferOffset = RawSectorOffset; 2041 2042 // 2043 // We will always need to perform copy operations for XA files. 2044 // We allocate an auxillary buffer to read the start of the 2045 // transfer. Then we can use a range of the user's buffer to 2046 // perform the next range of the transfer. Finally we may 2047 // need to allocate a buffer for the tail of the transfer. 2048 // 2049 // We can use the user's buffer (at the current scratch buffer) if the 2050 // following are true: 2051 // 2052 // If we are to store the beginning of the raw sector in the user's buffer. 2053 // The current scratch buffer precedes the destination in the user's buffer 2054 // (and hence also lies within it) 2055 // There are enough bytes remaining in the buffer for at least one 2056 // raw sector. 2057 // 2058 2059 if ((RawSectorOffset == 0) && 2060 (RemainingRawByteCount >= RAW_SECTOR_SIZE)) { 2061 2062 // 2063 // We can use the scratch buffer. We must ensure we don't send down reads 2064 // greater than the device can handle, since the driver is unable to split 2065 // raw requests. 2066 // 2067 2068 if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) { 2069 2070 CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE; 2071 2072 } else { 2073 2074 CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE; 2075 CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE; 2076 } 2077 2078 // 2079 // Now make sure we are within the page transfer limit. 2080 // 2081 2082 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentUserBuffer, RawSectorAlign( CurrentRawByteCount)) > 2083 Fcb->Vcb->MaximumPhysicalPages ) { 2084 2085 CurrentRawByteCount -= RAW_SECTOR_SIZE; 2086 CurrentCookedByteCount -= SECTOR_SIZE; 2087 } 2088 2089 // 2090 // Trim the number of bytes to read if it won't fit into the current buffer. Take 2091 // account of the fact that we must read in whole raw sector multiples. 2092 // 2093 2094 while (RawSectorAlign( CurrentRawByteCount) > RemainingRawByteCount) { 2095 2096 CurrentRawByteCount -= RAW_SECTOR_SIZE; 2097 CurrentCookedByteCount -= SECTOR_SIZE; 2098 } 2099 2100 // 2101 // Now trim the maximum number of raw bytes to the remaining bytes. 2102 // 2103 2104 if (CurrentRawByteCount > RemainingRawByteCount) { 2105 2106 CurrentRawByteCount = RemainingRawByteCount; 2107 } 2108 2109 // 2110 // Update the IO run array. We point to the scratch buffer as 2111 // well as the buffer and Mdl in the original Irp. 2112 // 2113 2114 ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount); 2115 2116 // 2117 // Point to the user's buffer and Mdl for this transfer. 2118 // 2119 2120 ThisIoRun->TransferBuffer = CurrentUserBuffer; 2121 ThisIoRun->TransferMdl = Irp->MdlAddress; 2122 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer, 2123 CurrentUserBufferOffset, 2124 PVOID); 2125 2126 } else { 2127 2128 // 2129 // We need to determine the number of bytes to transfer and the 2130 // offset into this page to begin the transfer. 2131 // 2132 // We will transfer only one raw sector. 2133 // 2134 2135 ThisIoRun->DiskByteCount = SECTOR_SIZE; 2136 2137 CurrentCookedByteCount = SECTOR_SIZE; 2138 2139 ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset; 2140 ThisIoRun->TransferBufferOffset = RawSectorOffset; 2141 2142 if (ThisIoRun->TransferByteCount > RemainingRawByteCount) { 2143 2144 ThisIoRun->TransferByteCount = RemainingRawByteCount; 2145 } 2146 2147 CurrentRawByteCount = ThisIoRun->TransferByteCount; 2148 2149 // 2150 // We need to allocate an auxillary buffer. We will allocate 2151 // a single page. Then we will build an Mdl to describe the buffer. 2152 // 2153 2154 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER ); 2155 2156 // 2157 // Allocate and build the Mdl to describe this buffer. 2158 // 2159 2160 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer, 2161 PAGE_SIZE, 2162 FALSE, 2163 FALSE, 2164 NULL ); 2165 2166 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer; 2167 2168 if (ThisIoRun->TransferMdl == NULL) { 2169 2170 IrpContext->Irp->IoStatus.Information = 0; 2171 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 2172 } 2173 2174 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl ); 2175 } 2176 } 2177 2178 // 2179 // Update the byte count for our caller. 2180 // 2181 2182 RemainingRawByteCount -= CurrentRawByteCount; 2183 *ThisByteCount += CurrentRawByteCount; 2184 2185 // 2186 // Break out if no more positions in the IoRuns array or 2187 // we have all of the bytes accounted for. 2188 // 2189 2190 if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) { 2191 2192 break; 2193 } 2194 2195 // 2196 // Update our local pointers to allow for the current range of bytes. 2197 // 2198 2199 ThisIoRun += 1; 2200 2201 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID ); 2202 CurrentUserBufferOffset += CurrentRawByteCount; 2203 2204 RawSectorOffset = 0; 2205 2206 CurrentCookedOffset += CurrentCookedByteCount; 2207 RemainingCookedByteCount -= CurrentCookedByteCount; 2208 } 2209 2210 return; 2211 } 2212 2213 2214 // 2215 // Local support routine 2216 // 2217 2218 BOOLEAN 2219 CdFinishBuffers ( 2220 _In_ PIRP_CONTEXT IrpContext, 2221 _Inout_ PIO_RUN IoRuns, 2222 _In_ ULONG RunCount, 2223 _In_ BOOLEAN FinalCleanup, 2224 _In_ BOOLEAN SaveXABuffer 2225 ) 2226 2227 /*++ 2228 2229 Routine Description: 2230 2231 This routine is called to perform any data transferred required for 2232 unaligned Io or to perform the final cleanup of the IoRuns array. 2233 2234 In all cases this is where we will deallocate any buffer and mdl 2235 allocated to perform the unaligned transfer. If this is not the 2236 final cleanup then we also transfer the bytes to the user buffer 2237 and flush the hardware cache. 2238 2239 We walk backwards through the run array because we may be shifting data 2240 in the user's buffer. Typical case is where we allocated a buffer for 2241 the first part of a read and then used the user's buffer for the 2242 next section (but stored it at the beginning of the buffer. 2243 2244 Arguments: 2245 2246 IoRuns - Pointer to the IoRuns array. 2247 2248 RunCount - Number of entries in the IoRuns array filled here. 2249 2250 FinalCleanup - Indicates if we should be deallocating temporary buffers 2251 (TRUE) or transferring bytes for a unaligned transfers and 2252 deallocating the buffers (FALSE). Flush the system cache if 2253 transferring data. 2254 2255 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise 2256 2257 Return Value: 2258 2259 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise. 2260 2261 --*/ 2262 2263 { 2264 BOOLEAN FlushIoBuffers = FALSE; 2265 2266 ULONG RemainingEntries = RunCount; 2267 PIO_RUN ThisIoRun = &IoRuns[RunCount - 1]; 2268 PVCB Vcb; 2269 2270 PAGED_CODE(); 2271 2272 // 2273 // Walk through each entry in the IoRun array. 2274 // 2275 2276 while (RemainingEntries != 0) { 2277 2278 // 2279 // We only need to deal with the case of an unaligned transfer. 2280 // 2281 2282 if (ThisIoRun->TransferByteCount != 0) { 2283 2284 // 2285 // If not the final cleanup then transfer the data to the 2286 // user's buffer and remember that we will need to flush 2287 // the user's buffer to memory. 2288 // 2289 2290 if (!FinalCleanup) { 2291 2292 RtlCopyMemory( ThisIoRun->UserBuffer, 2293 Add2Ptr( ThisIoRun->TransferBuffer, 2294 ThisIoRun->TransferBufferOffset, 2295 PVOID ), 2296 ThisIoRun->TransferByteCount ); 2297 2298 FlushIoBuffers = TRUE; 2299 } 2300 2301 // 2302 // Free any Mdl we may have allocated. If the Mdl isn't 2303 // present then we must have failed during the allocation 2304 // phase. 2305 // 2306 2307 if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) { 2308 2309 if (ThisIoRun->TransferMdl != NULL) { 2310 2311 IoFreeMdl( ThisIoRun->TransferMdl ); 2312 } 2313 2314 // 2315 // Now free any buffer we may have allocated. If the Mdl 2316 // doesn't match the original Mdl then free the buffer. 2317 // 2318 2319 if (ThisIoRun->TransferBuffer != NULL) { 2320 2321 // 2322 // If this is the final buffer for an XA read then store this buffer 2323 // into the Vcb so that we will have it when reading any remaining 2324 // portion of this buffer. 2325 // 2326 2327 if (SaveXABuffer) { 2328 2329 Vcb = IrpContext->Vcb; 2330 2331 CdLockVcb( IrpContext, Vcb ); 2332 2333 if (Vcb->XASector != NULL) { 2334 2335 CdFreePool( &Vcb->XASector ); 2336 } 2337 2338 Vcb->XASector = ThisIoRun->TransferBuffer; 2339 Vcb->XADiskOffset = ThisIoRun->DiskOffset; 2340 2341 SaveXABuffer = FALSE; 2342 2343 CdUnlockVcb( IrpContext, Vcb ); 2344 2345 // 2346 // Otherwise just free the buffer. 2347 // 2348 2349 } else { 2350 2351 CdFreePool( &ThisIoRun->TransferBuffer ); 2352 } 2353 } 2354 } 2355 } 2356 2357 // 2358 // Now handle the case where we failed in the process 2359 // of allocating associated Irps and Mdls. 2360 // 2361 2362 if (ThisIoRun->SavedIrp != NULL) { 2363 2364 if (ThisIoRun->SavedIrp->MdlAddress != NULL) { 2365 2366 IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress ); 2367 } 2368 2369 IoFreeIrp( ThisIoRun->SavedIrp ); 2370 } 2371 2372 // 2373 // Move to the previous IoRun entry. 2374 // 2375 2376 ThisIoRun -= 1; 2377 RemainingEntries -= 1; 2378 } 2379 2380 // 2381 // If we copied any data then flush the Io buffers. 2382 // 2383 2384 return FlushIoBuffers; 2385 } 2386 2387 // Tell prefast this is a completion routine. 2388 IO_COMPLETION_ROUTINE CdSyncCompletionRoutine; 2389 2390 NTSTATUS 2391 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2392 CdSyncCompletionRoutine ( 2393 PDEVICE_OBJECT DeviceObject, 2394 PIRP Irp, 2395 PVOID Contxt 2396 ) 2397 2398 /*++ 2399 2400 Routine Description: 2401 2402 Completion routine for synchronizing back to dispatch. 2403 2404 Arguments: 2405 2406 Contxt - pointer to KEVENT. 2407 2408 Return Value: 2409 2410 STATUS_MORE_PROCESSING_REQUIRED 2411 2412 --*/ 2413 2414 { 2415 PKEVENT Event = (PKEVENT)Contxt; 2416 _Analysis_assume_(Contxt != NULL); 2417 2418 UNREFERENCED_PARAMETER( Irp ); 2419 UNREFERENCED_PARAMETER( DeviceObject ); 2420 2421 KeSetEvent( Event, 0, FALSE ); 2422 2423 // 2424 // We don't want IO to get our IRP and free it. 2425 // 2426 2427 return STATUS_MORE_PROCESSING_REQUIRED; 2428 } 2429 2430 2431 _Requires_lock_held_(_Global_critical_region_) 2432 VOID 2433 CdFreeDirCache ( 2434 _In_ PIRP_CONTEXT IrpContext 2435 ) 2436 2437 /*++ 2438 2439 Routine Description: 2440 2441 Safely frees the sector cache buffer. 2442 2443 Arguments: 2444 2445 Return Value: 2446 2447 None. 2448 2449 --*/ 2450 2451 { 2452 PAGED_CODE(); 2453 2454 if (NULL != IrpContext->Vcb->SectorCacheBuffer) { 2455 2456 CdAcquireCacheForUpdate( IrpContext); 2457 CdFreePool( &IrpContext->Vcb->SectorCacheBuffer); 2458 CdReleaseCache( IrpContext); 2459 } 2460 } 2461 2462 _Requires_lock_held_(_Global_critical_region_) 2463 BOOLEAN 2464 CdReadDirDataThroughCache ( 2465 _In_ PIRP_CONTEXT IrpContext, 2466 _In_ PIO_RUN Run 2467 ) 2468 2469 /*++ 2470 2471 Routine Description: 2472 2473 Reads blocks through the sector cache. If the data is present, then it 2474 is copied from memory. If not present, one of the cache chunks will be 2475 replaced with a chunk containing the requested region, and the data 2476 copied from there. 2477 2478 Only intended for reading *directory* blocks, for the purpose of pre-caching 2479 directory information, by reading a chunk of blocks which hopefully contains 2480 other directory blocks, rather than just the (usually) single block requested. 2481 2482 Arguments: 2483 2484 Run - description of extent required, and buffer to read into. 2485 2486 Return Value: 2487 2488 None. Raises on error. 2489 2490 --*/ 2491 2492 { 2493 PVCB Vcb = IrpContext->Vcb; 2494 ULONG Lbn = SectorsFromLlBytes( Run->DiskOffset); 2495 ULONG Remaining = SectorsFromBytes( Run->DiskByteCount); 2496 PUCHAR UserBuffer = Run->TransferBuffer; 2497 2498 NTSTATUS Status; 2499 ULONG Found; 2500 ULONG BufferSectorOffset; 2501 ULONG StartBlock; 2502 ULONG EndBlock; 2503 ULONG Blocks; 2504 2505 PIO_STACK_LOCATION IrpSp; 2506 IO_STATUS_BLOCK Iosb; 2507 2508 PTRACK_DATA TrackData; 2509 2510 #if DBG 2511 BOOLEAN JustRead = FALSE; 2512 #endif 2513 2514 ULONG Index; 2515 PCD_SECTOR_CACHE_CHUNK Buffer; 2516 BOOLEAN Result = FALSE; 2517 2518 PAGED_CODE(); 2519 2520 CdAcquireCacheForRead( IrpContext); 2521 2522 _SEH2_TRY { 2523 2524 // 2525 // Check the cache hasn't gone away due to volume verify failure (which 2526 // is the *only* reason it'll go away). If this is the case we raise 2527 // the same error any I/O would return if the cache weren't here. 2528 // 2529 2530 if (NULL == Vcb->SectorCacheBuffer) { 2531 2532 CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED); 2533 } 2534 2535 while (Remaining) { 2536 2537 Buffer = NULL; 2538 2539 // 2540 // Look to see if any portion is currently cached. 2541 // 2542 2543 for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) { 2544 2545 if ((Vcb->SecCacheChunks[ Index].BaseLbn != -1) && 2546 (Vcb->SecCacheChunks[ Index].BaseLbn <= Lbn) && 2547 ((Vcb->SecCacheChunks[ Index].BaseLbn + CD_SEC_CHUNK_BLOCKS) > Lbn)) { 2548 2549 Buffer = &Vcb->SecCacheChunks[ Index]; 2550 break; 2551 } 2552 } 2553 2554 // 2555 // If we found any, copy it out and continue. 2556 // 2557 2558 if (NULL != Buffer) { 2559 2560 BufferSectorOffset = Lbn - Buffer->BaseLbn; 2561 Found = Min( CD_SEC_CHUNK_BLOCKS - BufferSectorOffset, Remaining); 2562 2563 RtlCopyMemory( UserBuffer, 2564 Buffer->Buffer + BytesFromSectors( BufferSectorOffset), 2565 BytesFromSectors( Found)); 2566 2567 Remaining -= Found; 2568 UserBuffer += BytesFromSectors( Found); 2569 Lbn += Found; 2570 #if DBG 2571 // 2572 // Update stats. Don't count a hit if we've just read the data in. 2573 // 2574 2575 if (!JustRead) { 2576 2577 InterlockedIncrement( (LONG*)&Vcb->SecCacheHits); 2578 } 2579 2580 JustRead = FALSE; 2581 #endif 2582 continue; 2583 } 2584 2585 // 2586 // Missed the cache, so we need to read a new chunk. Take the cache 2587 // resource exclusive while we do so. 2588 // 2589 2590 CdReleaseCache( IrpContext); 2591 CdAcquireCacheForUpdate( IrpContext); 2592 #if DBG 2593 Vcb->SecCacheMisses += 1; 2594 #endif 2595 // 2596 // Select the chunk to replace and calculate the start block of the 2597 // chunk to cache. We cache blocks which start on Lbns aligned on 2598 // multiples of chunk size, treating block 16 (VRS start) as block 2599 // zero. 2600 // 2601 2602 Buffer = &Vcb->SecCacheChunks[ Vcb->SecCacheLRUChunkIndex]; 2603 2604 StartBlock = Lbn - ((Lbn - 16) % CD_SEC_CHUNK_BLOCKS); 2605 2606 // 2607 // Make sure we don't try and read past end of the last track. 2608 // 2609 2610 #ifdef __REACTOS__ 2611 if (Vcb->CdromToc) { 2612 #endif 2613 TrackData = &Vcb->CdromToc->TrackData[(Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack + 1)]; 2614 2615 SwapCopyUchar4( &EndBlock, &TrackData->Address ); 2616 2617 Blocks = EndBlock - StartBlock; 2618 2619 if (Blocks > CD_SEC_CHUNK_BLOCKS) { 2620 2621 Blocks = CD_SEC_CHUNK_BLOCKS; 2622 } 2623 #ifdef __REACTOS__ 2624 } else { 2625 // HACK!!!!!!!! Might cause reads to overrun the end of the partition, no idea what consequences that can have. 2626 Blocks = CD_SEC_CHUNK_BLOCKS; 2627 } 2628 #endif 2629 2630 if ((0 == Blocks) || (Lbn < 16)) { 2631 2632 CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER); 2633 } 2634 2635 // 2636 // Now build / send the read request. 2637 // 2638 2639 IoReuseIrp( Vcb->SectorCacheIrp, STATUS_SUCCESS); 2640 2641 KeClearEvent( &Vcb->SectorCacheEvent); 2642 Vcb->SectorCacheIrp->Tail.Overlay.Thread = PsGetCurrentThread(); 2643 2644 // 2645 // Get a pointer to the stack location of the first driver which will be 2646 // invoked. This is where the function codes and the parameters are set. 2647 // 2648 2649 IrpSp = IoGetNextIrpStackLocation( Vcb->SectorCacheIrp); 2650 IrpSp->MajorFunction = (UCHAR) IRP_MJ_READ; 2651 2652 // 2653 // Build an MDL to describe the buffer. 2654 // 2655 2656 IoAllocateMdl( Buffer->Buffer, 2657 BytesFromSectors( Blocks), 2658 FALSE, 2659 FALSE, 2660 Vcb->SectorCacheIrp); 2661 2662 if (NULL == Vcb->SectorCacheIrp->MdlAddress) { 2663 2664 IrpContext->Irp->IoStatus.Information = 0; 2665 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES); 2666 } 2667 2668 // 2669 // We're reading/writing into the block cache (paged pool). Lock the 2670 // pages and update the MDL with physical page information. 2671 // 2672 2673 _SEH2_TRY { 2674 2675 MmProbeAndLockPages( Vcb->SectorCacheIrp->MdlAddress, 2676 KernelMode, 2677 (LOCK_OPERATION) IoWriteAccess ); 2678 } 2679 #ifdef _MSC_VER 2680 #pragma warning(suppress: 6320) 2681 #endif 2682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 2683 2684 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress ); 2685 Vcb->SectorCacheIrp->MdlAddress = NULL; 2686 } _SEH2_END; 2687 2688 if (NULL == Vcb->SectorCacheIrp->MdlAddress) { 2689 2690 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 2691 } 2692 2693 // 2694 // Reset the BaseLbn as we can't trust this Buffer's data until the request 2695 // is successfully completed. 2696 // 2697 2698 Buffer->BaseLbn = (ULONG)-1; 2699 2700 IrpSp->Parameters.Read.Length = BytesFromSectors( Blocks); 2701 IrpSp->Parameters.Read.ByteOffset.QuadPart = LlBytesFromSectors( StartBlock); 2702 2703 IoSetCompletionRoutine( Vcb->SectorCacheIrp, 2704 CdSyncCompletionRoutine, 2705 &Vcb->SectorCacheEvent, 2706 TRUE, 2707 TRUE, 2708 TRUE ); 2709 2710 Vcb->SectorCacheIrp->UserIosb = &Iosb; 2711 2712 Status = IoCallDriver( Vcb->TargetDeviceObject, Vcb->SectorCacheIrp ); 2713 2714 if (STATUS_PENDING == Status) { 2715 2716 2717 (VOID)KeWaitForSingleObject( &Vcb->SectorCacheEvent, 2718 Executive, 2719 KernelMode, 2720 FALSE, 2721 NULL ); 2722 2723 Status = Vcb->SectorCacheIrp->IoStatus.Status; 2724 } 2725 2726 Vcb->SectorCacheIrp->UserIosb = NULL; 2727 2728 // 2729 // Unlock the pages and free the MDL. 2730 // 2731 2732 MmUnlockPages( Vcb->SectorCacheIrp->MdlAddress ); 2733 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress ); 2734 Vcb->SectorCacheIrp->MdlAddress = NULL; 2735 2736 if (!NT_SUCCESS( Status )) { 2737 2738 try_leave( Status ); 2739 } 2740 2741 // 2742 // Update the buffer information, and drop the cache resource to shared 2743 // to allow in reads. 2744 // 2745 2746 Buffer->BaseLbn = StartBlock; 2747 Vcb->SecCacheLRUChunkIndex = (Vcb->SecCacheLRUChunkIndex + 1) % CD_SEC_CACHE_CHUNKS; 2748 2749 CdConvertCacheToShared( IrpContext); 2750 #if DBG 2751 JustRead = TRUE; 2752 #endif 2753 } 2754 2755 Result = TRUE; 2756 } 2757 _SEH2_FINALLY { 2758 2759 CdReleaseCache( IrpContext); 2760 } _SEH2_END; 2761 2762 return Result; 2763 } 2764 2765 2766 // 2767 // Local support routine 2768 // 2769 2770 _Requires_lock_held_(_Global_critical_region_) 2771 VOID 2772 CdMultipleAsync ( 2773 _In_ PIRP_CONTEXT IrpContext, 2774 _In_ PFCB Fcb, 2775 _In_ ULONG RunCount, 2776 _Inout_ PIO_RUN IoRuns 2777 ) 2778 2779 /*++ 2780 2781 Routine Description: 2782 2783 This routine first does the initial setup required of a Master IRP that is 2784 going to be completed using associated IRPs. This routine should not 2785 be used if only one async request is needed, instead the single read 2786 async routines should be called. 2787 2788 A context parameter is initialized, to serve as a communications area 2789 between here and the common completion routine. 2790 2791 Next this routine reads or writes one or more contiguous sectors from 2792 a device asynchronously, and is used if there are multiple reads for a 2793 master IRP. A completion routine is used to synchronize with the 2794 completion of all of the I/O requests started by calls to this routine. 2795 2796 Also, prior to calling this routine the caller must initialize the 2797 IoStatus field in the Context, with the correct success status and byte 2798 count which are expected if all of the parallel transfers complete 2799 successfully. After return this status will be unchanged if all requests 2800 were, in fact, successful. However, if one or more errors occur, the 2801 IoStatus will be modified to reflect the error status and byte count 2802 from the first run (by Vbo) which encountered an error. I/O status 2803 from all subsequent runs will not be indicated. 2804 2805 Arguments: 2806 2807 RunCount - Supplies the number of multiple async requests 2808 that will be issued against the master irp. 2809 2810 IoRuns - Supplies an array containing the Offset and ByteCount for the 2811 separate requests. 2812 2813 Return Value: 2814 2815 None. 2816 2817 --*/ 2818 2819 { 2820 PIO_COMPLETION_ROUTINE CompletionRoutine; 2821 PIO_STACK_LOCATION IrpSp; 2822 PMDL Mdl; 2823 PIRP Irp; 2824 PIRP MasterIrp; 2825 ULONG UnwindRunCount; 2826 BOOLEAN UseSectorCache; 2827 2828 PAGED_CODE(); 2829 2830 // 2831 // Set up things according to whether this is truely async. 2832 // 2833 2834 CompletionRoutine = CdMultiSyncCompletionRoutine; 2835 2836 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 2837 2838 CompletionRoutine = CdMultiAsyncCompletionRoutine; 2839 } 2840 2841 // 2842 // For directories, use the sector cache. 2843 // 2844 2845 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) && 2846 (NULL != Fcb->Vcb->SectorCacheBuffer) && 2847 (VcbMounted == IrpContext->Vcb->VcbCondition)) { 2848 2849 UseSectorCache = TRUE; 2850 } 2851 else { 2852 2853 UseSectorCache = FALSE; 2854 } 2855 2856 // 2857 // Initialize some local variables. 2858 // 2859 2860 MasterIrp = IrpContext->Irp; 2861 2862 // 2863 // Itterate through the runs, doing everything that can fail. 2864 // We let the cleanup in CdFinishBuffers clean up on error. 2865 // 2866 2867 for (UnwindRunCount = 0; 2868 UnwindRunCount < RunCount; 2869 UnwindRunCount += 1) { 2870 2871 if (UseSectorCache) { 2872 2873 if (!CdReadDirDataThroughCache( IrpContext, &IoRuns[ UnwindRunCount])) { 2874 2875 // 2876 // Turn off using directory cache and restart all over again. 2877 // 2878 2879 UseSectorCache = FALSE; 2880 UnwindRunCount = 0; 2881 } 2882 2883 continue; 2884 } 2885 2886 // 2887 // Create an associated IRP, making sure there is one stack entry for 2888 // us, as well. 2889 // 2890 2891 IoRuns[UnwindRunCount].SavedIrp = 2892 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) ); 2893 2894 if (Irp == NULL) { 2895 2896 IrpContext->Irp->IoStatus.Information = 0; 2897 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 2898 } 2899 2900 // 2901 // Allocate and build a partial Mdl for the request. 2902 // 2903 2904 Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress, 2905 IoRuns[UnwindRunCount].DiskByteCount, 2906 FALSE, 2907 FALSE, 2908 Irp ); 2909 2910 if (Mdl == NULL) { 2911 2912 IrpContext->Irp->IoStatus.Information = 0; 2913 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 2914 } 2915 2916 IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl, 2917 Mdl, 2918 IoRuns[UnwindRunCount].TransferVirtualAddress, 2919 IoRuns[UnwindRunCount].DiskByteCount ); 2920 2921 // 2922 // Get the first IRP stack location in the associated Irp 2923 // 2924 2925 IoSetNextIrpStackLocation( Irp ); 2926 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2927 2928 // 2929 // Setup the Stack location to describe our read. 2930 // 2931 2932 IrpSp->MajorFunction = IRP_MJ_READ; 2933 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount; 2934 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset; 2935 2936 // 2937 // Set up the completion routine address in our stack frame. 2938 // 2939 2940 IoSetCompletionRoutine( Irp, 2941 CompletionRoutine, 2942 IrpContext->IoContext, 2943 TRUE, 2944 TRUE, 2945 TRUE ); 2946 2947 // 2948 // Setup the next IRP stack location in the associated Irp for the disk 2949 // driver beneath us. 2950 // 2951 2952 IrpSp = IoGetNextIrpStackLocation( Irp ); 2953 2954 // 2955 // Setup the Stack location to do a read from the disk driver. 2956 // 2957 2958 IrpSp->MajorFunction = IRP_MJ_READ; 2959 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount; 2960 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset; 2961 } 2962 2963 // 2964 // If we used the cache, we're done. 2965 // 2966 2967 if (UseSectorCache) { 2968 2969 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { 2970 2971 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS; 2972 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE ); 2973 } 2974 2975 return; 2976 } 2977 2978 // 2979 // We only need to set the associated IRP count in the master irp to 2980 // make it a master IRP. But we set the count to one more than our 2981 // caller requested, because we do not want the I/O system to complete 2982 // the I/O. We also set our own count. 2983 // 2984 2985 IrpContext->IoContext->IrpCount = RunCount; 2986 IrpContext->IoContext->MasterIrp = MasterIrp; 2987 2988 // 2989 // We set the count in the master Irp to 1 since typically we 2990 // will clean up the associated irps ourselves. Setting this to one 2991 // means completing the last associated Irp with SUCCESS (in the async 2992 // case) will complete the master irp. 2993 // 2994 2995 MasterIrp->AssociatedIrp.IrpCount = 1; 2996 2997 // 2998 // If we (FS) acquired locks, transition the lock owners to an object, since 2999 // when we return this thread could go away before request completion, and 3000 // the resource package may otherwise try to boost priority, etc. 3001 // 3002 3003 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ) && 3004 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) { 3005 3006 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() ); 3007 3008 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3; 3009 3010 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource, 3011 (PVOID)IrpContext->IoContext->ResourceThreadId ); 3012 } 3013 3014 // 3015 // Now that all the dangerous work is done, issue the Io requests 3016 // 3017 3018 for (UnwindRunCount = 0; 3019 UnwindRunCount < RunCount; 3020 UnwindRunCount++) { 3021 3022 Irp = IoRuns[UnwindRunCount].SavedIrp; 3023 IoRuns[UnwindRunCount].SavedIrp = NULL; 3024 3025 if (NULL != Irp) { 3026 3027 // 3028 // If IoCallDriver returns an error, it has completed the Irp 3029 // and the error will be caught by our completion routines 3030 // and dealt with as a normal IO error. 3031 // 3032 3033 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp ); 3034 } 3035 } 3036 } 3037 3038 3039 // 3040 // Local support routine 3041 // 3042 3043 VOID 3044 CdMultipleXAAsync ( 3045 _In_ PIRP_CONTEXT IrpContext, 3046 _In_ ULONG RunCount, 3047 _Inout_ PIO_RUN IoRuns, 3048 _In_ PRAW_READ_INFO RawReads, 3049 _In_ TRACK_MODE_TYPE TrackMode 3050 ) 3051 3052 /*++ 3053 3054 Routine Description: 3055 3056 This routine first does the initial setup required of a Master IRP that is 3057 going to be completed using associated IRPs. This routine is used to generate 3058 the associated Irps used to read raw sectors from the disk. 3059 3060 A context parameter is initialized, to serve as a communications area 3061 between here and the common completion routine. 3062 3063 Next this routine reads or writes one or more contiguous sectors from 3064 a device asynchronously, and is used if there are multiple reads for a 3065 master IRP. A completion routine is used to synchronize with the 3066 completion of all of the I/O requests started by calls to this routine. 3067 3068 Also, prior to calling this routine the caller must initialize the 3069 IoStatus field in the Context, with the correct success status and byte 3070 count which are expected if all of the parallel transfers complete 3071 successfully. After return this status will be unchanged if all requests 3072 were, in fact, successful. However, if one or more errors occur, the 3073 IoStatus will be modified to reflect the error status and byte count 3074 from the first run (by Vbo) which encountered an error. I/O status 3075 from all subsequent runs will not be indicated. 3076 3077 Arguments: 3078 3079 RunCount - Supplies the number of multiple async requests 3080 that will be issued against the master irp. 3081 3082 IoRuns - Supplies an array containing the Offset and ByteCount for the 3083 separate requests. 3084 3085 RawReads - Supplies an array of structures to store in the Irps passed to the 3086 device driver to perform the low-level Io. 3087 3088 TrackMode - Supplies the recording mode of sectors in these IoRuns 3089 3090 Return Value: 3091 3092 None. 3093 3094 --*/ 3095 3096 { 3097 PIO_STACK_LOCATION IrpSp; 3098 PMDL Mdl; 3099 PIRP Irp; 3100 PIRP MasterIrp; 3101 ULONG UnwindRunCount; 3102 ULONG RawByteCount; 3103 3104 PIO_RUN ThisIoRun = IoRuns; 3105 PRAW_READ_INFO ThisRawRead = RawReads; 3106 3107 PAGED_CODE(); 3108 3109 // 3110 // Initialize some local variables. 3111 // 3112 3113 MasterIrp = IrpContext->Irp; 3114 3115 // 3116 // Itterate through the runs, doing everything that can fail. 3117 // We let the cleanup in CdFinishBuffers clean up on error. 3118 // 3119 3120 for (UnwindRunCount = 0; 3121 UnwindRunCount < RunCount; 3122 UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) { 3123 3124 // 3125 // Create an associated IRP, making sure there is one stack entry for 3126 // us, as well. 3127 // 3128 3129 ThisIoRun->SavedIrp = 3130 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) ); 3131 3132 if (Irp == NULL) { 3133 3134 IrpContext->Irp->IoStatus.Information = 0; 3135 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 3136 } 3137 3138 // 3139 // Should have been passed a byte count of at least one sector, and 3140 // must be a multiple of sector size 3141 // 3142 3143 NT_ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount)); 3144 3145 RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE; 3146 3147 // 3148 // Allocate and build a partial Mdl for the request. 3149 // 3150 3151 Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress, 3152 RawByteCount, 3153 FALSE, 3154 FALSE, 3155 Irp ); 3156 3157 if (Mdl == NULL) { 3158 3159 IrpContext->Irp->IoStatus.Information = 0; 3160 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 3161 } 3162 3163 IoBuildPartialMdl( ThisIoRun->TransferMdl, 3164 Mdl, 3165 ThisIoRun->TransferVirtualAddress, 3166 RawByteCount); 3167 // 3168 // Get the first IRP stack location in the associated Irp 3169 // 3170 3171 IoSetNextIrpStackLocation( Irp ); 3172 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 3173 3174 // 3175 // Setup the Stack location to describe our read (using cooked values) 3176 // These values won't be used for the raw read in any case. 3177 // 3178 3179 IrpSp->MajorFunction = IRP_MJ_READ; 3180 IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount; 3181 IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset; 3182 3183 // 3184 // Set up the completion routine address in our stack frame. 3185 // 3186 3187 IoSetCompletionRoutine( Irp, 3188 CdMultiSyncCompletionRoutine, 3189 IrpContext->IoContext, 3190 TRUE, 3191 TRUE, 3192 TRUE ); 3193 3194 // 3195 // Setup the next IRP stack location in the associated Irp for the disk 3196 // driver beneath us. 3197 // 3198 3199 IrpSp = IoGetNextIrpStackLocation( Irp ); 3200 3201 // 3202 // Setup the stack location to do a read of raw sectors at this location. 3203 // Note that the storage stack always reads multiples of whole XA sectors. 3204 // 3205 3206 ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset; 3207 ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT; 3208 ThisRawRead->TrackMode = TrackMode; 3209 3210 IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; 3211 3212 IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE; 3213 Irp->UserBuffer = ThisIoRun->TransferVirtualAddress; 3214 3215 IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO ); 3216 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead; 3217 3218 IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ; 3219 } 3220 3221 // 3222 // We only need to set the associated IRP count in the master irp to 3223 // make it a master IRP. But we set the count to one more than our 3224 // caller requested, because we do not want the I/O system to complete 3225 // the I/O. We also set our own count. 3226 // 3227 3228 IrpContext->IoContext->IrpCount = RunCount; 3229 IrpContext->IoContext->MasterIrp = MasterIrp; 3230 3231 // 3232 // We set the count in the master Irp to 1 since typically we 3233 // will clean up the associated irps ourselves. Setting this to one 3234 // means completing the last associated Irp with SUCCESS (in the async 3235 // case) will complete the master irp. 3236 // 3237 3238 MasterIrp->AssociatedIrp.IrpCount = 1; 3239 3240 // 3241 // Now that all the dangerous work is done, issue the Io requests 3242 // 3243 3244 for (UnwindRunCount = 0; 3245 UnwindRunCount < RunCount; 3246 UnwindRunCount++) { 3247 3248 Irp = IoRuns[UnwindRunCount].SavedIrp; 3249 IoRuns[UnwindRunCount].SavedIrp = NULL; 3250 3251 // 3252 // 3253 // If IoCallDriver returns an error, it has completed the Irp 3254 // and the error will be caught by our completion routines 3255 // and dealt with as a normal IO error. 3256 // 3257 3258 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp ); 3259 } 3260 3261 return; 3262 } 3263 3264 3265 // 3266 // Local support routine 3267 // 3268 3269 _Requires_lock_held_(_Global_critical_region_) 3270 VOID 3271 CdSingleAsync ( 3272 _In_ PIRP_CONTEXT IrpContext, 3273 _In_ PIO_RUN Run, 3274 _In_ PFCB Fcb 3275 ) 3276 3277 /*++ 3278 3279 Routine Description: 3280 3281 This routine reads one or more contiguous sectors from a device 3282 asynchronously, and is used if there is only one read necessary to 3283 complete the IRP. It implements the read by simply filling 3284 in the next stack frame in the Irp, and passing it on. The transfer 3285 occurs to the single buffer originally specified in the user request. 3286 3287 Arguments: 3288 3289 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from 3290 3291 ByteCount - Supplies the number of bytes to read from the device 3292 3293 Return Value: 3294 3295 None. 3296 3297 --*/ 3298 3299 { 3300 PIO_STACK_LOCATION IrpSp; 3301 PIO_COMPLETION_ROUTINE CompletionRoutine; 3302 3303 PAGED_CODE(); 3304 3305 // 3306 // For directories, look in the sector cache, 3307 // 3308 3309 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) && 3310 (NULL != Fcb->Vcb->SectorCacheBuffer) && 3311 (VcbMounted == IrpContext->Vcb->VcbCondition)) { 3312 3313 if (CdReadDirDataThroughCache( IrpContext, Run )) { 3314 3315 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { 3316 3317 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS; 3318 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE ); 3319 } 3320 3321 return; 3322 } 3323 } 3324 3325 // 3326 // Set up things according to whether this is truely async. 3327 // 3328 3329 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 3330 3331 CompletionRoutine = CdSingleSyncCompletionRoutine; 3332 3333 } else { 3334 3335 CompletionRoutine = CdSingleAsyncCompletionRoutine; 3336 3337 // 3338 // If we (FS) acquired locks, transition the lock owners to an object, since 3339 // when we return this thread could go away before request completion, and 3340 // the resource package may otherwise try to boost priority, etc. 3341 // 3342 3343 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) { 3344 3345 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() ); 3346 3347 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3; 3348 3349 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource, 3350 (PVOID)IrpContext->IoContext->ResourceThreadId ); 3351 } 3352 } 3353 3354 // 3355 // Set up the completion routine address in our stack frame. 3356 // 3357 3358 IoSetCompletionRoutine( IrpContext->Irp, 3359 CompletionRoutine, 3360 IrpContext->IoContext, 3361 TRUE, 3362 TRUE, 3363 TRUE ); 3364 3365 // 3366 // Setup the next IRP stack location in the associated Irp for the disk 3367 // driver beneath us. 3368 // 3369 3370 IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp ); 3371 3372 // 3373 // Setup the Stack location to do a read from the disk driver. 3374 // 3375 3376 IrpSp->MajorFunction = IrpContext->MajorFunction; 3377 IrpSp->Parameters.Read.Length = Run->DiskByteCount; 3378 IrpSp->Parameters.Read.ByteOffset.QuadPart = Run->DiskOffset; 3379 3380 // 3381 // Issue the Io request 3382 // 3383 3384 // 3385 // If IoCallDriver returns an error, it has completed the Irp 3386 // and the error will be caught by our completion routines 3387 // and dealt with as a normal IO error. 3388 // 3389 3390 (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp ); 3391 } 3392 3393 3394 // 3395 // Local support routine 3396 // 3397 3398 VOID 3399 CdWaitSync ( 3400 _In_ PIRP_CONTEXT IrpContext 3401 ) 3402 3403 /*++ 3404 3405 Routine Description: 3406 3407 This routine waits for one or more previously started I/O requests 3408 from the above routines, by simply waiting on the event. 3409 3410 Arguments: 3411 3412 Return Value: 3413 3414 None 3415 3416 --*/ 3417 3418 { 3419 PAGED_CODE(); 3420 3421 3422 (VOID)KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent, 3423 Executive, 3424 KernelMode, 3425 FALSE, 3426 NULL ); 3427 3428 KeClearEvent( &IrpContext->IoContext->SyncEvent ); 3429 } 3430 3431 3432 // 3433 // Local support routine 3434 // 3435 3436 NTSTATUS 3437 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3438 CdMultiSyncCompletionRoutine ( 3439 PDEVICE_OBJECT DeviceObject, 3440 PIRP Irp, 3441 PVOID Context 3442 ) 3443 3444 /*++ 3445 3446 Routine Description: 3447 3448 This is the completion routine for all synchronous reads 3449 started via CdMultipleAsynch. 3450 3451 The completion routine has has the following responsibilities: 3452 3453 If the individual request was completed with an error, then 3454 this completion routine must see if this is the first error 3455 and remember the error status in the Context. 3456 3457 If the IrpCount goes to 1, then it sets the event in the Context 3458 parameter to signal the caller that all of the asynch requests 3459 are done. 3460 3461 Arguments: 3462 3463 DeviceObject - Pointer to the file system device object. 3464 3465 Irp - Pointer to the associated Irp which is being completed. (This 3466 Irp will no longer be accessible after this routine returns.) 3467 3468 Context - The context parameter which was specified for all of 3469 the multiple asynch I/O requests for this MasterIrp. 3470 3471 Return Value: 3472 3473 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can 3474 immediately complete the Master Irp without being in a race condition 3475 with the IoCompleteRequest thread trying to decrement the IrpCount in 3476 the Master Irp. 3477 3478 --*/ 3479 3480 { 3481 PCD_IO_CONTEXT IoContext = Context; 3482 _Analysis_assume_(Context != NULL); 3483 3484 AssertVerifyDeviceIrp( Irp ); 3485 3486 // 3487 // If we got an error (or verify required), remember it in the Irp 3488 // 3489 3490 if (!NT_SUCCESS( Irp->IoStatus.Status )) { 3491 3492 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status ); 3493 IoContext->MasterIrp->IoStatus.Information = 0; 3494 } 3495 3496 // 3497 // We must do this here since IoCompleteRequest won't get a chance 3498 // on this associated Irp. 3499 // 3500 3501 IoFreeMdl( Irp->MdlAddress ); 3502 IoFreeIrp( Irp ); 3503 3504 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) { 3505 3506 // 3507 // Update the Master Irp with any error status from the associated Irps. 3508 // 3509 3510 IoContext->MasterIrp->IoStatus.Status = IoContext->Status; 3511 KeSetEvent( &IoContext->SyncEvent, 0, FALSE ); 3512 } 3513 3514 UNREFERENCED_PARAMETER( DeviceObject ); 3515 3516 return STATUS_MORE_PROCESSING_REQUIRED; 3517 } 3518 3519 3520 // 3521 // Local support routine 3522 // 3523 3524 NTSTATUS 3525 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3526 CdMultiAsyncCompletionRoutine ( 3527 PDEVICE_OBJECT DeviceObject, 3528 PIRP Irp, 3529 PVOID Context 3530 ) 3531 3532 /*++ 3533 3534 Routine Description: 3535 3536 This is the completion routine for all asynchronous reads 3537 started via CdMultipleAsynch. 3538 3539 The completion routine has has the following responsibilities: 3540 3541 If the individual request was completed with an error, then 3542 this completion routine must see if this is the first error 3543 and remember the error status in the Context. 3544 3545 Arguments: 3546 3547 DeviceObject - Pointer to the file system device object. 3548 3549 Irp - Pointer to the associated Irp which is being completed. (This 3550 Irp will no longer be accessible after this routine returns.) 3551 3552 Context - The context parameter which was specified for all of 3553 the multiple asynch I/O requests for this MasterIrp. 3554 3555 Return Value: 3556 3557 Currently always returns STATUS_SUCCESS. 3558 3559 --*/ 3560 3561 { 3562 PCD_IO_CONTEXT IoContext = Context; 3563 _Analysis_assume_(Context != NULL); 3564 AssertVerifyDeviceIrp( Irp ); 3565 3566 UNREFERENCED_PARAMETER( DeviceObject ); 3567 3568 // 3569 // If we got an error (or verify required), remember it in the Irp 3570 // 3571 3572 if (!NT_SUCCESS( Irp->IoStatus.Status )) { 3573 3574 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status ); 3575 } 3576 3577 // 3578 // Decrement IrpCount and see if it goes to zero. 3579 // 3580 3581 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) { 3582 3583 // 3584 // Mark the master Irp pending 3585 // 3586 3587 IoMarkIrpPending( IoContext->MasterIrp ); 3588 3589 // 3590 // Update the Master Irp with any error status from the associated Irps. 3591 // 3592 3593 IoContext->MasterIrp->IoStatus.Status = IoContext->Status; 3594 3595 // 3596 // Update the information field with the correct value. 3597 // 3598 3599 IoContext->MasterIrp->IoStatus.Information = 0; 3600 3601 if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) { 3602 3603 IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount; 3604 } 3605 3606 // 3607 // Now release the resource 3608 // 3609 3610 _Analysis_assume_lock_held_(*IoContext->Resource); 3611 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId ); 3612 3613 // 3614 // and finally, free the context record. 3615 // 3616 3617 CdFreeIoContext( IoContext ); 3618 3619 // 3620 // Return success in this case. 3621 // 3622 3623 return STATUS_SUCCESS; 3624 3625 } else { 3626 3627 // 3628 // We need to cleanup the associated Irp and its Mdl. 3629 // 3630 3631 IoFreeMdl( Irp->MdlAddress ); 3632 IoFreeIrp( Irp ); 3633 3634 return STATUS_MORE_PROCESSING_REQUIRED; 3635 } 3636 3637 } 3638 3639 3640 // 3641 // Local support routine 3642 // 3643 3644 NTSTATUS 3645 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3646 CdSingleSyncCompletionRoutine ( 3647 PDEVICE_OBJECT DeviceObject, 3648 PIRP Irp, 3649 PVOID Context 3650 ) 3651 3652 /*++ 3653 3654 Routine Description: 3655 3656 This is the completion routine for all reads started via CdSingleAsynch. 3657 3658 The completion routine has has the following responsibilities: 3659 3660 It sets the event in the Context parameter to signal the caller 3661 that all of the asynch requests are done. 3662 3663 Arguments: 3664 3665 DeviceObject - Pointer to the file system device object. 3666 3667 Irp - Pointer to the Irp for this request. (This Irp will no longer 3668 be accessible after this routine returns.) 3669 3670 Context - The context parameter which was specified in the call to 3671 CdSingleAsynch. 3672 3673 Return Value: 3674 3675 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can 3676 immediately complete the Master Irp without being in a race condition 3677 with the IoCompleteRequest thread trying to decrement the IrpCount in 3678 the Master Irp. 3679 3680 --*/ 3681 3682 { 3683 _Analysis_assume_(Context != NULL); 3684 3685 UNREFERENCED_PARAMETER( DeviceObject ); 3686 3687 AssertVerifyDeviceIrp( Irp ); 3688 3689 // 3690 // Store the correct information field into the Irp. 3691 // 3692 3693 if (!NT_SUCCESS( Irp->IoStatus.Status )) { 3694 3695 Irp->IoStatus.Information = 0; 3696 } 3697 3698 KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE ); 3699 3700 return STATUS_MORE_PROCESSING_REQUIRED; 3701 } 3702 3703 3704 // 3705 // Local support routine 3706 // 3707 3708 NTSTATUS 3709 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3710 CdSingleAsyncCompletionRoutine ( 3711 PDEVICE_OBJECT DeviceObject, 3712 PIRP Irp, 3713 PVOID Context 3714 ) 3715 3716 /*++ 3717 3718 Routine Description: 3719 3720 This is the completion routine for all asynchronous reads 3721 started via CdSingleAsynch. 3722 3723 Arguments: 3724 3725 DeviceObject - Pointer to the file system device object. 3726 3727 Irp - Pointer to the Irp for this request. (This Irp will no longer 3728 be accessible after this routine returns.) 3729 3730 Context - The context parameter which was specified in the call to 3731 CdSingleAsynch. 3732 3733 Return Value: 3734 3735 Currently always returns STATUS_SUCCESS. 3736 3737 --*/ 3738 3739 { 3740 PCD_IO_CONTEXT IoContext = Context; 3741 3742 UNREFERENCED_PARAMETER( DeviceObject ); 3743 3744 _Analysis_assume_(IoContext != NULL); 3745 AssertVerifyDeviceIrp( Irp ); 3746 3747 // 3748 // Update the information field with the correct value for bytes read. 3749 // 3750 3751 Irp->IoStatus.Information = 0; 3752 3753 if (NT_SUCCESS( Irp->IoStatus.Status )) { 3754 3755 Irp->IoStatus.Information = IoContext->RequestedByteCount; 3756 } 3757 3758 // 3759 // Mark the Irp pending 3760 // 3761 3762 IoMarkIrpPending( Irp ); 3763 3764 // 3765 // Now release the resource 3766 // 3767 3768 _Analysis_assume_lock_held_(*IoContext->Resource); 3769 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId ); 3770 3771 // 3772 // and finally, free the context record. 3773 // 3774 3775 CdFreeIoContext( IoContext ); 3776 return STATUS_SUCCESS; 3777 3778 } 3779 3780 3781 // 3782 // Local support routine 3783 // 3784 3785 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT)))) 3786 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE))) 3787 VOID 3788 CdReadAudioSystemFile ( 3789 _In_ PIRP_CONTEXT IrpContext, 3790 _In_ PFCB Fcb, 3791 _In_ LONGLONG StartingOffset, 3792 _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount, 3793 _Out_writes_bytes_(ByteCount) PVOID SystemBuffer 3794 ) 3795 3796 /*++ 3797 3798 Routine Description: 3799 3800 This routine is called to read the pseudo root directory and path 3801 table for a music disk. We build the individual elements on the 3802 stack and copy into the cache buffer. 3803 3804 Arguments: 3805 3806 Fcb - Fcb representing the file to read. 3807 3808 StartingOffset - Logical offset in the file to read from. 3809 3810 ByteCount - Number of bytes to read. 3811 3812 SystemBuffer - Pointer to buffer to fill in. This will always be page 3813 aligned. 3814 3815 Return Value: 3816 3817 None. 3818 3819 --*/ 3820 3821 { 3822 PRAW_PATH_ISO RawPath; 3823 PRAW_DIRENT RawDirent; 3824 3825 ULONG CurrentTrack; 3826 ULONG SectorOffset; 3827 ULONG EntryCount; 3828 UCHAR TrackOnes; 3829 UCHAR TrackTens; 3830 PTRACK_DATA ThisTrack; 3831 3832 LONGLONG CurrentOffset; 3833 3834 PVOID CurrentSector; 3835 3836 PSYSTEM_USE_XA SystemUse; 3837 3838 ULONG BytesToCopy; 3839 3840 UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12]; 3841 3842 PAGED_CODE(); 3843 3844 // 3845 // If this is the path table then we just need a single entry. 3846 // 3847 3848 if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) { 3849 3850 // 3851 // Sanity check that the offset is zero. 3852 // 3853 3854 NT_ASSERT( StartingOffset == 0 ); 3855 3856 // 3857 // Store a pseudo path entry in our local buffer. 3858 // 3859 3860 RawPath = (PRAW_PATH_ISO) LocalBuffer; 3861 3862 RtlZeroMemory( RawPath, sizeof( LocalBuffer )); 3863 3864 RawPath->DirIdLen = 1; 3865 RawPath->ParentNum = 1; 3866 RawPath->DirId[0] = '\0'; 3867 3868 // 3869 // Now copy to the user's buffer. 3870 // 3871 3872 BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2; 3873 3874 if (BytesToCopy > ByteCount) { 3875 3876 BytesToCopy = ByteCount; 3877 } 3878 3879 RtlCopyMemory( SystemBuffer, 3880 RawPath, 3881 BytesToCopy ); 3882 3883 // 3884 // We need to deal with the multiple sector case for the root directory. 3885 // 3886 3887 } else { 3888 3889 // 3890 // Initialize the first track to return to our caller. 3891 // 3892 3893 CurrentTrack = 0; 3894 3895 // 3896 // If the offset is zero then store the entries for the self and parent 3897 // entries. 3898 // 3899 3900 if (StartingOffset == 0) { 3901 3902 RawDirent = SystemBuffer; 3903 3904 // 3905 // Clear all of the fields initially. 3906 // 3907 3908 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId )); 3909 3910 // 3911 // Now fill in the interesting fields. 3912 // 3913 3914 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1; 3915 RawDirent->FileIdLen = 1; 3916 RawDirent->FileId[0] = '\0'; 3917 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY ); 3918 3919 // 3920 // Set the time stamp to be Jan 1, 1995 3921 // 3922 3923 RawDirent->RecordTime[0] = 95; 3924 RawDirent->RecordTime[1] = 1; 3925 RawDirent->RecordTime[2] = 1; 3926 3927 SectorOffset = RawDirent->DirLen; 3928 3929 RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT ); 3930 3931 // 3932 // Clear all of the fields initially. 3933 // 3934 3935 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId )); 3936 3937 // 3938 // Now fill in the interesting fields. 3939 // 3940 3941 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1; 3942 RawDirent->FileIdLen = 1; 3943 RawDirent->FileId[0] = '\1'; 3944 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY ); 3945 3946 // 3947 // Set the time stamp to be Jan 1, 1995 3948 // 3949 3950 RawDirent->RecordTime[0] = 95; 3951 RawDirent->RecordTime[1] = 1; 3952 RawDirent->RecordTime[2] = 1; 3953 3954 SectorOffset += RawDirent->DirLen; 3955 EntryCount = 2; 3956 3957 // 3958 // Otherwise compute the starting track to write to the buffer. 3959 // 3960 3961 } else { 3962 3963 // 3964 // Count the tracks in each preceding sector. 3965 // 3966 3967 CurrentOffset = 0; 3968 3969 do { 3970 3971 CurrentTrack += CdAudioDirentsPerSector; 3972 CurrentOffset += SECTOR_SIZE; 3973 3974 } while (CurrentOffset < StartingOffset); 3975 3976 // 3977 // Bias the track count to reflect the two default entries. 3978 // 3979 3980 CurrentTrack -= 2; 3981 3982 SectorOffset = 0; 3983 EntryCount = 0; 3984 } 3985 3986 // 3987 // We now know the first track to return as well as where we are in 3988 // the current sector. We will walk through sector by sector adding 3989 // the entries for the separate tracks in the TOC. We will zero 3990 // any sectors or partial sectors without data. 3991 // 3992 3993 CurrentSector = SystemBuffer; 3994 BytesToCopy = SECTOR_SIZE; 3995 3996 // 3997 // Loop for each sector. 3998 // 3999 4000 do { 4001 4002 // 4003 // Add entries until we reach our threshold for each sector. 4004 // 4005 4006 do { 4007 4008 // 4009 // If we are beyond the entries in the TOC then exit. 4010 // 4011 4012 if (CurrentTrack >= IrpContext->Vcb->TrackCount) { 4013 4014 break; 4015 } 4016 4017 ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack]; 4018 4019 // 4020 // Point to the current position in the buffer. 4021 // 4022 4023 RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT ); 4024 4025 // 4026 // Clear all of the fields initially. 4027 // 4028 4029 RtlZeroMemory( RawDirent, CdAudioDirentSize ); 4030 4031 // 4032 // Now fill in the interesting fields. 4033 // 4034 4035 RawDirent->DirLen = (UCHAR) CdAudioDirentSize; 4036 RawDirent->FileIdLen = CdAudioFileNameLength; 4037 4038 RtlCopyMemory( RawDirent->FileId, 4039 CdAudioFileName, 4040 CdAudioFileNameLength ); 4041 4042 // 4043 // Set the time stamp to be Jan 1, 1995 00:00 4044 // 4045 4046 RawDirent->RecordTime[0] = 95; 4047 RawDirent->RecordTime[1] = 1; 4048 RawDirent->RecordTime[2] = 1; 4049 4050 // 4051 // Put the track number into the file name. 4052 // 4053 4054 TrackTens = TrackOnes = ThisTrack->TrackNumber; 4055 4056 TrackOnes = (TrackOnes % 10) + '0'; 4057 4058 TrackTens /= 10; 4059 TrackTens = (TrackTens % 10) + '0'; 4060 4061 RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens; 4062 RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes; 4063 4064 SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA ); 4065 4066 SystemUse->Attributes = SYSTEM_USE_XA_DA; 4067 SystemUse->Signature = SYSTEM_XA_SIGNATURE; 4068 4069 // 4070 // Store the track number as the file number. 4071 // 4072 4073 SystemUse->FileNumber = (UCHAR) CurrentTrack; 4074 4075 EntryCount += 1; 4076 SectorOffset += CdAudioDirentSize; 4077 CurrentTrack += 1; 4078 4079 } while (EntryCount < CdAudioDirentsPerSector); 4080 4081 // 4082 // Zero the remaining portion of this buffer. 4083 // 4084 4085 RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ), 4086 SECTOR_SIZE - SectorOffset ); 4087 4088 // 4089 // Prepare for the next sector. 4090 // 4091 4092 EntryCount = 0; 4093 BytesToCopy += SECTOR_SIZE; 4094 SectorOffset = 0; 4095 CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID ); 4096 4097 } while (BytesToCopy <= ByteCount); 4098 } 4099 4100 return; 4101 } 4102 4103 4104 NTSTATUS 4105 CdHijackIrpAndFlushDevice ( 4106 _In_ PIRP_CONTEXT IrpContext, 4107 _Inout_ PIRP Irp, 4108 _In_ PDEVICE_OBJECT TargetDeviceObject 4109 ) 4110 4111 /*++ 4112 4113 Routine Description: 4114 4115 This routine is called when we need to send a flush to a device but 4116 we don't have a flush Irp. What this routine does is make a copy 4117 of its current Irp stack location, but changes the Irp Major code 4118 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at 4119 the knees in the completion routine, fix it up and return to the 4120 user as if nothing had happened. 4121 4122 Arguments: 4123 4124 Irp - The Irp to hijack 4125 4126 TargetDeviceObject - The device to send the request to. 4127 4128 Return Value: 4129 4130 NTSTATUS - The Status from the flush in case anybody cares. 4131 4132 --*/ 4133 4134 { 4135 KEVENT Event; 4136 NTSTATUS Status; 4137 PIO_STACK_LOCATION NextIrpSp; 4138 4139 PAGED_CODE(); 4140 4141 UNREFERENCED_PARAMETER( IrpContext ); 4142 4143 // 4144 // Get the next stack location, and copy over the stack location 4145 // 4146 4147 NextIrpSp = IoGetNextIrpStackLocation( Irp ); 4148 4149 *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp ); 4150 4151 NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS; 4152 NextIrpSp->MinorFunction = 0; 4153 4154 // 4155 // Set up the completion routine 4156 // 4157 4158 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 4159 4160 IoSetCompletionRoutine( Irp, 4161 CdSyncCompletionRoutine, 4162 &Event, 4163 TRUE, 4164 TRUE, 4165 TRUE ); 4166 4167 // 4168 // Send the request. 4169 // 4170 4171 Status = IoCallDriver( TargetDeviceObject, Irp ); 4172 4173 if (Status == STATUS_PENDING) { 4174 4175 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); 4176 4177 Status = Irp->IoStatus.Status; 4178 } 4179 4180 // 4181 // If the driver doesn't support flushes, return SUCCESS. 4182 // 4183 4184 if (Status == STATUS_INVALID_DEVICE_REQUEST) { 4185 4186 Status = STATUS_SUCCESS; 4187 } 4188 4189 Irp->IoStatus.Status = 0; 4190 Irp->IoStatus.Information = 0; 4191 4192 return Status; 4193 } 4194 4195 4196