1 2 /*++ 3 4 Copyright (c) 1989-2000 Microsoft Corporation 5 6 Module Name: 7 8 CdData.c 9 10 Abstract: 11 12 This module declares the global data used by the Cdfs file system. 13 14 This module also handles the dispath routines in the Fsd threads as well as 15 handling the IrpContext and Irp through the exception path. 16 17 18 --*/ 19 20 #include "cdprocs.h" 21 22 #ifdef CD_SANITY 23 BOOLEAN CdTestTopLevel = TRUE; 24 BOOLEAN CdTestRaisedStatus = TRUE; 25 BOOLEAN CdBreakOnAnyRaise = FALSE; 26 BOOLEAN CdTraceRaises = FALSE; 27 NTSTATUS CdInterestingExceptionCodes[] = { STATUS_DISK_CORRUPT_ERROR, 28 STATUS_FILE_CORRUPT_ERROR, 29 0, 0, 0, 0, 0, 0, 0, 0 }; 30 #endif 31 32 // 33 // The Bug check file id for this module 34 // 35 36 #define BugCheckFileId (CDFS_BUG_CHECK_CDDATA) 37 38 // 39 // Global data structures 40 // 41 42 CD_DATA CdData; 43 FAST_IO_DISPATCH CdFastIoDispatch; 44 45 // 46 // Reserved directory strings. 47 // 48 49 WCHAR CdUnicodeSelfArray[] = { L'.' }; 50 WCHAR CdUnicodeParentArray[] = { L'.', L'.' }; 51 52 UNICODE_STRING CdUnicodeDirectoryNames[] = { 53 { 2, 2, CdUnicodeSelfArray}, 54 { 4, 4, CdUnicodeParentArray} 55 }; 56 57 // 58 // Volume descriptor identifier strings. 59 // 60 61 CHAR CdHsgId[] = { 'C', 'D', 'R', 'O', 'M' }; 62 CHAR CdIsoId[] = { 'C', 'D', '0', '0', '1' }; 63 CHAR CdXaId[] = { 'C', 'D', '-', 'X', 'A', '0', '0', '1' }; 64 65 // 66 // Volume label for audio disks. 67 // 68 69 WCHAR CdAudioLabel[] = { L'A', L'u', L'd', L'i', L'o', L' ', L'C', L'D' }; 70 USHORT CdAudioLabelLength = sizeof( CdAudioLabel ); 71 72 // 73 // Pseudo file names for audio disks. 74 // 75 76 CHAR CdAudioFileName[] = { 'T', 'r', 'a', 'c', 'k', '0', '0', '.', 'c', 'd', 'a' }; 77 UCHAR CdAudioFileNameLength = sizeof( CdAudioFileName ); 78 ULONG CdAudioDirentSize = FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName ) + sizeof( SYSTEM_USE_XA ); 79 ULONG CdAudioDirentsPerSector = SECTOR_SIZE / (FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName ) + sizeof( SYSTEM_USE_XA )); 80 ULONG CdAudioSystemUseOffset = FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName ); 81 82 // 83 // Escape sequences for mounting Unicode volumes. 84 // 85 86 PCHAR CdJolietEscape[] = { "%/@", "%/C", "%/E" }; 87 88 // 89 // Audio Play Files consist completely of this header block. These 90 // files are readable in the root of any audio disc regardless of 91 // the capabilities of the drive. 92 // 93 // The "Unique Disk ID Number" is a calculated value consisting of 94 // a combination of parameters, including the number of tracks and 95 // the starting locations of those tracks. 96 // 97 // Applications interpreting CDDA RIFF files should be advised that 98 // additional RIFF file chunks may be added to this header in the 99 // future in order to add information, such as the disk and song title. 100 // 101 102 LONG CdAudioPlayHeader[] = { 103 0x46464952, // Chunk ID = 'RIFF' 104 4 * 11 - 8, // Chunk Size = (file size - 8) 105 0x41444443, // 'CDDA' 106 0x20746d66, // 'fmt ' 107 24, // Chunk Size (of 'fmt ' subchunk) = 24 108 0x00000001, // WORD Format Tag, WORD Track Number 109 0x00000000, // DWORD Unique Disk ID Number 110 0x00000000, // DWORD Track Starting Sector (LBN) 111 0x00000000, // DWORD Track Length (LBN count) 112 0x00000000, // DWORD Track Starting Sector (MSF) 113 0x00000000 // DWORD Track Length (MSF) 114 }; 115 116 // Audio Philes begin with this header block to identify the data as a 117 // PCM waveform. AudioPhileHeader is coded as if it has no data included 118 // in the waveform. Data must be added in 2352-byte multiples. 119 // 120 // Fields marked 'ADJUST' need to be adjusted based on the size of the 121 // data: Add (nSectors*2352) to the DWORDs at offsets 1*4 and 10*4. 122 // 123 // File Size of TRACK??.WAV = nSectors*2352 + sizeof(AudioPhileHeader) 124 // RIFF('WAVE' fmt(1, 2, 44100, 176400, 16, 4) data( <CD Audio Raw Data> ) 125 // 126 // The number of sectors in a CD-XA CD-DA file is (DataLen/2048). 127 // CDFS will expose these files to applications as if they were just 128 // 'WAVE' files, adjusting the file size so that the RIFF file is valid. 129 // 130 // NT NOTE: We do not do any fidelity adjustment. These are presented as raw 131 // 2352 byte sectors - 95 has the glimmer of an idea to allow CDFS to expose 132 // the CDXA CDDA data at different sampling rates in a virtual directory 133 // structure, but we will never do that. 134 // 135 136 LONG CdXAAudioPhileHeader[] = { 137 0x46464952, // Chunk ID = 'RIFF' 138 -8, // Chunk Size = (file size - 8) ADJUST1 139 0x45564157, // 'WAVE' 140 0x20746d66, // 'fmt ' 141 16, // Chunk Size (of 'fmt ' subchunk) = 16 142 0x00020001, // WORD Format Tag WORD nChannels 143 44100, // DWORD nSamplesPerSecond 144 2352 * 75, // DWORD nAvgBytesPerSec 145 0x00100004, // WORD nBlockAlign WORD nBitsPerSample 146 0x61746164, // 'data' 147 -44 // <CD Audio Raw Data> ADJUST2 148 }; 149 150 // 151 // XA Files begin with this RIFF header block to identify the data as 152 // raw CD-XA sectors. Data must be added in 2352-byte multiples. 153 // 154 // This header is added to all CD-XA files which are marked as having 155 // mode2form2 sectors. 156 // 157 // Fields marked 'ADJUST' need to be adjusted based on the size of the 158 // data: Add file size to the marked DWORDS. 159 // 160 // File Size of TRACK??.WAV = nSectors*2352 + sizeof(XAFileHeader) 161 // 162 // RIFF('CDXA' FMT(Owner, Attr, 'X', 'A', FileNum, 0) data ( <CDXA Raw Data> ) 163 // 164 165 LONG CdXAFileHeader[] = { 166 0x46464952, // Chunk ID = 'RIFF' 167 -8, // Chunk Size = (file size - 8) ADJUST 168 0x41584443, // 'CDXA' 169 0x20746d66, // 'fmt ' 170 16, // Chunk Size (of CDXA chunk) = 16 171 0, // DWORD Owner ID 172 0x41580000, // WORD Attributes 173 // BYTE Signature byte 1 'X' 174 // BYTE Signature byte 2 'A' 175 0, // BYTE File Number 176 0, // BYTE Reserved[7] 177 0x61746164, // 'data' 178 -44 // <CD-XA Raw Sectors> ADJUST 179 }; 180 181 #ifdef CDFS_TELEMETRY_DATA 182 183 // 184 // Telemetry Data for reporting 185 // 186 187 CDFS_TELEMETRY_DATA_CONTEXT CdTelemetryData; 188 189 #endif // CDFS_TELEMETRY_DATA 190 191 #ifdef ALLOC_PRAGMA 192 #pragma alloc_text(PAGE, CdFastIoCheckIfPossible) 193 #pragma alloc_text(PAGE, CdSerial32) 194 #pragma alloc_text(PAGE, CdSetThreadContext) 195 #endif 196 197 _IRQL_requires_max_(APC_LEVEL) 198 __drv_dispatchType(DRIVER_DISPATCH) 199 __drv_dispatchType(IRP_MJ_CREATE) 200 __drv_dispatchType(IRP_MJ_CLOSE) 201 __drv_dispatchType(IRP_MJ_READ) 202 __drv_dispatchType(IRP_MJ_WRITE) 203 __drv_dispatchType(IRP_MJ_QUERY_INFORMATION) 204 __drv_dispatchType(IRP_MJ_SET_INFORMATION) 205 __drv_dispatchType(IRP_MJ_QUERY_VOLUME_INFORMATION) 206 __drv_dispatchType(IRP_MJ_DIRECTORY_CONTROL) 207 __drv_dispatchType(IRP_MJ_FILE_SYSTEM_CONTROL) 208 __drv_dispatchType(IRP_MJ_DEVICE_CONTROL) 209 __drv_dispatchType(IRP_MJ_LOCK_CONTROL) 210 __drv_dispatchType(IRP_MJ_CLEANUP) 211 __drv_dispatchType(IRP_MJ_PNP) 212 __drv_dispatchType(IRP_MJ_SHUTDOWN) 213 NTSTATUS 214 NTAPI 215 CdFsdDispatch ( 216 _In_ PDEVICE_OBJECT DeviceObject, 217 _Inout_ PIRP Irp 218 ) 219 220 /*++ 221 222 Routine Description: 223 224 This is the driver entry to all of the Fsd dispatch points. 225 226 Conceptually the Io routine will call this routine on all requests 227 to the file system. We case on the type of request and invoke the 228 correct handler for this type of request. There is an exception filter 229 to catch any exceptions in the CDFS code as well as the CDFS process 230 exception routine. 231 232 This routine allocates and initializes the IrpContext for this request as 233 well as updating the top-level thread context as necessary. We may loop 234 in this routine if we need to retry the request for any reason. The 235 status code STATUS_CANT_WAIT is used to indicate this. Suppose the disk 236 in the drive has changed. An Fsd request will proceed normally until it 237 recognizes this condition. STATUS_VERIFY_REQUIRED is raised at that point 238 and the exception code will handle the verify and either return 239 STATUS_CANT_WAIT or STATUS_PENDING depending on whether the request was 240 posted. 241 242 Arguments: 243 244 DeviceObject - Supplies the volume device object for this request 245 246 Irp - Supplies the Irp being processed 247 248 Return Value: 249 250 NTSTATUS - The FSD status for the IRP 251 252 --*/ 253 254 { 255 THREAD_CONTEXT ThreadContext = {0}; 256 PIRP_CONTEXT IrpContext = NULL; 257 BOOLEAN Wait; 258 259 #ifdef CD_SANITY 260 PVOID PreviousTopLevel; 261 #endif 262 263 NTSTATUS Status; 264 265 #if DBG 266 267 KIRQL SaveIrql = KeGetCurrentIrql(); 268 269 #endif 270 271 ASSERT_OPTIONAL_IRP( Irp ); 272 273 UNREFERENCED_PARAMETER( DeviceObject ); 274 275 FsRtlEnterFileSystem(); 276 277 #ifdef CD_SANITY 278 PreviousTopLevel = IoGetTopLevelIrp(); 279 #endif 280 281 // 282 // Loop until this request has been completed or posted. 283 // 284 285 do { 286 287 // 288 // Use a try-except to handle the exception cases. 289 // 290 291 _SEH2_TRY { 292 293 // 294 // If the IrpContext is NULL then this is the first pass through 295 // this loop. 296 // 297 298 if (IrpContext == NULL) { 299 300 // 301 // Decide if this request is waitable an allocate the IrpContext. 302 // If the file object in the stack location is NULL then this 303 // is a mount which is always waitable. Otherwise we look at 304 // the file object flags. 305 // 306 307 if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) { 308 309 Wait = TRUE; 310 311 } else { 312 313 Wait = CanFsdWait( Irp ); 314 } 315 316 IrpContext = CdCreateIrpContext( Irp, Wait ); 317 318 // 319 // Update the thread context information. 320 // 321 322 CdSetThreadContext( IrpContext, &ThreadContext ); 323 324 #ifdef CD_SANITY 325 NT_ASSERT( !CdTestTopLevel || 326 SafeNodeType( IrpContext->TopLevel ) == CDFS_NTC_IRP_CONTEXT ); 327 #endif 328 329 // 330 // Otherwise cleanup the IrpContext for the retry. 331 // 332 333 } else { 334 335 // 336 // Set the MORE_PROCESSING flag to make sure the IrpContext 337 // isn't inadvertently deleted here. Then cleanup the 338 // IrpContext to perform the retry. 339 // 340 341 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING ); 342 CdCleanupIrpContext( IrpContext, FALSE ); 343 } 344 345 // 346 // Case on the major irp code. 347 // 348 349 switch (IrpContext->MajorFunction) { 350 351 case IRP_MJ_CREATE : 352 353 Status = CdCommonCreate( IrpContext, Irp ); 354 break; 355 356 case IRP_MJ_CLOSE : 357 358 Status = CdCommonClose( IrpContext, Irp ); 359 break; 360 361 case IRP_MJ_READ : 362 363 // 364 // If this is an Mdl complete request, don't go through 365 // common read. 366 // 367 368 if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) { 369 370 Status = CdCompleteMdl( IrpContext, Irp ); 371 372 } else { 373 374 Status = CdCommonRead( IrpContext, Irp ); 375 } 376 377 break; 378 379 case IRP_MJ_WRITE : 380 381 Status = CdCommonWrite( IrpContext, Irp ); 382 break; 383 384 case IRP_MJ_QUERY_INFORMATION : 385 386 Status = CdCommonQueryInfo( IrpContext, Irp ); 387 break; 388 389 case IRP_MJ_SET_INFORMATION : 390 391 Status = CdCommonSetInfo( IrpContext, Irp ); 392 break; 393 394 case IRP_MJ_QUERY_VOLUME_INFORMATION : 395 396 Status = CdCommonQueryVolInfo( IrpContext, Irp ); 397 break; 398 399 case IRP_MJ_DIRECTORY_CONTROL : 400 401 Status = CdCommonDirControl( IrpContext, Irp ); 402 break; 403 404 case IRP_MJ_FILE_SYSTEM_CONTROL : 405 406 Status = CdCommonFsControl( IrpContext, Irp ); 407 break; 408 409 case IRP_MJ_DEVICE_CONTROL : 410 411 Status = CdCommonDevControl( IrpContext, Irp ); 412 break; 413 414 case IRP_MJ_LOCK_CONTROL : 415 416 Status = CdCommonLockControl( IrpContext, Irp ); 417 break; 418 419 case IRP_MJ_CLEANUP : 420 421 Status = CdCommonCleanup( IrpContext, Irp ); 422 break; 423 424 case IRP_MJ_PNP : 425 426 Status = CdCommonPnp( IrpContext, Irp ); 427 break; 428 429 case IRP_MJ_SHUTDOWN : 430 431 Status = CdCommonShutdown( IrpContext, Irp ); 432 break; 433 434 default : 435 436 Status = STATUS_INVALID_DEVICE_REQUEST; 437 CdCompleteRequest( IrpContext, Irp, Status ); 438 } 439 440 } _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 441 442 Status = CdProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 443 } _SEH2_END; 444 445 } while (Status == STATUS_CANT_WAIT); 446 447 #ifdef CD_SANITY 448 NT_ASSERT( !CdTestTopLevel || 449 (PreviousTopLevel == IoGetTopLevelIrp()) ); 450 #endif 451 452 FsRtlExitFileSystem(); 453 454 NT_ASSERT( SaveIrql == KeGetCurrentIrql( )); 455 456 return Status; 457 } 458 459 460 #ifdef CD_SANITY 461 462 VOID 463 CdRaiseStatusEx ( 464 _In_ PIRP_CONTEXT IrpContext, 465 _In_ NTSTATUS Status, 466 _In_ BOOLEAN NormalizeStatus, 467 _In_opt_ ULONG FileId, 468 _In_opt_ ULONG Line 469 ) 470 { 471 BOOLEAN BreakIn = FALSE; 472 473 AssertVerifyDevice( IrpContext, Status); 474 475 if (CdTraceRaises) { 476 477 DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status, FileId, Line); 478 } 479 480 if (CdTestRaisedStatus && !CdBreakOnAnyRaise) { 481 482 ULONG Index; 483 484 for (Index = 0; 485 Index < (sizeof( CdInterestingExceptionCodes) / sizeof( CdInterestingExceptionCodes[0])); 486 Index++) { 487 488 if ((STATUS_SUCCESS != CdInterestingExceptionCodes[Index]) && 489 (CdInterestingExceptionCodes[Index] == Status)) { 490 491 BreakIn = TRUE; 492 break; 493 } 494 } 495 } 496 497 if (BreakIn || CdBreakOnAnyRaise) { 498 499 DbgPrint( "CDFS: Breaking on raised status %08x (BI=%d,BA=%d)\n", Status, BreakIn, CdBreakOnAnyRaise); 500 DbgPrint( "CDFS: (FILEID %d LINE %d)\n", FileId, Line); 501 DbgPrint( "CDFS: Contact CDFS.SYS component owner for triage.\n"); 502 DbgPrint( "CDFS: 'eb %p 0;eb %p 0' to disable this alert.\n", &CdTestRaisedStatus, &CdBreakOnAnyRaise); 503 504 NT_ASSERT(FALSE); 505 } 506 507 if (NormalizeStatus) { 508 509 IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR); 510 } 511 else { 512 513 IrpContext->ExceptionStatus = Status; 514 } 515 516 IrpContext->RaisedAtLineFile = (FileId << 16) | Line; 517 518 ExRaiseStatus( IrpContext->ExceptionStatus); 519 } 520 521 #endif 522 523 524 LONG 525 CdExceptionFilter ( 526 _Inout_ PIRP_CONTEXT IrpContext, 527 _In_ PEXCEPTION_POINTERS ExceptionPointer 528 ) 529 530 /*++ 531 532 Routine Description: 533 534 This routine is used to decide whether we will handle a raised exception 535 status. If CDFS explicitly raised an error then this status is already 536 in the IrpContext. We choose which is the correct status code and 537 either indicate that we will handle the exception or bug-check the system. 538 539 Arguments: 540 541 ExceptionCode - Supplies the exception code to being checked. 542 543 Return Value: 544 545 ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks 546 547 --*/ 548 549 { 550 NTSTATUS ExceptionCode; 551 BOOLEAN TestStatus = TRUE; 552 553 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext ); 554 555 ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode; 556 557 // 558 // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code 559 // from the exception record. 560 // 561 562 if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && 563 (ExceptionPointer->ExceptionRecord->NumberParameters >= 3)) { 564 565 ExceptionCode = 566 (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2]; 567 } 568 569 // 570 // If there is an Irp context then check which status code to use. 571 // 572 573 if (ARGUMENT_PRESENT( IrpContext )) { 574 575 if (IrpContext->ExceptionStatus == STATUS_SUCCESS) { 576 577 // 578 // Store the real status into the IrpContext. 579 // 580 581 IrpContext->ExceptionStatus = ExceptionCode; 582 583 } else { 584 585 // 586 // No need to test the status code if we raised it ourselves. 587 // 588 589 TestStatus = FALSE; 590 } 591 } 592 593 AssertVerifyDevice( IrpContext, IrpContext->ExceptionStatus ); 594 595 // 596 // Bug check if this status is not supported. 597 // 598 599 if (TestStatus && !FsRtlIsNtstatusExpected( ExceptionCode )) { 600 601 #ifdef _MSC_VER 602 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "We're corrupted." ) 603 #endif 604 CdBugCheck( (ULONG_PTR) ExceptionPointer->ExceptionRecord, 605 (ULONG_PTR) ExceptionPointer->ContextRecord, 606 (ULONG_PTR) ExceptionPointer->ExceptionRecord->ExceptionAddress ); 607 608 } 609 610 return EXCEPTION_EXECUTE_HANDLER; 611 } 612 613 614 615 _Requires_lock_held_(_Global_critical_region_) 616 NTSTATUS 617 CdProcessException ( 618 _In_opt_ PIRP_CONTEXT IrpContext, 619 _Inout_ PIRP Irp, 620 _In_ NTSTATUS ExceptionCode 621 ) 622 623 /*++ 624 625 Routine Description: 626 627 This routine processes an exception. It either completes the request 628 with the exception status in the IrpContext, sends this off to the Fsp 629 workque or causes it to be retried in the current thread if a verification 630 is needed. 631 632 If the volume needs to be verified (STATUS_VERIFY_REQUIRED) and we can 633 do the work in the current thread we will translate the status code 634 to STATUS_CANT_WAIT to indicate that we need to retry the request. 635 636 Arguments: 637 638 Irp - Supplies the Irp being processed 639 640 ExceptionCode - Supplies the normalized exception status being handled 641 642 Return Value: 643 644 NTSTATUS - Returns the results of either posting the Irp or the 645 saved completion status. 646 647 --*/ 648 649 { 650 PDEVICE_OBJECT Device = NULL; 651 PVPB Vpb; 652 PETHREAD Thread; 653 654 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext ); 655 ASSERT_IRP( Irp ); 656 657 // 658 // If there is not an irp context, then complete the request with the 659 // current status code. 660 // 661 662 if (!ARGUMENT_PRESENT( IrpContext )) { 663 664 CdCompleteRequest( NULL, Irp, ExceptionCode ); 665 return ExceptionCode; 666 } 667 668 // 669 // Get the real exception status from the IrpContext. 670 // 671 672 ExceptionCode = IrpContext->ExceptionStatus; 673 674 // 675 // Check if we are posting this request. One of the following must be true 676 // if we are to post a request. 677 // 678 // - Status code is STATUS_CANT_WAIT and the request is asynchronous 679 // or we are forcing this to be posted. 680 // 681 // - Status code is STATUS_VERIFY_REQUIRED and we are at APC level 682 // or higher, or within a guarded region. Can't wait for IO in 683 // the verify path in this case. 684 // 685 // Set the MORE_PROCESSING flag in the IrpContext to keep if from being 686 // deleted if this is a retryable condition. 687 // 688 // 689 // Note that (children of) CdFsdPostRequest can raise (Mdl allocation). 690 // 691 692 _SEH2_TRY { 693 694 if (ExceptionCode == STATUS_CANT_WAIT) { 695 696 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST )) { 697 698 ExceptionCode = CdFsdPostRequest( IrpContext, Irp ); 699 } 700 } 701 else if ((ExceptionCode == STATUS_VERIFY_REQUIRED) && 702 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) && 703 KeAreAllApcsDisabled()) { 704 705 ExceptionCode = CdFsdPostRequest( IrpContext, Irp ); 706 } 707 } 708 _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 709 710 ExceptionCode = _SEH2_GetExceptionCode(); 711 } _SEH2_END; 712 // 713 // If we posted the request or our caller will retry then just return here. 714 // 715 716 if ((ExceptionCode == STATUS_PENDING) || 717 (ExceptionCode == STATUS_CANT_WAIT)) { 718 719 return ExceptionCode; 720 } 721 722 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING ); 723 724 // 725 // If we are not a top level request then we just complete the request 726 // with the current status code. 727 // 728 729 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) { 730 731 CdCompleteRequest( IrpContext, Irp, ExceptionCode ); 732 return ExceptionCode; 733 } 734 735 // 736 // Store this error into the Irp for posting back to the Io system. 737 // 738 739 Irp->IoStatus.Status = ExceptionCode; 740 741 if (IoIsErrorUserInduced( ExceptionCode )) { 742 743 // 744 // Check for the various error conditions that can be caused by, 745 // and possibly resolved my the user. 746 // 747 748 if (ExceptionCode == STATUS_VERIFY_REQUIRED) { 749 750 // 751 // Now we are at the top level file system entry point. 752 // 753 // If we have already posted this request then the device to 754 // verify is in the original thread. Find this via the Irp. 755 // 756 757 Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread ); 758 IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL ); 759 760 // 761 // If there is no device in that location then check in the 762 // current thread. 763 // 764 765 if (Device == NULL) { 766 767 Device = IoGetDeviceToVerify( PsGetCurrentThread() ); 768 IoSetDeviceToVerify( PsGetCurrentThread(), NULL ); 769 770 NT_ASSERT( Device != NULL ); 771 772 } 773 774 // 775 // It turns out some storage drivers really do set invalid non-NULL device 776 // objects to verify. 777 // 778 // To work around this, completely ignore the device to verify in the thread, 779 // and just use our real device object instead. 780 // 781 782 if (IrpContext->Vcb) { 783 784 Device = IrpContext->Vcb->Vpb->RealDevice; 785 } 786 787 // 788 // Let's not BugCheck just because the device to verify is somehow still NULL. 789 // 790 791 if (Device == NULL) { 792 793 ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR; 794 795 CdCompleteRequest( IrpContext, Irp, ExceptionCode ); 796 797 return ExceptionCode; 798 } 799 800 // 801 // CdPerformVerify() will do the right thing with the Irp. 802 // If we return STATUS_CANT_WAIT then the current thread 803 // can retry the request. 804 // 805 806 return CdPerformVerify( IrpContext, Irp, Device ); 807 } 808 809 // 810 // The other user induced conditions generate an error unless 811 // they have been disabled for this request. 812 // 813 814 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS )) { 815 816 CdCompleteRequest( IrpContext, Irp, ExceptionCode ); 817 818 return ExceptionCode; 819 820 } 821 // 822 // Generate a pop-up. 823 // 824 else { 825 826 if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) { 827 828 Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb; 829 830 } else { 831 832 Vpb = NULL; 833 } 834 835 836 // 837 // The device to verify is either in my thread local storage 838 // or that of the thread that owns the Irp. 839 // 840 841 Thread = Irp->Tail.Overlay.Thread; 842 Device = IoGetDeviceToVerify( Thread ); 843 844 if (Device == NULL) { 845 846 Thread = PsGetCurrentThread(); 847 Device = IoGetDeviceToVerify( Thread ); 848 849 NT_ASSERT( Device != NULL ); 850 } 851 852 // 853 // It turns out some storage drivers really do set invalid non-NULL device 854 // objects to verify. 855 // 856 // To work around this, completely ignore the device to verify in the thread, 857 // and just use our real device object instead. 858 // 859 860 if (IrpContext->Vcb) { 861 862 Device = IrpContext->Vcb->Vpb->RealDevice; 863 } 864 865 // 866 // Let's not BugCheck just because the device to verify is somehow still NULL. 867 // 868 869 if (Device == NULL) { 870 871 CdCompleteRequest( IrpContext, Irp, ExceptionCode ); 872 873 return ExceptionCode; 874 } 875 876 // 877 // This routine actually causes the pop-up. It usually 878 // does this by queuing an APC to the callers thread, 879 // but in some cases it will complete the request immediately, 880 // so it is very important to IoMarkIrpPending() first. 881 // 882 883 IoMarkIrpPending( Irp ); 884 IoRaiseHardError( Irp, Vpb, Device ); 885 886 // 887 // We will be handing control back to the caller here, so 888 // reset the saved device object. 889 // 890 891 IoSetDeviceToVerify( Thread, NULL ); 892 893 // 894 // The Irp will be completed by Io or resubmitted. In either 895 // case we must clean up the IrpContext here. 896 // 897 898 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); 899 return STATUS_PENDING; 900 } 901 } 902 903 // 904 // This is just a run of the mill error. 905 // 906 907 CdCompleteRequest( IrpContext, Irp, ExceptionCode ); 908 909 return ExceptionCode; 910 } 911 912 913 VOID 914 CdCompleteRequest ( 915 _Inout_opt_ PIRP_CONTEXT IrpContext, 916 _Inout_opt_ PIRP Irp, 917 _In_ NTSTATUS Status 918 ) 919 920 /*++ 921 922 Routine Description: 923 924 This routine completes a Irp and cleans up the IrpContext. Either or 925 both of these may not be specified. 926 927 Arguments: 928 929 Irp - Supplies the Irp being processed. 930 931 Status - Supplies the status to complete the Irp with 932 933 Return Value: 934 935 None. 936 937 --*/ 938 939 { 940 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext ); 941 ASSERT_OPTIONAL_IRP( Irp ); 942 943 // 944 // Cleanup the IrpContext if passed in here. 945 // 946 947 if (ARGUMENT_PRESENT( IrpContext )) { 948 949 CdCleanupIrpContext( IrpContext, FALSE ); 950 } 951 952 // 953 // If we have an Irp then complete the irp. 954 // 955 956 if (ARGUMENT_PRESENT( Irp )) { 957 958 // 959 // Clear the information field in case we have used this Irp 960 // internally. 961 // 962 963 if (NT_ERROR( Status ) && 964 FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) { 965 966 Irp->IoStatus.Information = 0; 967 } 968 969 Irp->IoStatus.Status = Status; 970 971 AssertVerifyDeviceIrp( Irp ); 972 973 IoCompleteRequest( Irp, IO_CD_ROM_INCREMENT ); 974 } 975 976 return; 977 } 978 979 980 VOID 981 CdSetThreadContext ( 982 _Inout_ PIRP_CONTEXT IrpContext, 983 _In_ PTHREAD_CONTEXT ThreadContext 984 ) 985 986 /*++ 987 988 Routine Description: 989 990 This routine is called at each Fsd/Fsp entry point set up the IrpContext 991 and thread local storage to track top level requests. If there is 992 not a Cdfs context in the thread local storage then we use the input one. 993 Otherwise we use the one already there. This routine also updates the 994 IrpContext based on the state of the top-level context. 995 996 If the TOP_LEVEL flag in the IrpContext is already set when we are called 997 then we force this request to appear top level. 998 999 Arguments: 1000 1001 ThreadContext - Address on stack for local storage if not already present. 1002 1003 ForceTopLevel - We force this request to appear top level regardless of 1004 any previous stack value. 1005 1006 Return Value: 1007 1008 None 1009 1010 --*/ 1011 1012 { 1013 PTHREAD_CONTEXT CurrentThreadContext; 1014 #ifdef __REACTOS__ 1015 ULONG_PTR StackTop; 1016 ULONG_PTR StackBottom; 1017 #endif 1018 1019 PAGED_CODE(); 1020 1021 ASSERT_IRP_CONTEXT( IrpContext ); 1022 1023 // 1024 // Get the current top-level irp out of the thread storage. 1025 // If NULL then this is the top-level request. 1026 // 1027 1028 CurrentThreadContext = (PTHREAD_CONTEXT) IoGetTopLevelIrp(); 1029 1030 if (CurrentThreadContext == NULL) { 1031 1032 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ); 1033 } 1034 1035 // 1036 // Initialize the input context unless we are using the current 1037 // thread context block. We use the new block if our caller 1038 // specified this or the existing block is invalid. 1039 // 1040 // The following must be true for the current to be a valid Cdfs context. 1041 // 1042 // Structure must lie within current stack. 1043 // Address must be ULONG aligned. 1044 // Cdfs signature must be present. 1045 // 1046 // If this is not a valid Cdfs context then use the input thread 1047 // context and store it in the top level context. 1048 // 1049 1050 #ifdef __REACTOS__ 1051 IoGetStackLimits( &StackTop, &StackBottom); 1052 #endif 1053 1054 #ifdef _MSC_VER 1055 #pragma warning(suppress: 6011) // Bug in PREFast around bitflag operations 1056 #endif 1057 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) || 1058 #ifndef __REACTOS__ 1059 (!IoWithinStackLimits( (ULONG_PTR)CurrentThreadContext, sizeof( THREAD_CONTEXT ) ) || 1060 #else 1061 (((ULONG_PTR) CurrentThreadContext > StackBottom - sizeof( THREAD_CONTEXT )) || 1062 ((ULONG_PTR) CurrentThreadContext <= StackTop) || 1063 #endif 1064 FlagOn( (ULONG_PTR) CurrentThreadContext, 0x3 ) || 1065 (CurrentThreadContext->Cdfs != 0x53464443))) { 1066 1067 ThreadContext->Cdfs = 0x53464443; 1068 ThreadContext->SavedTopLevelIrp = (PIRP) CurrentThreadContext; 1069 ThreadContext->TopLevelIrpContext = IrpContext; 1070 IoSetTopLevelIrp( (PIRP) ThreadContext ); 1071 1072 IrpContext->TopLevel = IrpContext; 1073 IrpContext->ThreadContext = ThreadContext; 1074 1075 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS ); 1076 1077 // 1078 // Otherwise use the IrpContext in the thread context. 1079 // 1080 1081 } else { 1082 1083 IrpContext->TopLevel = CurrentThreadContext->TopLevelIrpContext; 1084 } 1085 1086 return; 1087 } 1088 1089 1090 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE) 1091 _IRQL_requires_same_ 1092 _Success_(return != FALSE) 1093 BOOLEAN 1094 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1095 CdFastIoCheckIfPossible ( 1096 _In_ PFILE_OBJECT FileObject, 1097 _In_ PLARGE_INTEGER FileOffset, 1098 _In_ ULONG Length, 1099 _In_ BOOLEAN Wait, 1100 _In_ ULONG LockKey, 1101 _In_ BOOLEAN CheckForReadOperation, 1102 _Pre_notnull_ 1103 _When_(return != FALSE, _Post_equal_to_(_Old_(IoStatus))) 1104 _When_(return == FALSE, _Post_valid_) 1105 PIO_STATUS_BLOCK IoStatus, 1106 _In_ PDEVICE_OBJECT DeviceObject 1107 ) 1108 1109 /*++ 1110 1111 Routine Description: 1112 1113 This routine checks if fast i/o is possible for a read/write operation 1114 1115 Arguments: 1116 1117 FileObject - Supplies the file object used in the query 1118 1119 FileOffset - Supplies the starting byte offset for the read/write operation 1120 1121 Length - Supplies the length, in bytes, of the read/write operation 1122 1123 Wait - Indicates if we can wait 1124 1125 LockKey - Supplies the lock key 1126 1127 CheckForReadOperation - Indicates if this is a check for a read or write 1128 operation 1129 1130 IoStatus - Receives the status of the operation if our return value is 1131 FastIoReturnError 1132 1133 Return Value: 1134 1135 BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs 1136 to take the long route. 1137 1138 --*/ 1139 1140 { 1141 PFCB Fcb; 1142 TYPE_OF_OPEN TypeOfOpen; 1143 LARGE_INTEGER LargeLength; 1144 1145 PAGED_CODE(); 1146 1147 UNREFERENCED_PARAMETER( Wait ); 1148 UNREFERENCED_PARAMETER( DeviceObject ); 1149 1150 // 1151 // Decode the type of file object we're being asked to process and 1152 // make sure that is is only a user file open. 1153 // 1154 1155 TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb ); 1156 1157 if ((TypeOfOpen != UserFileOpen) || !CheckForReadOperation) { 1158 1159 IoStatus->Status = STATUS_INVALID_PARAMETER; 1160 return TRUE; 1161 } 1162 1163 LargeLength.QuadPart = Length; 1164 1165 // 1166 // Check whether the file locks will allow for fast io. 1167 // 1168 1169 if ((Fcb->FileLock == NULL) || 1170 FsRtlFastCheckLockForRead( Fcb->FileLock, 1171 FileOffset, 1172 &LargeLength, 1173 LockKey, 1174 FileObject, 1175 PsGetCurrentProcess() )) { 1176 1177 return TRUE; 1178 } 1179 1180 return FALSE; 1181 } 1182 1183 1184 ULONG 1185 CdSerial32 ( 1186 _In_reads_bytes_(ByteCount) PCHAR Buffer, 1187 _In_ ULONG ByteCount 1188 ) 1189 /*++ 1190 1191 Routine Description: 1192 1193 This routine is called to generate a 32 bit serial number. This is 1194 done by doing four separate checksums into an array of bytes and 1195 then treating the bytes as a ULONG. 1196 1197 Arguments: 1198 1199 Buffer - Pointer to the buffer to generate the ID for. 1200 1201 ByteCount - Number of bytes in the buffer. 1202 1203 Return Value: 1204 1205 ULONG - The 32 bit serial number. 1206 1207 --*/ 1208 1209 { 1210 union { 1211 UCHAR Bytes[4]; 1212 ULONG SerialId; 1213 } Checksum; 1214 1215 PAGED_CODE(); 1216 1217 // 1218 // Initialize the serial number. 1219 // 1220 1221 Checksum.SerialId = 0; 1222 1223 // 1224 // Continue while there are more bytes to use. 1225 // 1226 1227 while (ByteCount--) { 1228 1229 // 1230 // Increment this sub-checksum. 1231 // 1232 1233 Checksum.Bytes[ByteCount & 0x3] += *(Buffer++); 1234 } 1235 1236 // 1237 // Return the checksums as a ULONG. 1238 // 1239 1240 return Checksum.SerialId; 1241 } 1242 1243 1244