1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 StrucSup.c 8 9 Abstract: 10 11 This module implements the Cdfs in-memory data structure manipulation 12 routines 13 14 15 --*/ 16 17 #include "cdprocs.h" 18 19 // 20 // The Bug check file id for this module 21 // 22 23 #define BugCheckFileId (CDFS_BUG_CHECK_STRUCSUP) 24 25 // 26 // Local macros 27 // 28 29 // 30 // PFCB 31 // CdAllocateFcbData ( 32 // _In_ PIRP_CONTEXT IrpContext 33 // ); 34 // 35 // VOID 36 // CdDeallocateFcbData ( 37 // _In_ PIRP_CONTEXT IrpContext, 38 // _Inout_ PFCB Fcb 39 // ); 40 // 41 // PFCB 42 // CdAllocateFcbIndex ( 43 // _In_ PIRP_CONTEXT IrpContext 44 // ); 45 // 46 // VOID 47 // CdDeallocateFcbIndex ( 48 // _In_ PIRP_CONTEXT IrpContext, 49 // _Inout_ PFCB Fcb 50 // ); 51 // 52 // PFCB_NONPAGED 53 // CdAllocateFcbNonpaged ( 54 // _In_ PIRP_CONTEXT IrpContext 55 // ); 56 // 57 // VOID 58 // CdDeallocateFcbNonpaged ( 59 // _In_ PIRP_CONTEXT IrpContext, 60 // _Inout_ PFCB_NONPAGED FcbNonpaged 61 // ); 62 // 63 // PCCB 64 // CdAllocateCcb ( 65 // _In_ PIRP_CONTEXT IrpContext 66 // ); 67 // 68 // VOID 69 // CdDeallocateCcb ( 70 // _In_ PIRP_CONTEXT IrpContext, 71 // _Inout_ PCCB Ccb 72 // ); 73 // 74 75 #define CdAllocateFcbData(IC) \ 76 FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_DATA, TAG_FCB_DATA ) 77 78 #define CdDeallocateFcbData(IC,F) \ 79 CdFreePool( &(F) ) 80 81 #define CdAllocateFcbIndex(IC) \ 82 FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_INDEX, TAG_FCB_INDEX ) 83 84 #define CdDeallocateFcbIndex(IC,F) \ 85 CdFreePool( &(F) ) 86 87 #define CdAllocateFcbNonpaged(IC) \ 88 ExAllocatePoolWithTag( CdNonPagedPool, sizeof( FCB_NONPAGED ), TAG_FCB_NONPAGED ) 89 90 #define CdDeallocateFcbNonpaged(IC,FNP) \ 91 CdFreePool( &(FNP) ) 92 93 #define CdAllocateCcb(IC) \ 94 FsRtlAllocatePoolWithTag( CdPagedPool, sizeof( CCB ), TAG_CCB ) 95 96 #define CdDeallocateCcb(IC,C) \ 97 CdFreePool( &(C) ) 98 99 // 100 // Local structures 101 // 102 103 typedef struct _FCB_TABLE_ELEMENT { 104 105 FILE_ID FileId; 106 PFCB Fcb; 107 108 } FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT; 109 110 // 111 // Local macros 112 // 113 114 // 115 // VOID 116 // CdInsertFcbTable ( 117 // _In_ PIRP_CONTEXT IrpContext, 118 // _In_ PFCB Fcb 119 // ); 120 // 121 // VOID 122 // CdDeleteFcbTable ( 123 // _In_ PIRP_CONTEXT IrpContext, 124 // _In_ PFCB Fcb 125 // ); 126 // 127 128 129 #define CdInsertFcbTable(IC,F) { \ 130 FCB_TABLE_ELEMENT _Key; \ 131 _Key.Fcb = (F); \ 132 _Key.FileId = (F)->FileId; \ 133 RtlInsertElementGenericTable( &(F)->Vcb->FcbTable, \ 134 &_Key, \ 135 sizeof( FCB_TABLE_ELEMENT ), \ 136 NULL ); \ 137 } 138 139 #define CdDeleteFcbTable(IC,F) { \ 140 FCB_TABLE_ELEMENT _Key; \ 141 _Key.FileId = (F)->FileId; \ 142 RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \ 143 } 144 145 // 146 // Local support routines 147 // 148 149 VOID 150 CdDeleteFcb ( 151 _In_ PIRP_CONTEXT IrpContext, 152 _In_ PFCB Fcb 153 ); 154 155 PFCB_NONPAGED 156 CdCreateFcbNonpaged ( 157 _In_ PIRP_CONTEXT IrpContext 158 ); 159 160 VOID 161 CdDeleteFcbNonpaged ( 162 _In_ PIRP_CONTEXT IrpContext, 163 _In_ PFCB_NONPAGED FcbNonpaged 164 ); 165 166 // Inform prefast that this is a compare routine. 167 RTL_GENERIC_COMPARE_ROUTINE CdFcbTableCompare; 168 169 RTL_GENERIC_COMPARE_RESULTS 170 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 171 CdFcbTableCompare ( 172 _In_ PRTL_GENERIC_TABLE FcbTable, 173 _In_ PVOID Fid1, 174 _In_ PVOID Fid2 175 ); 176 177 // Inform prefast that this is an alloc reoutine. 178 RTL_GENERIC_ALLOCATE_ROUTINE CdAllocateFcbTable; 179 180 PVOID 181 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 182 CdAllocateFcbTable ( 183 _In_ PRTL_GENERIC_TABLE FcbTable, 184 _In_ CLONG ByteSize 185 ); 186 187 // Inform prefast that this is a free reoutine. 188 RTL_GENERIC_FREE_ROUTINE CdDeallocateFcbTable; 189 190 VOID 191 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 192 CdDeallocateFcbTable ( 193 _In_ PRTL_GENERIC_TABLE FcbTable, 194 _In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer 195 ); 196 197 ULONG 198 CdTocSerial ( 199 _In_ PIRP_CONTEXT IrpContext, 200 _In_ PCDROM_TOC_LARGE CdromToc 201 ); 202 203 #ifdef ALLOC_PRAGMA 204 #pragma alloc_text(PAGE, CdAllocateFcbTable) 205 #pragma alloc_text(PAGE, CdCleanupIrpContext) 206 #pragma alloc_text(PAGE, CdCreateCcb) 207 #pragma alloc_text(PAGE, CdCreateFcb) 208 #pragma alloc_text(PAGE, CdCreateFcbNonpaged) 209 #pragma alloc_text(PAGE, CdCreateFileLock) 210 #pragma alloc_text(PAGE, CdCreateIrpContext) 211 #pragma alloc_text(PAGE, CdDeallocateFcbTable) 212 #pragma alloc_text(PAGE, CdDeleteCcb) 213 #pragma alloc_text(PAGE, CdDeleteFcb) 214 #pragma alloc_text(PAGE, CdDeleteFcbNonpaged) 215 #pragma alloc_text(PAGE, CdDeleteFileLock) 216 #pragma alloc_text(PAGE, CdDeleteVcb) 217 #pragma alloc_text(PAGE, CdFcbTableCompare) 218 #pragma alloc_text(PAGE, CdGetNextFcb) 219 #pragma alloc_text(PAGE, CdInitializeFcbFromFileContext) 220 #pragma alloc_text(PAGE, CdInitializeFcbFromPathEntry) 221 #pragma alloc_text(PAGE, CdInitializeStackIrpContext) 222 #pragma alloc_text(PAGE, CdInitializeVcb) 223 #pragma alloc_text(PAGE, CdLookupFcbTable) 224 #pragma alloc_text(PAGE, CdProcessToc) 225 #pragma alloc_text(PAGE, CdTeardownStructures) 226 #pragma alloc_text(PAGE, CdTocSerial) 227 #pragma alloc_text(PAGE, CdUpdateVcbFromVolDescriptor) 228 #endif 229 230 // 231 // Some static names for volume streams 232 // 233 234 UNICODE_STRING CdInternalStreamNames[] = { 235 { 24, 24, L"$PATH_TABLE$"}, 236 { 2, 2, L"\\"} 237 }; 238 239 240 VOID 241 CdInitializeVcb ( 242 _In_ PIRP_CONTEXT IrpContext, 243 _Inout_ PVCB Vcb, 244 _In_ __drv_aliasesMem PDEVICE_OBJECT TargetDeviceObject, 245 _In_ __drv_aliasesMem PVPB Vpb, 246 _In_ __drv_aliasesMem PCDROM_TOC_LARGE CdromToc, 247 _In_ ULONG TocLength, 248 _In_ ULONG TocTrackCount, 249 _In_ ULONG TocDiskFlags, 250 _In_ ULONG BlockFactor, 251 _In_ ULONG MediaChangeCount 252 ) 253 254 /*++ 255 256 Routine Description: 257 258 This routine initializes and inserts a new Vcb record into the in-memory 259 data structure. The Vcb record "hangs" off the end of the Volume device 260 object and must be allocated by our caller. 261 262 Arguments: 263 264 Vcb - Supplies the address of the Vcb record being initialized. 265 266 TargetDeviceObject - Supplies the address of the target device object to 267 associate with the Vcb record. 268 269 Vpb - Supplies the address of the Vpb to associate with the Vcb record. 270 271 CdromToc - Buffer to hold table of contents. NULL if TOC command not 272 supported. 273 274 TocLength - Byte count length of TOC. We use this as the TOC length to 275 return on a user query. 276 277 TocTrackCount - Count of tracks in TOC. Used to create pseudo files for 278 audio disks. 279 280 TocDiskFlags - Flag field to indicate the type of tracks on the disk. 281 282 BlockFactor - Used to decode any multi-session information. 283 284 MediaChangeCount - Initial media change count of the target device 285 286 Return Value: 287 288 None. 289 290 --*/ 291 292 { 293 PAGED_CODE(); 294 295 UNREFERENCED_PARAMETER( IrpContext ); 296 297 // 298 // We start by first zeroing out all of the VCB, this will guarantee 299 // that any stale data is wiped clean. 300 // 301 302 RtlZeroMemory( Vcb, sizeof( VCB )); 303 304 // 305 // Set the proper node type code and node byte size. 306 // 307 308 Vcb->NodeTypeCode = CDFS_NTC_VCB; 309 Vcb->NodeByteSize = sizeof( VCB ); 310 311 // 312 // Initialize the DirNotify structs. FsRtlNotifyInitializeSync can raise. 313 // 314 315 InitializeListHead( &Vcb->DirNotifyList ); 316 FsRtlNotifyInitializeSync( &Vcb->NotifySync ); 317 318 // 319 // Pick up a VPB right now so we know we can pull this filesystem stack 320 // off of the storage stack on demand. This can raise - if it does, 321 // uninitialize the notify structures before returning. 322 // 323 324 _SEH2_TRY { 325 326 Vcb->SwapVpb = FsRtlAllocatePoolWithTag( CdNonPagedPool, 327 sizeof( VPB ), 328 TAG_VPB ); 329 } 330 _SEH2_FINALLY { 331 332 if (_SEH2_AbnormalTermination()) { 333 334 FsRtlNotifyUninitializeSync( &Vcb->NotifySync ); 335 } 336 } _SEH2_END; 337 338 // 339 // Nothing beyond this point should raise. 340 // 341 342 RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) ); 343 344 // 345 // Initialize the resource variable for the Vcb and files. 346 // 347 348 ExInitializeResourceLite( &Vcb->VcbResource ); 349 ExInitializeResourceLite( &Vcb->FileResource ); 350 ExInitializeFastMutex( &Vcb->VcbMutex ); 351 352 // 353 // Insert this Vcb record on the CdData.VcbQueue. 354 // 355 356 InsertHeadList( &CdData.VcbQueue, &Vcb->VcbLinks ); 357 358 // 359 // Set the Target Device Object and Vpb fields, referencing the 360 // Target device for the mount. 361 // 362 363 ObReferenceObject( TargetDeviceObject ); 364 Vcb->TargetDeviceObject = TargetDeviceObject; 365 Vcb->Vpb = Vpb; 366 367 // 368 // Set the removable media flag based on the real device's 369 // characteristics 370 // 371 372 if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) { 373 374 SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA ); 375 } 376 377 // 378 // Initialize the generic Fcb Table. 379 // 380 381 RtlInitializeGenericTable( &Vcb->FcbTable, 382 (PRTL_GENERIC_COMPARE_ROUTINE) CdFcbTableCompare, 383 (PRTL_GENERIC_ALLOCATE_ROUTINE) CdAllocateFcbTable, 384 (PRTL_GENERIC_FREE_ROUTINE) CdDeallocateFcbTable, 385 NULL ); 386 387 // 388 // Show that we have a mount in progress. 389 // 390 391 CdUpdateVcbCondition( Vcb, VcbMountInProgress); 392 393 // 394 // Refererence the Vcb for two reasons. The first is a reference 395 // that prevents the Vcb from going away on the last close unless 396 // dismount has already occurred. The second is to make sure 397 // we don't go into the dismount path on any error during mount 398 // until we get to the Mount cleanup. 399 // 400 401 Vcb->VcbReference = 1 + CDFS_RESIDUAL_REFERENCE; 402 403 // 404 // Update the TOC information in the Vcb. 405 // 406 407 Vcb->CdromToc = CdromToc; 408 Vcb->TocLength = TocLength; 409 Vcb->TrackCount = TocTrackCount; 410 Vcb->DiskFlags = TocDiskFlags; 411 412 // 413 // If this disk contains audio tracks only then set the audio flag. 414 // 415 416 if (TocDiskFlags == CDROM_DISK_AUDIO_TRACK) { 417 418 SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA ); 419 } 420 421 // 422 // Set the block factor. 423 // 424 425 Vcb->BlockFactor = BlockFactor; 426 427 // 428 // Set the media change count on the device 429 // 430 431 CdUpdateMediaChangeCount( Vcb, MediaChangeCount); 432 } 433 434 435 VOID 436 CdUpdateVcbFromVolDescriptor ( 437 _In_ PIRP_CONTEXT IrpContext, 438 _Inout_ PVCB Vcb, 439 _In_reads_bytes_opt_(SECTOR_SIZE) PCHAR RawIsoVd 440 ) 441 442 /*++ 443 444 Routine Description: 445 446 This routine is called to perform the final initialization of a Vcb from the 447 volume descriptor on the disk. 448 449 Arguments: 450 451 Vcb - Vcb for the volume being mounted. We have already set the flags for the 452 type of descriptor. 453 454 RawIsoVd - If specified this is the volume descriptor to use to mount the 455 volume. Not specified for a raw disk. 456 457 Return Value: 458 459 None 460 461 --*/ 462 463 { 464 ULONG StartingBlock; 465 ULONG ByteCount; 466 467 LONGLONG FileId = 0; 468 469 PRAW_DIRENT RawDirent; 470 PATH_ENTRY PathEntry; 471 PCD_MCB_ENTRY McbEntry; 472 473 BOOLEAN UnlockVcb = FALSE; 474 475 PAGED_CODE(); 476 477 // 478 // Use a try-finally to facilitate cleanup. 479 // 480 481 _SEH2_TRY { 482 483 // 484 // Copy the block size and compute the various block masks. 485 // Block size must not be larger than the sector size. We will 486 // use a default of the CD physical sector size if we are not 487 // on a data-full disc. 488 // 489 // This must always be set. 490 // 491 492 Vcb->BlockSize = ( ARGUMENT_PRESENT( RawIsoVd ) ? 493 CdRvdBlkSz( RawIsoVd, Vcb->VcbState ) : 494 SECTOR_SIZE ); 495 496 // 497 // We no longer accept media where blocksize != sector size. 498 // 499 500 if (Vcb->BlockSize != SECTOR_SIZE) { 501 502 CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR ); 503 } 504 505 Vcb->BlocksPerSector = SECTOR_SIZE / Vcb->BlockSize; 506 Vcb->BlockMask = Vcb->BlockSize - 1; 507 Vcb->BlockInverseMask = ~Vcb->BlockMask; 508 509 Vcb->BlockToSectorShift = 0; 510 Vcb->BlockToByteShift = SECTOR_SHIFT; 511 512 // 513 // If there is a volume descriptor then do the internal Fcb's and 514 // other Vcb fields. 515 // 516 517 if (ARGUMENT_PRESENT( RawIsoVd )) { 518 519 // 520 // Create the path table Fcb and refererence it and the Vcb. 521 // 522 523 CdLockVcb( IrpContext, Vcb ); 524 UnlockVcb = TRUE; 525 526 Vcb->PathTableFcb = CdCreateFcb( IrpContext, 527 *((PFILE_ID) &FileId), 528 CDFS_NTC_FCB_PATH_TABLE, 529 NULL ); 530 531 CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 ); 532 CdUnlockVcb( IrpContext, Vcb ); 533 UnlockVcb = FALSE; 534 535 // 536 // Compute the stream offset and size of this path table. 537 // 538 539 StartingBlock = CdRvdPtLoc( RawIsoVd, Vcb->VcbState ); 540 541 ByteCount = CdRvdPtSz( RawIsoVd, Vcb->VcbState ); 542 543 Vcb->PathTableFcb->StreamOffset = BytesFromBlocks( Vcb, 544 SectorBlockOffset( Vcb, StartingBlock )); 545 546 Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (Vcb->PathTableFcb->StreamOffset + 547 ByteCount); 548 549 Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart; 550 551 Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart ); 552 553 // 554 // Now add the mapping information. 555 // 556 557 CdLockFcb( IrpContext, Vcb->PathTableFcb ); 558 559 CdAddInitialAllocation( IrpContext, 560 Vcb->PathTableFcb, 561 StartingBlock, 562 Vcb->PathTableFcb->AllocationSize.QuadPart ); 563 564 CdUnlockFcb( IrpContext, Vcb->PathTableFcb ); 565 566 // 567 // Point to the file resource. 568 // 569 570 Vcb->PathTableFcb->Resource = &Vcb->FileResource; 571 572 // 573 // Mark the Fcb as initialized and create the stream file for this. 574 // 575 576 SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED ); 577 578 CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb, &CdInternalStreamNames[0]); 579 580 // 581 // Create the root index and reference it in the Vcb. 582 // 583 584 CdLockVcb( IrpContext, Vcb ); 585 UnlockVcb = TRUE; 586 Vcb->RootIndexFcb = CdCreateFcb( IrpContext, 587 *((PFILE_ID) &FileId), 588 CDFS_NTC_FCB_INDEX, 589 NULL ); 590 591 CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 ); 592 CdUnlockVcb( IrpContext, Vcb ); 593 UnlockVcb = FALSE; 594 595 // 596 // Create the File id by hand for this Fcb. 597 // 598 599 CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset ); 600 CdFidSetDirectory( Vcb->RootIndexFcb->FileId ); 601 602 // 603 // Create a pseudo path table entry so we can call the initialization 604 // routine for the directory. 605 // 606 607 RawDirent = (PRAW_DIRENT) CdRvdDirent( RawIsoVd, Vcb->VcbState ); 608 609 CopyUchar4( &PathEntry.DiskOffset, RawDirent->FileLoc ); 610 611 PathEntry.DiskOffset += RawDirent->XarLen; 612 PathEntry.Ordinal = 1; 613 PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset; 614 615 CdInitializeFcbFromPathEntry( IrpContext, 616 Vcb->RootIndexFcb, 617 NULL, 618 &PathEntry ); 619 620 // 621 // Create the stream file for the root directory. 622 // 623 624 CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb, &CdInternalStreamNames[1] ); 625 626 // 627 // Now do the volume dasd Fcb. Create this and reference it in the 628 // Vcb. 629 // 630 631 CdLockVcb( IrpContext, Vcb ); 632 UnlockVcb = TRUE; 633 634 Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext, 635 *((PFILE_ID) &FileId), 636 CDFS_NTC_FCB_DATA, 637 NULL ); 638 639 CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 ); 640 CdUnlockVcb( IrpContext, Vcb ); 641 UnlockVcb = FALSE; 642 643 // 644 // The file size is the full disk. 645 // 646 647 StartingBlock = CdRvdVolSz( RawIsoVd, Vcb->VcbState ); 648 649 Vcb->VolumeDasdFcb->FileSize.QuadPart = LlBytesFromBlocks( Vcb, StartingBlock ); 650 651 Vcb->VolumeDasdFcb->AllocationSize.QuadPart = 652 Vcb->VolumeDasdFcb->ValidDataLength.QuadPart = Vcb->VolumeDasdFcb->FileSize.QuadPart; 653 654 // 655 // Now add the extent representing the volume 'by hand'. 656 // 657 658 CdLockFcb( IrpContext, Vcb->VolumeDasdFcb ); 659 660 McbEntry = Vcb->VolumeDasdFcb->Mcb.McbArray; 661 662 McbEntry->FileOffset = 663 McbEntry->DiskOffset = 0; 664 665 McbEntry->ByteCount = Vcb->VolumeDasdFcb->AllocationSize.QuadPart; 666 667 McbEntry->DataBlockByteCount = 668 McbEntry->TotalBlockByteCount = McbEntry->ByteCount; 669 670 Vcb->VolumeDasdFcb->Mcb.CurrentEntryCount = 1; 671 672 CdUnlockFcb( IrpContext, Vcb->VolumeDasdFcb ); 673 674 // 675 // Point to the file resource. 676 // 677 678 Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource; 679 680 Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY; 681 682 // 683 // Mark the Fcb as initialized. 684 // 685 686 SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED ); 687 688 // 689 // Check and see if this is an XA disk. 690 // 691 692 if (FlagOn( Vcb->VcbState, VCB_STATE_ISO | VCB_STATE_JOLIET) 693 && RtlEqualMemory( CdXaId, 694 Add2Ptr( RawIsoVd, 0x400, PCHAR ), 695 8 )) { 696 697 SetFlag( Vcb->VcbState, VCB_STATE_CDXA ); 698 } 699 700 // 701 // If this is a music disk then we want to mock this disk to make it 702 // look like ISO disk. We will create a pseudo root directory in 703 // that case. 704 // 705 706 } else if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) { 707 708 ULONG RootDirectorySize; 709 710 // 711 // Create the path table Fcb and refererence it and the Vcb. 712 // 713 714 CdLockVcb( IrpContext, Vcb ); 715 UnlockVcb = TRUE; 716 717 Vcb->PathTableFcb = CdCreateFcb( IrpContext, 718 *((PFILE_ID) &FileId), 719 CDFS_NTC_FCB_PATH_TABLE, 720 NULL ); 721 722 CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 ); 723 CdUnlockVcb( IrpContext, Vcb ); 724 UnlockVcb = FALSE; 725 726 // 727 // We only create a pseudo entry for the root. 728 // 729 730 Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2); 731 732 Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart; 733 734 Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart ); 735 736 // 737 // Point to the file resource. 738 // 739 740 Vcb->PathTableFcb->Resource = &Vcb->FileResource; 741 742 // 743 // Mark the Fcb as initialized and create the stream file for this. 744 // 745 746 SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED ); 747 748 CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb, &CdInternalStreamNames[0]); 749 750 // 751 // Create the root index and reference it in the Vcb. 752 // 753 754 CdLockVcb( IrpContext, Vcb ); 755 UnlockVcb = TRUE; 756 Vcb->RootIndexFcb = CdCreateFcb( IrpContext, 757 *((PFILE_ID) &FileId), 758 CDFS_NTC_FCB_INDEX, 759 NULL ); 760 761 CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 ); 762 CdUnlockVcb( IrpContext, Vcb ); 763 UnlockVcb = FALSE; 764 765 // 766 // Create the File id by hand for this Fcb. 767 // 768 769 CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset ); 770 CdFidSetDirectory( Vcb->RootIndexFcb->FileId ); 771 772 // 773 // Create a pseudo path table entry so we can call the initialization 774 // routine for the directory. 775 // 776 777 RtlZeroMemory( &PathEntry, sizeof( PATH_ENTRY )); 778 779 780 PathEntry.Ordinal = 1; 781 PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset; 782 783 CdInitializeFcbFromPathEntry( IrpContext, 784 Vcb->RootIndexFcb, 785 NULL, 786 &PathEntry ); 787 788 // 789 // Set the sizes by hand for this Fcb. It should have an entry for each track plus an 790 // entry for the root and parent. 791 // 792 793 RootDirectorySize = (Vcb->TrackCount + 2) * CdAudioDirentSize; 794 RootDirectorySize = SectorAlign( RootDirectorySize ); 795 796 Vcb->RootIndexFcb->AllocationSize.QuadPart = 797 Vcb->RootIndexFcb->ValidDataLength.QuadPart = 798 Vcb->RootIndexFcb->FileSize.QuadPart = RootDirectorySize; 799 800 SetFlag( Vcb->RootIndexFcb->FcbState, FCB_STATE_INITIALIZED ); 801 802 // 803 // Create the stream file for the root directory. 804 // 805 806 CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb, &CdInternalStreamNames[1] ); 807 808 // 809 // Now do the volume dasd Fcb. Create this and reference it in the 810 // Vcb. 811 // 812 813 CdLockVcb( IrpContext, Vcb ); 814 UnlockVcb = TRUE; 815 816 Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext, 817 *((PFILE_ID) &FileId), 818 CDFS_NTC_FCB_DATA, 819 NULL ); 820 821 CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 ); 822 CdUnlockVcb( IrpContext, Vcb ); 823 UnlockVcb = FALSE; 824 825 // 826 // We won't allow raw reads on this Fcb so leave the size at 827 // zero. 828 // 829 830 // 831 // Point to the file resource. 832 // 833 834 Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource; 835 836 Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY; 837 838 // 839 // Mark the Fcb as initialized. 840 // 841 842 SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED ); 843 844 // 845 // We will store a hard-coded name in the Vpb and use the toc as 846 // the serial number. 847 // 848 849 Vcb->Vpb->VolumeLabelLength = CdAudioLabelLength; 850 851 RtlCopyMemory( Vcb->Vpb->VolumeLabel, 852 CdAudioLabel, 853 CdAudioLabelLength ); 854 855 // 856 // Find the serial number for the audio disk. 857 // 858 859 Vcb->Vpb->SerialNumber = CdTocSerial( IrpContext, Vcb->CdromToc ); 860 861 // 862 // Set the ISO bit so we know how to treat the names. 863 // 864 865 SetFlag( Vcb->VcbState, VCB_STATE_ISO ); 866 } 867 868 } _SEH2_FINALLY { 869 870 if (UnlockVcb) { CdUnlockVcb( IrpContext, Vcb ); } 871 } _SEH2_END; 872 } 873 874 875 VOID 876 CdDeleteVcb ( 877 _In_ PIRP_CONTEXT IrpContext, 878 _Inout_ PVCB Vcb 879 ) 880 881 /*++ 882 883 Routine Description: 884 885 This routine is called to delete a Vcb which failed mount or has been 886 dismounted. The dismount code should have already removed all of the 887 open Fcb's. We do nothing here but clean up other auxilary structures. 888 889 Arguments: 890 891 Vcb - Vcb to delete. 892 893 Return Value: 894 895 None 896 897 --*/ 898 899 { 900 PAGED_CODE(); 901 902 ASSERT_EXCLUSIVE_CDDATA; 903 ASSERT_EXCLUSIVE_VCB( Vcb ); 904 905 UNREFERENCED_PARAMETER( IrpContext ); 906 907 // 908 // Chuck the backpocket Vpb we kept just in case. 909 // 910 911 CdFreePool( &Vcb->SwapVpb ); 912 913 // 914 // If there is a Vpb then we must delete it ourselves. 915 // 916 917 CdFreePool( &Vcb->Vpb ); 918 919 // 920 // Dereference our target if we haven't already done so. 921 // 922 923 if (Vcb->TargetDeviceObject != NULL) { 924 925 ObDereferenceObject( Vcb->TargetDeviceObject ); 926 } 927 928 // 929 // Delete the XA Sector and sector cache buffer if allocated. 930 // 931 932 CdFreePool( &Vcb->XASector ); 933 CdFreePool( &Vcb->SectorCacheBuffer); 934 935 if (Vcb->SectorCacheIrp != NULL) { 936 937 IoFreeIrp( Vcb->SectorCacheIrp); 938 Vcb->SectorCacheIrp = NULL; 939 940 ExDeleteResourceLite( &Vcb->SectorCacheResource); 941 } 942 943 // 944 // Remove this entry from the global queue. 945 // 946 947 RemoveEntryList( &Vcb->VcbLinks ); 948 949 // 950 // Delete the Vcb and File resources. 951 // 952 953 ExDeleteResourceLite( &Vcb->VcbResource ); 954 ExDeleteResourceLite( &Vcb->FileResource ); 955 956 // 957 // Delete the TOC if present. 958 // 959 960 CdFreePool( &Vcb->CdromToc ); 961 962 // 963 // Uninitialize the notify structures. 964 // 965 966 if (Vcb->NotifySync != NULL) { 967 968 FsRtlNotifyUninitializeSync( &Vcb->NotifySync ); 969 } 970 971 // 972 // Now delete the volume device object. 973 // 974 #ifdef _MSC_VER 975 #pragma prefast( suppress: __WARNING_BUFFER_UNDERFLOW, "This is ok, the Vcb is embedded in our volume device object, and that is what we are really deleting." ) 976 #endif 977 IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, 978 VOLUME_DEVICE_OBJECT, 979 Vcb )); 980 981 return; 982 } 983 984 985 PFCB 986 CdCreateFcb ( 987 _In_ PIRP_CONTEXT IrpContext, 988 _In_ FILE_ID FileId, 989 _In_ NODE_TYPE_CODE NodeTypeCode, 990 _Out_opt_ PBOOLEAN FcbExisted 991 ) 992 993 /*++ 994 995 Routine Description: 996 997 This routine is called to find the Fcb for the given FileId. We will 998 look this up first in the Fcb table and if not found we will create 999 an Fcb. We don't initialize it or insert it into the FcbTable in this 1000 routine. 1001 1002 This routine is called while the Vcb is locked. 1003 1004 Arguments: 1005 1006 FileId - This is the Id for the target Fcb. 1007 1008 NodeTypeCode - Node type for this Fcb if we need to create. 1009 1010 FcbExisted - If specified, we store whether the Fcb existed. 1011 1012 Return Value: 1013 1014 PFCB - The Fcb found in the table or created if needed. 1015 1016 --*/ 1017 1018 { 1019 PFCB NewFcb; 1020 BOOLEAN LocalFcbExisted; 1021 1022 PAGED_CODE(); 1023 1024 // 1025 // Use the local boolean if one was not passed in. 1026 // 1027 1028 if (!ARGUMENT_PRESENT( FcbExisted )) { 1029 1030 FcbExisted = &LocalFcbExisted; 1031 } 1032 1033 // 1034 // Maybe this is already in the table. 1035 // 1036 1037 NewFcb = CdLookupFcbTable( IrpContext, IrpContext->Vcb, FileId ); 1038 1039 // 1040 // If not then create the Fcb is requested by our caller. 1041 // 1042 1043 if (NewFcb == NULL) { 1044 1045 // 1046 // Allocate and initialize the structure depending on the 1047 // type code. 1048 // 1049 1050 switch (NodeTypeCode) { 1051 1052 case CDFS_NTC_FCB_PATH_TABLE: 1053 case CDFS_NTC_FCB_INDEX: 1054 1055 NewFcb = CdAllocateFcbIndex( IrpContext ); 1056 1057 RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX ); 1058 1059 NewFcb->NodeByteSize = SIZEOF_FCB_INDEX; 1060 1061 InitializeListHead( &NewFcb->FcbQueue ); 1062 1063 break; 1064 1065 case CDFS_NTC_FCB_DATA : 1066 1067 NewFcb = CdAllocateFcbData( IrpContext ); 1068 1069 RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA ); 1070 1071 NewFcb->NodeByteSize = SIZEOF_FCB_DATA; 1072 1073 break; 1074 1075 default: 1076 1077 #ifdef _MSC_VER 1078 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "This is a bug." ) 1079 #endif 1080 CdBugCheck( 0, 0, 0 ); 1081 } 1082 1083 // 1084 // Now do the common initialization. 1085 // 1086 1087 NewFcb->NodeTypeCode = NodeTypeCode; 1088 1089 NewFcb->Vcb = IrpContext->Vcb; 1090 NewFcb->FileId = FileId; 1091 1092 CdInitializeMcb( IrpContext, NewFcb ); 1093 1094 // 1095 // Now create the non-paged section object. 1096 // 1097 1098 NewFcb->FcbNonpaged = CdCreateFcbNonpaged( IrpContext ); 1099 1100 // 1101 // Deallocate the Fcb and raise if the allocation failed. 1102 // 1103 1104 if (NewFcb->FcbNonpaged == NULL) { 1105 1106 CdFreePool( &NewFcb ); 1107 1108 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 1109 } 1110 1111 *FcbExisted = FALSE; 1112 1113 // 1114 // Initialize Advanced FCB Header fields 1115 // 1116 1117 ExInitializeFastMutex( &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex ); 1118 FsRtlSetupAdvancedHeader( &NewFcb->Header, 1119 &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex ); 1120 1121 if (NodeTypeCode == CDFS_NTC_FCB_DATA) { 1122 1123 FsRtlInitializeOplock( CdGetFcbOplock(NewFcb) ); 1124 } 1125 1126 } else { 1127 1128 *FcbExisted = TRUE; 1129 } 1130 1131 return NewFcb; 1132 } 1133 1134 1135 VOID 1136 CdInitializeFcbFromPathEntry ( 1137 _In_ PIRP_CONTEXT IrpContext, 1138 _Inout_ PFCB Fcb, 1139 _In_opt_ PFCB ParentFcb, 1140 _In_ PPATH_ENTRY PathEntry 1141 ) 1142 1143 /*++ 1144 1145 Routine Description: 1146 1147 This routine is called to initialize an Fcb for a directory from 1148 the path entry. Since we only have a starting point for the directory, 1149 not the length, we can only speculate on the sizes. 1150 1151 The general initialization is performed in CdCreateFcb. 1152 1153 Arguments: 1154 1155 Fcb - Newly created Fcb for this stream. 1156 1157 ParentFcb - Parent Fcb for this stream. It may not be present. 1158 1159 PathEntry - PathEntry for this Fcb in the Path Table. 1160 1161 Return Value: 1162 1163 None 1164 1165 --*/ 1166 1167 { 1168 PAGED_CODE(); 1169 1170 // 1171 // Fill in the Index specific fields of the Fcb. 1172 // 1173 1174 Fcb->StreamOffset = BytesFromBlocks( Fcb->Vcb, 1175 SectorBlockOffset( Fcb->Vcb, PathEntry->DiskOffset )); 1176 1177 Fcb->Ordinal = PathEntry->Ordinal; 1178 1179 // 1180 // Initialize the common header in the Fcb. The node type is already 1181 // present. 1182 // 1183 1184 Fcb->Resource = &Fcb->Vcb->FileResource; 1185 1186 // 1187 // Always set the sizes to one sector until we read the self-entry. 1188 // 1189 1190 Fcb->AllocationSize.QuadPart = 1191 Fcb->FileSize.QuadPart = 1192 Fcb->ValidDataLength.QuadPart = SECTOR_SIZE; 1193 1194 CdAddInitialAllocation( IrpContext, 1195 Fcb, 1196 PathEntry->DiskOffset, 1197 SECTOR_SIZE ); 1198 // 1199 // State flags for this Fcb. 1200 // 1201 1202 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY ); 1203 1204 // 1205 // Link into the other in-memory structures and into the Fcb table. 1206 // 1207 1208 if (ParentFcb != NULL) { 1209 1210 Fcb->ParentFcb = ParentFcb; 1211 1212 InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks ); 1213 1214 CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 ); 1215 } 1216 1217 CdInsertFcbTable( IrpContext, Fcb ); 1218 SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE ); 1219 1220 return; 1221 } 1222 1223 1224 VOID 1225 CdInitializeFcbFromFileContext ( 1226 _In_ PIRP_CONTEXT IrpContext, 1227 _Inout_ PFCB Fcb, 1228 _In_ PFCB ParentFcb, 1229 _In_ PFILE_ENUM_CONTEXT FileContext 1230 ) 1231 1232 /*++ 1233 1234 Routine Description: 1235 1236 This routine is called to initialize an Fcb for a file from 1237 the file context. We have looked up all of the dirents for this 1238 stream and have the full file size. We will load the all of the allocation 1239 for the file into the Mcb now. 1240 1241 The general initialization is performed in CdCreateFcb. 1242 1243 Arguments: 1244 1245 Fcb - Newly created Fcb for this stream. 1246 1247 ParentFcb - Parent Fcb for this stream. 1248 1249 FileContext - FileContext for the file. 1250 1251 Return Value: 1252 1253 None 1254 1255 --*/ 1256 1257 { 1258 PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent; 1259 PCOMPOUND_DIRENT CurrentCompoundDirent; 1260 1261 LONGLONG CurrentFileOffset; 1262 ULONG CurrentMcbEntryOffset; 1263 1264 PAGED_CODE(); 1265 1266 // 1267 // Use a try-finally to facilitate cleanup. 1268 // 1269 1270 CdLockFcb( IrpContext, Fcb ); 1271 1272 _SEH2_TRY { 1273 1274 // 1275 // Initialize the common header in the Fcb. The node type is already 1276 // present. 1277 // 1278 1279 Fcb->Resource = &IrpContext->Vcb->FileResource; 1280 1281 // 1282 // Allocation occurs in block-sized units. 1283 // 1284 1285 Fcb->FileSize.QuadPart = 1286 Fcb->ValidDataLength.QuadPart = FileContext->FileSize; 1287 1288 Fcb->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, FileContext->FileSize ); 1289 1290 // 1291 // Set the flags from the dirent. We always start with the read-only bit. 1292 // 1293 1294 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY ); 1295 if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_HIDDEN )) { 1296 1297 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN ); 1298 } 1299 1300 // 1301 // Convert the time to NT time. 1302 // 1303 1304 CdConvertCdTimeToNtTime( IrpContext, 1305 ThisDirent->CdTime, 1306 (PLARGE_INTEGER) &Fcb->CreationTime ); 1307 1308 // 1309 // Set the flag indicating the type of extent. 1310 // 1311 1312 if (ThisDirent->ExtentType != Form1Data) { 1313 1314 if (ThisDirent->ExtentType == Mode2Form2Data) { 1315 1316 SetFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE ); 1317 1318 } else { 1319 1320 SetFlag( Fcb->FcbState, FCB_STATE_DA_FILE ); 1321 } 1322 1323 Fcb->XAAttributes = ThisDirent->XAAttributes; 1324 Fcb->XAFileNumber = ThisDirent->XAFileNumber; 1325 } 1326 1327 // 1328 // Read through all of the dirents for the file until we find the last 1329 // and add the allocation into the Mcb. 1330 // 1331 1332 CurrentCompoundDirent = FileContext->InitialDirent; 1333 CurrentFileOffset = 0; 1334 CurrentMcbEntryOffset = 0; 1335 1336 while (TRUE) { 1337 1338 CdAddAllocationFromDirent( IrpContext, 1339 Fcb, 1340 CurrentMcbEntryOffset, 1341 CurrentFileOffset, 1342 &CurrentCompoundDirent->Dirent ); 1343 1344 // 1345 // Break out if we are at the last dirent. 1346 // 1347 1348 if (!FlagOn( CurrentCompoundDirent->Dirent.DirentFlags, CD_ATTRIBUTE_MULTI )) { 1349 1350 break; 1351 } 1352 1353 CurrentFileOffset += CurrentCompoundDirent->Dirent.DataLength; 1354 CurrentMcbEntryOffset += 1; 1355 1356 // 1357 // We better be able to find the next dirent. 1358 // 1359 1360 if (!CdLookupNextDirent( IrpContext, 1361 ParentFcb, 1362 &CurrentCompoundDirent->DirContext, 1363 &FileContext->CurrentDirent->DirContext )) { 1364 1365 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 1366 } 1367 1368 CurrentCompoundDirent = FileContext->CurrentDirent; 1369 1370 CdUpdateDirentFromRawDirent( IrpContext, 1371 ParentFcb, 1372 &CurrentCompoundDirent->DirContext, 1373 &CurrentCompoundDirent->Dirent ); 1374 } 1375 1376 // 1377 // Show that the Fcb is initialized. 1378 // 1379 1380 SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED ); 1381 1382 // 1383 // Link into the other in-memory structures and into the Fcb table. 1384 // 1385 1386 Fcb->ParentFcb = ParentFcb; 1387 1388 InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks ); 1389 1390 CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 ); 1391 1392 CdInsertFcbTable( IrpContext, Fcb ); 1393 SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE ); 1394 1395 } _SEH2_FINALLY { 1396 1397 CdUnlockFcb( IrpContext, Fcb ); 1398 } _SEH2_END; 1399 1400 return; 1401 } 1402 1403 1404 PCCB 1405 CdCreateCcb ( 1406 _In_ PIRP_CONTEXT IrpContext, 1407 _In_ PFCB Fcb, 1408 _In_ ULONG Flags 1409 ) 1410 1411 /*++ 1412 1413 Routine Description: 1414 1415 This routine is called to allocate and initialize the Ccb structure. 1416 1417 Arguments: 1418 1419 Fcb - This is the Fcb for the file being opened. 1420 1421 Flags - User flags to set in this Ccb. 1422 1423 Return Value: 1424 1425 PCCB - Pointer to the created Ccb. 1426 1427 --*/ 1428 1429 { 1430 PCCB NewCcb; 1431 PAGED_CODE(); 1432 1433 UNREFERENCED_PARAMETER( IrpContext ); 1434 1435 // 1436 // Allocate and initialize the structure. 1437 // 1438 1439 NewCcb = CdAllocateCcb( IrpContext ); 1440 1441 RtlZeroMemory( NewCcb, sizeof( CCB )); 1442 1443 // 1444 // Set the proper node type code and node byte size 1445 // 1446 1447 NewCcb->NodeTypeCode = CDFS_NTC_CCB; 1448 NewCcb->NodeByteSize = sizeof( CCB ); 1449 1450 // 1451 // Set the initial value for the flags and Fcb 1452 // 1453 1454 NewCcb->Flags = Flags; 1455 NewCcb->Fcb = Fcb; 1456 1457 return NewCcb; 1458 } 1459 1460 1461 VOID 1462 CdDeleteCcb ( 1463 _In_ PIRP_CONTEXT IrpContext, 1464 _In_ __drv_freesMem( Pool ) PCCB Ccb 1465 ) 1466 /*++ 1467 1468 Routine Description: 1469 1470 This routine is called to cleanup and deallocate a Ccb structure. 1471 1472 Arguments: 1473 1474 Ccb - This is the Ccb to delete. 1475 1476 Return Value: 1477 1478 None 1479 1480 --*/ 1481 1482 { 1483 PAGED_CODE(); 1484 1485 UNREFERENCED_PARAMETER( IrpContext ); 1486 1487 if (Ccb->SearchExpression.FileName.Buffer != NULL) { 1488 1489 CdFreePool( &Ccb->SearchExpression.FileName.Buffer ); 1490 } 1491 1492 CdDeallocateCcb( IrpContext, Ccb ); 1493 return; 1494 } 1495 1496 1497 _When_(RaiseOnError || return, _At_(Fcb->FileLock, _Post_notnull_)) 1498 _When_(RaiseOnError, _At_(IrpContext, _Pre_notnull_)) 1499 BOOLEAN 1500 CdCreateFileLock ( 1501 _In_opt_ PIRP_CONTEXT IrpContext, 1502 _Inout_ PFCB Fcb, 1503 _In_ BOOLEAN RaiseOnError 1504 ) 1505 1506 /*++ 1507 1508 Routine Description: 1509 1510 This routine is called when we want to attach a file lock structure to the 1511 given Fcb. It is possible the file lock is already attached. 1512 1513 This routine is sometimes called from the fast path and sometimes in the 1514 Irp-based path. We don't want to raise in the fast path, just return FALSE. 1515 1516 Arguments: 1517 1518 Fcb - This is the Fcb to create the file lock for. 1519 1520 RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we 1521 return FALSE on an allocation failure. 1522 1523 Return Value: 1524 1525 BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise. 1526 1527 --*/ 1528 1529 { 1530 BOOLEAN Result = TRUE; 1531 PFILE_LOCK FileLock; 1532 1533 PAGED_CODE(); 1534 1535 // 1536 // Lock the Fcb and check if there is really any work to do. 1537 // 1538 1539 CdLockFcb( IrpContext, Fcb ); 1540 1541 if (Fcb->FileLock != NULL) { 1542 1543 CdUnlockFcb( IrpContext, Fcb ); 1544 return TRUE; 1545 } 1546 1547 Fcb->FileLock = FileLock = 1548 FsRtlAllocateFileLock( NULL, NULL ); 1549 1550 CdUnlockFcb( IrpContext, Fcb ); 1551 1552 // 1553 // Return or raise as appropriate. 1554 // 1555 1556 if (FileLock == NULL) { 1557 1558 if (RaiseOnError) { 1559 1560 NT_ASSERT( ARGUMENT_PRESENT( IrpContext )); 1561 1562 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 1563 } 1564 1565 Result = FALSE; 1566 } 1567 1568 return Result; 1569 } 1570 1571 1572 _Ret_valid_ PIRP_CONTEXT 1573 CdCreateIrpContext ( 1574 _In_ PIRP Irp, 1575 _In_ BOOLEAN Wait 1576 ) 1577 1578 /*++ 1579 1580 Routine Description: 1581 1582 This routine is called to initialize an IrpContext for the current 1583 CDFS request. We allocate the structure and then initialize it from 1584 the given Irp. 1585 1586 Arguments: 1587 1588 Irp - Irp for this request. 1589 1590 Wait - TRUE if this request is synchronous, FALSE otherwise. 1591 1592 Return Value: 1593 1594 PIRP_CONTEXT - Allocated IrpContext. 1595 1596 --*/ 1597 1598 { 1599 PIRP_CONTEXT NewIrpContext = NULL; 1600 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1601 1602 PAGED_CODE(); 1603 1604 // 1605 // The only operations a filesystem device object should ever receive 1606 // are create/teardown of fsdo handles and operations which do not 1607 // occur in the context of fileobjects (i.e., mount). 1608 // 1609 1610 #ifndef __REACTOS__ 1611 if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject) { 1612 #else 1613 if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject || 1614 IrpSp->DeviceObject == CdData.HddFileSystemDeviceObject) { 1615 #endif 1616 1617 if (IrpSp->FileObject != NULL && 1618 IrpSp->MajorFunction != IRP_MJ_CREATE && 1619 IrpSp->MajorFunction != IRP_MJ_CLEANUP && 1620 IrpSp->MajorFunction != IRP_MJ_CLOSE) { 1621 1622 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST ); 1623 } 1624 1625 NT_ASSERT( IrpSp->FileObject != NULL || 1626 1627 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 1628 IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST && 1629 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) || 1630 1631 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 1632 IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) || 1633 1634 IrpSp->MajorFunction == IRP_MJ_SHUTDOWN ); 1635 } 1636 1637 // 1638 // Look in our lookaside list for an IrpContext. 1639 // 1640 1641 if (CdData.IrpContextDepth) { 1642 1643 CdLockCdData(); 1644 NewIrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList ); 1645 if (NewIrpContext != NULL) { 1646 1647 CdData.IrpContextDepth--; 1648 } 1649 1650 CdUnlockCdData(); 1651 } 1652 1653 if (NewIrpContext == NULL) { 1654 1655 // 1656 // We didn't get it from our private list so allocate it from pool. 1657 // 1658 1659 NewIrpContext = FsRtlAllocatePoolWithTag( CdNonPagedPool, sizeof( IRP_CONTEXT ), TAG_IRP_CONTEXT ); 1660 } 1661 1662 RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT )); 1663 1664 // 1665 // Set the proper node type code and node byte size 1666 // 1667 1668 NewIrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT; 1669 NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT ); 1670 1671 // 1672 // Set the originating Irp field 1673 // 1674 1675 NewIrpContext->Irp = Irp; 1676 1677 // 1678 // Copy RealDevice for workque algorithms. We will update this in the Mount or 1679 // Verify since they have no file objects to use here. 1680 // 1681 1682 if (IrpSp->FileObject != NULL) { 1683 1684 NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject; 1685 } 1686 1687 // 1688 // Locate the volume device object and Vcb that we are trying to access. 1689 // This may be our filesystem device object. In that case don't initialize 1690 // the Vcb field. 1691 // 1692 1693 #ifndef __REACTOS__ 1694 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) { 1695 #else 1696 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject && 1697 IrpSp->DeviceObject != CdData.HddFileSystemDeviceObject) { 1698 #endif 1699 1700 NewIrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb; 1701 1702 } 1703 1704 // 1705 // Major/Minor Function codes 1706 // 1707 1708 NewIrpContext->MajorFunction = IrpSp->MajorFunction; 1709 NewIrpContext->MinorFunction = IrpSp->MinorFunction; 1710 1711 // 1712 // Set the wait parameter 1713 // 1714 1715 if (Wait) { 1716 1717 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 1718 1719 } else { 1720 1721 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 1722 } 1723 1724 // 1725 // return and tell the caller 1726 // 1727 1728 return NewIrpContext; 1729 } 1730 1731 1732 VOID 1733 CdCleanupIrpContext ( 1734 _In_ PIRP_CONTEXT IrpContext, 1735 _In_ BOOLEAN Post 1736 ) 1737 1738 /*++ 1739 1740 Routine Description: 1741 1742 This routine is called to cleanup and possibly deallocate the Irp Context. 1743 If the request is being posted or this Irp Context is possibly on the 1744 stack then we only cleanup any auxilary structures. 1745 1746 Arguments: 1747 1748 Post - TRUE if we are posting this request, FALSE if we are deleting 1749 or retrying this in the current thread. 1750 1751 Return Value: 1752 1753 None. 1754 1755 --*/ 1756 1757 { 1758 PAGED_CODE(); 1759 1760 // 1761 // If we aren't doing more processing then deallocate this as appropriate. 1762 // 1763 1764 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) { 1765 1766 // 1767 // If this context is the top level CDFS context then we need to 1768 // restore the top level thread context. 1769 // 1770 1771 if (IrpContext->ThreadContext != NULL) { 1772 1773 CdRestoreThreadContext( IrpContext ); 1774 } 1775 1776 // 1777 // Deallocate the Io context if allocated. 1778 // 1779 1780 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) { 1781 1782 CdFreeIoContext( IrpContext->IoContext ); 1783 } 1784 1785 // 1786 // Deallocate the IrpContext if not from the stack. 1787 // 1788 1789 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) { 1790 1791 if (CdData.IrpContextDepth < CdData.IrpContextMaxDepth) { 1792 1793 CdLockCdData(); 1794 1795 PushEntryList( &CdData.IrpContextList, (PSINGLE_LIST_ENTRY) IrpContext ); 1796 CdData.IrpContextDepth++; 1797 1798 CdUnlockCdData(); 1799 1800 } else { 1801 1802 // 1803 // We couldn't add this to our lookaside list so free it to 1804 // pool. 1805 // 1806 1807 CdFreePool( &IrpContext ); 1808 } 1809 } 1810 1811 // 1812 // Clear the appropriate flags. 1813 // 1814 1815 } else if (Post) { 1816 1817 // 1818 // If this context is the top level CDFS context then we need to 1819 // restore the top level thread context. 1820 // 1821 1822 if (IrpContext->ThreadContext != NULL) { 1823 1824 CdRestoreThreadContext( IrpContext ); 1825 } 1826 1827 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST ); 1828 1829 } else { 1830 1831 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY ); 1832 } 1833 1834 return; 1835 } 1836 1837 1838 VOID 1839 CdInitializeStackIrpContext ( 1840 _Out_ PIRP_CONTEXT IrpContext, 1841 _In_ PIRP_CONTEXT_LITE IrpContextLite 1842 ) 1843 1844 /*++ 1845 1846 Routine Description: 1847 1848 This routine is called to initialize an IrpContext for the current 1849 CDFS request. The IrpContext is on the stack and we need to initialize 1850 it for the current request. The request is a close operation. 1851 1852 Arguments: 1853 1854 IrpContext - IrpContext to initialize. 1855 1856 IrpContextLite - Structure containing the details of this request. 1857 1858 Return Value: 1859 1860 None 1861 1862 --*/ 1863 1864 { 1865 PAGED_CODE(); 1866 1867 // 1868 // Zero and then initialize the structure. 1869 // 1870 1871 RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT )); 1872 1873 // 1874 // Set the proper node type code and node byte size 1875 // 1876 1877 IrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT; 1878 IrpContext->NodeByteSize = sizeof( IRP_CONTEXT ); 1879 1880 // 1881 // Note that this is from the stack. 1882 // 1883 1884 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK ); 1885 1886 // 1887 // Copy RealDevice for workque algorithms. 1888 // 1889 1890 IrpContext->RealDevice = IrpContextLite->RealDevice; 1891 1892 // 1893 // The Vcb is found in the Fcb. 1894 // 1895 1896 IrpContext->Vcb = IrpContextLite->Fcb->Vcb; 1897 1898 // 1899 // Major/Minor Function codes 1900 // 1901 1902 IrpContext->MajorFunction = IRP_MJ_CLOSE; 1903 1904 // 1905 // Set the wait parameter 1906 // 1907 1908 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 1909 1910 return; 1911 } 1912 1913 1914 1915 _Requires_lock_held_(_Global_critical_region_) 1916 VOID 1917 CdTeardownStructures ( 1918 _In_ PIRP_CONTEXT IrpContext, 1919 _Inout_ PFCB StartingFcb, 1920 _Out_ PBOOLEAN RemovedStartingFcb 1921 ) 1922 1923 /*++ 1924 1925 Routine Description: 1926 1927 This routine is used to walk from some starting point in the Fcb tree towards 1928 the root. It will remove the Fcb and continue walking up the tree until 1929 it finds a point where we can't remove an Fcb. 1930 1931 We look at the following fields in the Fcb to determine whether we can 1932 remove this. 1933 1934 1 - Handle count must be zero. 1935 2 - If directory then only the only reference can be for a stream file. 1936 3 - Reference count must either be zero or go to zero here. 1937 1938 We return immediately if we are recursively entering this routine. 1939 1940 Arguments: 1941 1942 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb 1943 must currently be acquired exclusively. 1944 1945 RemovedStartingFcb - Address to store whether we removed the starting Fcb. 1946 1947 Return Value: 1948 1949 None 1950 1951 --*/ 1952 1953 { 1954 PVCB Vcb = StartingFcb->Vcb; 1955 PFCB CurrentFcb = StartingFcb; 1956 BOOLEAN AcquiredCurrentFcb = FALSE; 1957 PFCB ParentFcb; 1958 1959 PAGED_CODE(); 1960 1961 *RemovedStartingFcb = FALSE; 1962 1963 // 1964 // If this is a recursive call to TearDownStructures we return immediately 1965 // doing no operation. 1966 // 1967 1968 if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) { 1969 1970 return; 1971 } 1972 1973 SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN ); 1974 1975 // 1976 // Use a try-finally to safely clear the top-level field. 1977 // 1978 1979 _SEH2_TRY { 1980 1981 // 1982 // Loop until we find an Fcb we can't remove. 1983 // 1984 1985 do { 1986 1987 // 1988 // See if there is an internal stream we should delete. 1989 // Only do this if it is the last reference on the Fcb. 1990 // 1991 1992 if ((SafeNodeType( CurrentFcb ) != CDFS_NTC_FCB_DATA) && 1993 (CurrentFcb->FcbUserReference == 0) && 1994 (CurrentFcb->FileObject != NULL)) { 1995 1996 // 1997 // Go ahead and delete the stream file object. 1998 // 1999 2000 CdDeleteInternalStream( IrpContext, CurrentFcb ); 2001 } 2002 2003 // 2004 // If the reference count is non-zero then break. 2005 // 2006 2007 if (CurrentFcb->FcbReference != 0) { 2008 2009 break; 2010 } 2011 2012 // 2013 // It looks like we have a candidate for removal here. We 2014 // will need to acquire the parent, if present, in order to 2015 // remove this from the parent prefix table. 2016 // 2017 2018 ParentFcb = CurrentFcb->ParentFcb; 2019 2020 if (ParentFcb != NULL) { 2021 2022 CdAcquireFcbExclusive( IrpContext, ParentFcb, FALSE ); 2023 } 2024 2025 // 2026 // Now lock the vcb. 2027 // 2028 2029 CdLockVcb( IrpContext, Vcb ); 2030 2031 // 2032 // Final check to see if the reference count is still zero. 2033 // 2034 2035 if (CurrentFcb->FcbReference != 0) { 2036 2037 CdUnlockVcb( IrpContext, Vcb ); 2038 2039 if (ParentFcb != NULL) { 2040 2041 CdReleaseFcb( IrpContext, ParentFcb ); 2042 } 2043 2044 break; 2045 } 2046 2047 // 2048 // If there is a parent then do the necessary cleanup for the parent. 2049 // 2050 2051 if (ParentFcb != NULL) { 2052 2053 CdRemovePrefix( IrpContext, CurrentFcb ); 2054 RemoveEntryList( &CurrentFcb->FcbLinks ); 2055 2056 CdDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 ); 2057 } 2058 2059 if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) { 2060 2061 CdDeleteFcbTable( IrpContext, CurrentFcb ); 2062 ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE ); 2063 2064 } 2065 2066 // 2067 // Unlock the Vcb but hold the parent in order to walk up 2068 // the tree. 2069 // 2070 2071 CdUnlockVcb( IrpContext, Vcb ); 2072 CdDeleteFcb( IrpContext, CurrentFcb ); 2073 2074 // 2075 // Move to the parent Fcb. 2076 // 2077 2078 CurrentFcb = ParentFcb; 2079 AcquiredCurrentFcb = TRUE; 2080 2081 } while (CurrentFcb != NULL); 2082 2083 } _SEH2_FINALLY { 2084 2085 // 2086 // Release the current Fcb if we have acquired it. 2087 // 2088 2089 if (AcquiredCurrentFcb && (CurrentFcb != NULL)) { 2090 2091 CdReleaseFcb( IrpContext, CurrentFcb ); 2092 } 2093 2094 // 2095 // Clear the teardown flag. 2096 // 2097 2098 ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN ); 2099 } _SEH2_END; 2100 2101 *RemovedStartingFcb = (CurrentFcb != StartingFcb); 2102 return; 2103 } 2104 2105 2106 PFCB 2107 CdLookupFcbTable ( 2108 _In_ PIRP_CONTEXT IrpContext, 2109 _In_ PVCB Vcb, 2110 _In_ FILE_ID FileId 2111 ) 2112 2113 /*++ 2114 2115 Routine Description: 2116 2117 This routine will look through the Fcb table looking for a matching 2118 entry. 2119 2120 Arguments: 2121 2122 Vcb - Vcb for this volume. 2123 2124 FileId - This is the key value to use for the search. 2125 2126 Return Value: 2127 2128 PFCB - A pointer to the matching entry or NULL otherwise. 2129 2130 --*/ 2131 2132 { 2133 FCB_TABLE_ELEMENT Key; 2134 PFCB_TABLE_ELEMENT Hit; 2135 PFCB ReturnFcb = NULL; 2136 2137 PAGED_CODE(); 2138 2139 Key.FileId = FileId; 2140 2141 Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key ); 2142 2143 if (Hit != NULL) { 2144 2145 ReturnFcb = Hit->Fcb; 2146 } 2147 2148 return ReturnFcb; 2149 2150 UNREFERENCED_PARAMETER( IrpContext ); 2151 } 2152 2153 2154 PFCB 2155 CdGetNextFcb ( 2156 _In_ PIRP_CONTEXT IrpContext, 2157 _In_ PVCB Vcb, 2158 _In_ PVOID *RestartKey 2159 ) 2160 2161 /*++ 2162 2163 Routine Description: 2164 2165 This routine will enumerate through all of the Fcb's in the Fcb table. 2166 2167 Arguments: 2168 2169 Vcb - Vcb for this volume. 2170 2171 RestartKey - This value is used by the table package to maintain 2172 its position in the enumeration. It is initialized to NULL 2173 for the first search. 2174 2175 Return Value: 2176 2177 PFCB - A pointer to the next fcb or NULL if the enumeration is 2178 completed 2179 2180 --*/ 2181 2182 { 2183 PFCB Fcb; 2184 2185 PAGED_CODE(); 2186 2187 UNREFERENCED_PARAMETER( IrpContext ); 2188 2189 Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey ); 2190 2191 if (Fcb != NULL) { 2192 2193 Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb; 2194 } 2195 2196 return Fcb; 2197 } 2198 2199 2200 NTSTATUS 2201 CdProcessToc ( 2202 _In_ PIRP_CONTEXT IrpContext, 2203 _In_ PDEVICE_OBJECT TargetDeviceObject, 2204 _In_ PCDROM_TOC_LARGE CdromToc, 2205 _Inout_ PULONG Length, 2206 _Out_ PULONG TrackCount, 2207 _Inout_ PULONG DiskFlags 2208 ) 2209 2210 /*++ 2211 2212 Routine Description: 2213 2214 This routine is called to verify and process the TOC for this disk. 2215 We hide a data track for a CD+ volume. 2216 2217 Arguments: 2218 2219 TargetDeviceObject - Device object to send TOC request to. 2220 2221 CdromToc - Pointer to TOC structure. 2222 2223 Length - On input this is the length of the TOC. On return is the TOC 2224 length we will show to the user. 2225 2226 TrackCount - This is the count of tracks for the TOC. We use this 2227 when creating a pseudo directory for a music disk. 2228 2229 DiskFlags - We return flags indicating what we know about this disk. 2230 2231 Return Value: 2232 2233 NTSTATUS - The result of trying to read the TOC. 2234 2235 --*/ 2236 2237 { 2238 NTSTATUS Status; 2239 IO_STATUS_BLOCK Iosb; 2240 CDROM_READ_TOC_EX Command; 2241 2242 ULONG CurrentTrack; 2243 ULONG LocalTrackCount; 2244 ULONG LocalTocLength; 2245 ULONG Address = 0; 2246 BOOLEAN UseReadToc = FALSE; 2247 2248 union { 2249 2250 UCHAR BigEndian[2]; 2251 USHORT Length; 2252 2253 } BiasedTocLength; 2254 2255 PTRACK_DATA Track; 2256 2257 PAGED_CODE(); 2258 2259 // 2260 // Zero the command block. This conveniently corresponds to an 2261 // LBA mode READ_TOC request. 2262 // 2263 2264 RtlZeroMemory( &Command, sizeof( Command)); 2265 2266 RetryReadToc: 2267 2268 // 2269 // Go ahead and read the table of contents 2270 // 2271 2272 Status = CdPerformDevIoCtrlEx( IrpContext, 2273 UseReadToc ? IOCTL_CDROM_READ_TOC : IOCTL_CDROM_READ_TOC_EX, 2274 TargetDeviceObject, 2275 &Command, 2276 sizeof( Command ), 2277 CdromToc, 2278 sizeof( CDROM_TOC_LARGE ), 2279 FALSE, 2280 TRUE, 2281 &Iosb ); 2282 2283 // 2284 // Nothing to process if this request fails. 2285 // 2286 2287 if (!NT_SUCCESS( Status )) { 2288 2289 // 2290 // If the underlying device does not support READ_TOC_EX, try the old method. 2291 // 2292 2293 if (!UseReadToc && 2294 ((Status == STATUS_INVALID_DEVICE_REQUEST) || 2295 (Status == STATUS_NOT_IMPLEMENTED) || /* ReactOS Change: we return STATUS_NOT_IMPLEMENTED for IOCTL_CDROM_READ_TOC_EX */ 2296 (Status == STATUS_INVALID_PARAMETER))) { 2297 2298 UseReadToc = TRUE; 2299 goto RetryReadToc; 2300 } 2301 2302 return Status; 2303 } 2304 2305 // 2306 // Get the number of tracks and stated size of this structure. 2307 // 2308 2309 CurrentTrack = 0; 2310 LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1; 2311 LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] ); 2312 2313 // 2314 // Get out if there is an immediate problem with the TOC. 2315 // 2316 2317 if ((LocalTocLength > Iosb.Information) || 2318 (CdromToc->FirstTrack > CdromToc->LastTrack)) { 2319 2320 Status = STATUS_DISK_CORRUPT_ERROR; 2321 return Status; 2322 } 2323 2324 // 2325 // Walk through the individual tracks. Stop at the first data track after 2326 // any lead-in audio tracks. 2327 // 2328 2329 do { 2330 2331 // 2332 // Get the next track. 2333 // 2334 2335 Track = &CdromToc->TrackData[CurrentTrack]; 2336 2337 // 2338 // If this is a data track then check if we have only seen audio tracks 2339 // to this point. 2340 // 2341 2342 if (FlagOn( Track->Control, TOC_DATA_TRACK )) { 2343 2344 // 2345 // If we have only seen audio tracks then assume this is a 2346 // CD+ disk. Hide the current data track and only return 2347 // the previous audio tracks. Set the disk type to be mixed 2348 // data/audio. 2349 // 2350 2351 if (FlagOn( *DiskFlags, CDROM_DISK_AUDIO_TRACK ) && 2352 !FlagOn( *DiskFlags, CDROM_DISK_DATA_TRACK )) { 2353 2354 // 2355 // Remove one track from the TOC. 2356 // 2357 2358 CdromToc->LastTrack -= 1; 2359 2360 // 2361 // Knock 2.5 minutes off the current track to hide the final leadin. 2362 // 2.5 min = 150 sec = (x 75) 11250 frames (sectors). 2363 // 2364 2365 SwapCopyUchar4( &Address, &Track->Address); 2366 Address -= 11250; 2367 SwapCopyUchar4( &Track->Address, &Address); 2368 2369 Track->TrackNumber = TOC_LAST_TRACK; 2370 2371 // 2372 // Set the disk type to mixed data/audio. 2373 // 2374 2375 SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK ); 2376 2377 break; 2378 } 2379 2380 // 2381 // Set the flag to indicate data tracks present. 2382 // 2383 2384 SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK ); 2385 2386 // 2387 // If this is a audio track then set the flag indicating audio 2388 // tracks. 2389 // 2390 2391 } else { 2392 2393 SetFlag( *DiskFlags, CDROM_DISK_AUDIO_TRACK ); 2394 } 2395 2396 // 2397 // Set our index for the next track. 2398 // 2399 2400 CurrentTrack += 1; 2401 2402 } while (CurrentTrack < LocalTrackCount); 2403 2404 // 2405 // Set the length to point just past the last track we looked at. 2406 // 2407 2408 *TrackCount = CurrentTrack; 2409 *Length = PtrOffset( CdromToc, &CdromToc->TrackData[CurrentTrack + 1] ); 2410 BiasedTocLength.Length = (USHORT) *Length - 2; 2411 2412 CdromToc->Length[0] = BiasedTocLength.BigEndian[1]; 2413 CdromToc->Length[1] = BiasedTocLength.BigEndian[0]; 2414 2415 return Status; 2416 } 2417 2418 2419 // 2420 // Local support routine 2421 // 2422 2423 VOID 2424 CdDeleteFcb ( 2425 _In_ PIRP_CONTEXT IrpContext, 2426 _In_ PFCB Fcb 2427 ) 2428 2429 /*++ 2430 2431 Routine Description: 2432 2433 This routine is called to cleanup and deallocate an Fcb. We know there 2434 are no references remaining. We cleanup any auxilary structures and 2435 deallocate this Fcb. 2436 2437 Arguments: 2438 2439 Fcb - This is the Fcb to deallcoate. 2440 2441 Return Value: 2442 2443 None 2444 2445 --*/ 2446 2447 { 2448 PVCB Vcb = NULL; 2449 PAGED_CODE(); 2450 2451 // 2452 // Sanity check the counts. 2453 // 2454 2455 NT_ASSERT( Fcb->FcbCleanup == 0 ); 2456 NT_ASSERT( Fcb->FcbReference == 0 ); 2457 2458 // 2459 // Release any Filter Context structures associated with this FCB 2460 // 2461 2462 FsRtlTeardownPerStreamContexts( &Fcb->Header ); 2463 2464 // 2465 // Start with the common structures. 2466 // 2467 2468 CdUninitializeMcb( IrpContext, Fcb ); 2469 2470 CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged ); 2471 2472 // 2473 // Check if we need to deallocate the prefix name buffer. 2474 // 2475 2476 if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) && 2477 (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) { 2478 2479 CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer ); 2480 } 2481 2482 // 2483 // Now look at the short name prefix. 2484 // 2485 2486 if (Fcb->ShortNamePrefix != NULL) { 2487 2488 CdFreePool( &Fcb->ShortNamePrefix ); 2489 } 2490 2491 // 2492 // Now do the type specific structures. 2493 // 2494 2495 switch (Fcb->NodeTypeCode) { 2496 2497 case CDFS_NTC_FCB_PATH_TABLE: 2498 case CDFS_NTC_FCB_INDEX: 2499 2500 NT_ASSERT( Fcb->FileObject == NULL ); 2501 NT_ASSERT( IsListEmpty( &Fcb->FcbQueue )); 2502 2503 if (Fcb == Fcb->Vcb->RootIndexFcb) { 2504 2505 Vcb = Fcb->Vcb; 2506 Vcb->RootIndexFcb = NULL; 2507 2508 } else if (Fcb == Fcb->Vcb->PathTableFcb) { 2509 2510 Vcb = Fcb->Vcb; 2511 Vcb->PathTableFcb = NULL; 2512 } 2513 2514 CdDeallocateFcbIndex( IrpContext, *(PVOID*)&Fcb );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */ 2515 break; 2516 2517 case CDFS_NTC_FCB_DATA : 2518 2519 if (Fcb->FileLock != NULL) { 2520 2521 FsRtlFreeFileLock( Fcb->FileLock ); 2522 } 2523 2524 FsRtlUninitializeOplock( CdGetFcbOplock(Fcb) ); 2525 2526 if (Fcb == Fcb->Vcb->VolumeDasdFcb) { 2527 2528 Vcb = Fcb->Vcb; 2529 Vcb->VolumeDasdFcb = NULL; 2530 } 2531 2532 CdDeallocateFcbData( IrpContext, *(PVOID*)&Fcb );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */ 2533 } 2534 2535 // 2536 // Decrement the Vcb reference count if this is a system 2537 // Fcb. 2538 // 2539 2540 if (Vcb != NULL) { 2541 2542 InterlockedDecrement( (LONG*)&Vcb->VcbReference ); 2543 InterlockedDecrement( (LONG*)&Vcb->VcbUserReference ); 2544 } 2545 2546 return; 2547 } 2548 2549 2550 // 2551 // Local support routine 2552 // 2553 2554 PFCB_NONPAGED 2555 CdCreateFcbNonpaged ( 2556 _In_ PIRP_CONTEXT IrpContext 2557 ) 2558 2559 /*++ 2560 2561 Routine Description: 2562 2563 This routine is called to create and initialize the non-paged portion 2564 of an Fcb. 2565 2566 Arguments: 2567 2568 Return Value: 2569 2570 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created. 2571 2572 --*/ 2573 2574 { 2575 PFCB_NONPAGED FcbNonpaged; 2576 2577 PAGED_CODE(); 2578 2579 UNREFERENCED_PARAMETER( IrpContext ); 2580 2581 // 2582 // Allocate the non-paged pool and initialize the various 2583 // synchronization objects. 2584 // 2585 2586 FcbNonpaged = CdAllocateFcbNonpaged( IrpContext ); 2587 2588 if (FcbNonpaged != NULL) { 2589 2590 RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED )); 2591 2592 FcbNonpaged->NodeTypeCode = CDFS_NTC_FCB_NONPAGED; 2593 FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED ); 2594 2595 ExInitializeResourceLite( &FcbNonpaged->FcbResource ); 2596 ExInitializeFastMutex( &FcbNonpaged->FcbMutex ); 2597 } 2598 2599 return FcbNonpaged; 2600 } 2601 2602 2603 // 2604 // Local support routine 2605 // 2606 2607 VOID 2608 CdDeleteFcbNonpaged ( 2609 _In_ PIRP_CONTEXT IrpContext, 2610 _In_ PFCB_NONPAGED FcbNonpaged 2611 ) 2612 2613 /*++ 2614 2615 Routine Description: 2616 2617 This routine is called to cleanup the non-paged portion of an Fcb. 2618 2619 Arguments: 2620 2621 FcbNonpaged - Structure to clean up. 2622 2623 Return Value: 2624 2625 None 2626 2627 --*/ 2628 2629 { 2630 PAGED_CODE(); 2631 2632 UNREFERENCED_PARAMETER( IrpContext ); 2633 2634 ExDeleteResourceLite( &FcbNonpaged->FcbResource ); 2635 2636 CdDeallocateFcbNonpaged( IrpContext, *(PVOID*)&FcbNonpaged );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */ 2637 2638 return; 2639 } 2640 2641 2642 // 2643 // Local support routine 2644 // 2645 2646 RTL_GENERIC_COMPARE_RESULTS 2647 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2648 CdFcbTableCompare ( 2649 _In_ PRTL_GENERIC_TABLE FcbTable, 2650 _In_ PVOID Fid1, 2651 _In_ PVOID Fid2 2652 ) 2653 2654 /*++ 2655 2656 Routine Description: 2657 2658 This routine is the Cdfs compare routine called by the generic table package. 2659 If will compare the two File Id values and return a comparison result. 2660 2661 Arguments: 2662 2663 FcbTable - This is the table being searched. 2664 2665 Fid1 - First key value. 2666 2667 Fid2 - Second key value. 2668 2669 Return Value: 2670 2671 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two 2672 input structures 2673 2674 --*/ 2675 2676 { 2677 FILE_ID Id1, Id2; 2678 PAGED_CODE(); 2679 2680 Id1 = *((FILE_ID UNALIGNED *) Fid1); 2681 Id2 = *((FILE_ID UNALIGNED *) Fid2); 2682 2683 if (Id1.QuadPart < Id2.QuadPart) { 2684 2685 return GenericLessThan; 2686 2687 } else if (Id1.QuadPart > Id2.QuadPart) { 2688 2689 return GenericGreaterThan; 2690 2691 } else { 2692 2693 return GenericEqual; 2694 } 2695 2696 UNREFERENCED_PARAMETER( FcbTable ); 2697 } 2698 2699 2700 // 2701 // Local support routine 2702 // 2703 2704 PVOID 2705 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2706 CdAllocateFcbTable ( 2707 _In_ PRTL_GENERIC_TABLE FcbTable, 2708 _In_ CLONG ByteSize 2709 ) 2710 2711 /*++ 2712 2713 Routine Description: 2714 2715 This is a generic table support routine to allocate memory 2716 2717 Arguments: 2718 2719 FcbTable - Supplies the generic table being used 2720 2721 ByteSize - Supplies the number of bytes to allocate 2722 2723 Return Value: 2724 2725 PVOID - Returns a pointer to the allocated data 2726 2727 --*/ 2728 2729 { 2730 PAGED_CODE(); 2731 2732 UNREFERENCED_PARAMETER( FcbTable ); 2733 2734 return( FsRtlAllocatePoolWithTag( CdPagedPool, ByteSize, TAG_FCB_TABLE )); 2735 } 2736 2737 2738 // 2739 // Local support routine 2740 // 2741 VOID 2742 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 2743 CdDeallocateFcbTable ( 2744 _In_ PRTL_GENERIC_TABLE FcbTable, 2745 _In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer 2746 ) 2747 /*++ 2748 2749 Routine Description: 2750 2751 This is a generic table support routine that deallocates memory 2752 2753 Arguments: 2754 2755 FcbTable - Supplies the generic table being used 2756 2757 Buffer - Supplies the buffer being deallocated 2758 2759 Return Value: 2760 2761 None. 2762 2763 --*/ 2764 2765 { 2766 PAGED_CODE(); 2767 2768 CdFreePool( &Buffer ); 2769 2770 UNREFERENCED_PARAMETER( FcbTable ); 2771 } 2772 2773 2774 // 2775 // Local support routine 2776 // 2777 2778 ULONG 2779 CdTocSerial ( 2780 _In_ PIRP_CONTEXT IrpContext, 2781 _In_ PCDROM_TOC_LARGE CdromToc 2782 ) 2783 2784 /*++ 2785 2786 Routine Description: 2787 2788 This routine is called to generate a serial number for an audio disk. 2789 The number is based on the starting positions of the tracks. 2790 The following algorithm is used. 2791 2792 If the number of tracks is <= 2 then initialize the serial number to the 2793 leadout block number. 2794 2795 Then add the starting address of each track (use 0x00mmssff format). 2796 2797 Arguments: 2798 2799 CdromToc - Valid table of contents to use for track information. 2800 2801 Return Value: 2802 2803 ULONG - 32 bit serial number based on TOC. 2804 2805 --*/ 2806 2807 { 2808 ULONG SerialNumber = 0; 2809 PTRACK_DATA ThisTrack; 2810 PTRACK_DATA LastTrack; 2811 ULONG Address; 2812 ULONG MsfAddress = 0; // satisfy PREFIX 2813 2814 PAGED_CODE(); 2815 2816 UNREFERENCED_PARAMETER( IrpContext ); 2817 2818 // 2819 // Check if there are two tracks or fewer. 2820 // 2821 2822 LastTrack = &CdromToc->TrackData[ CdromToc->LastTrack - CdromToc->FirstTrack + 1]; 2823 ThisTrack = &CdromToc->TrackData[0]; 2824 2825 if (CdromToc->LastTrack - CdromToc->FirstTrack <= 1) { 2826 2827 SwapCopyUchar4( &Address, LastTrack->Address); 2828 CdLbnToMmSsFf( Address, (PUCHAR)&SerialNumber); 2829 } 2830 else { 2831 2832 // 2833 // Add the starting offset of each track and add to the serial number. 2834 // 2835 2836 while (ThisTrack != LastTrack) { 2837 2838 SwapCopyUchar4( &Address, ThisTrack->Address); 2839 CdLbnToMmSsFf( Address, (PUCHAR)&MsfAddress); 2840 2841 SerialNumber += MsfAddress; 2842 ThisTrack += 1; 2843 } 2844 } 2845 2846 return SerialNumber; 2847 } 2848 2849 2850