1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// AppleCDDAFileSystemUtils.c created by CJS on Sun 14-May-2000 25 26#ifndef __APPLE_CDDA_FS_UTILS_H__ 27#include "AppleCDDAFileSystemUtils.h" 28#endif 29 30#ifndef __APPLE_CDDA_FS_DEBUG_H__ 31#include "AppleCDDAFileSystemDebug.h" 32#endif 33 34#ifndef __APPLE_CDDA_FS_DEFINES_H__ 35#include "AppleCDDAFileSystemDefines.h" 36#endif 37 38#ifndef __AIFF_SUPPORT_H__ 39#include "AIFFSupport.h" 40#endif 41 42#ifndef __APPLE_CDDA_FS_VFS_OPS_H__ 43#include "AppleCDDAFileSystemVFSOps.h" 44#endif 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/stat.h> 50#include <sys/proc.h> 51#include <sys/mount.h> 52#include <sys/vnode.h> 53#include <sys/namei.h> 54#include <sys/malloc.h> 55#include <sys/attr.h> 56#include <sys/time.h> 57#include <sys/ubc.h> 58#include <sys/unistd.h> 59 60 61//----------------------------------------------------------------------------- 62// Static Function Prototypes 63//----------------------------------------------------------------------------- 64 65static int BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr ); 66static UInt32 CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr ); 67static UInt32 CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr ); 68static int FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize ); 69 70 71//----------------------------------------------------------------------------- 72// CreateNewCDDANode - This routine is responsible for creating new nodes 73//----------------------------------------------------------------------------- 74 75errno_t 76CreateNewCDDANode ( mount_t mountPtr, 77 UInt32 nodeID, 78 enum vtype vNodeType, 79 vnode_t parentVNodePtr, 80 struct componentname * compNamePtr, 81 vnode_t * vNodeHandle ) 82{ 83 84 errno_t result = 0; 85 AppleCDDANodePtr cddaNodePtr = NULL; 86 vnode_t vNodePtr = NULLVP; 87 struct vnode_fsparam vfsp; 88 89 DebugAssert ( ( mountPtr != NULL ) ); 90 DebugAssert ( ( vNodeHandle != NULL ) ); 91 92 // Allocate the cddaNode 93 MALLOC ( cddaNodePtr, AppleCDDANodePtr, sizeof ( AppleCDDANode ), M_TEMP, M_WAITOK ); 94 95 // Zero the structure 96 bzero ( cddaNodePtr, sizeof ( AppleCDDANode ) ); 97 98 // Set the nodeID 99 cddaNodePtr->nodeID = nodeID; 100 101 // Zero the FS param structure 102 bzero ( &vfsp, sizeof ( vfsp ) ); 103 104 vfsp.vnfs_mp = mountPtr; 105 vfsp.vnfs_vtype = vNodeType; 106 vfsp.vnfs_str = "cddafs"; 107 vfsp.vnfs_dvp = parentVNodePtr; 108 vfsp.vnfs_fsnode = cddaNodePtr; 109 vfsp.vnfs_cnp = compNamePtr; 110 vfsp.vnfs_vops = gCDDA_VNodeOp_p; 111 vfsp.vnfs_rdev = 0; 112 113#if DEBUG 114 if ( compNamePtr != NULL ) 115 { 116 117 DebugLog ( ( "compNamePtr->cn_flags = 0x%08x\n", ( int ) compNamePtr->cn_flags ) ); 118 DebugLog ( ( "compNamePtr->cn_nameiop = 0x%08x\n", ( int ) compNamePtr->cn_nameiop ) ); 119 DebugLog ( ( "compNamePtr->cn_pnbuf = %s\n", compNamePtr->cn_pnbuf ) ); 120 DebugLog ( ( "compNamePtr->cn_nameptr = %s\n", compNamePtr->cn_nameptr ) ); 121 DebugLog ( ( "compNamePtr->cn_namelen = %ld\n", compNamePtr->cn_namelen ) ); 122 DebugLog ( ( "compNamePtr->cn_hash = 0x%08x\n", ( int ) compNamePtr->cn_hash ) ); 123 DebugLog ( ( "compNamePtr->cn_consume = %ld\n\n", compNamePtr->cn_consume ) ); 124 125 } 126#endif /* DEBUG */ 127 128 if ( ( parentVNodePtr != NULL ) && ( compNamePtr != NULL ) && ( compNamePtr->cn_flags & MAKEENTRY ) ) 129 vfsp.vnfs_flags = 0; 130 else 131 vfsp.vnfs_flags = VNFS_NOCACHE; 132 133 vfsp.vnfs_markroot = ( nodeID == kAppleCDDARootFileID ); 134 vfsp.vnfs_marksystem = 0; 135 136 // Note that vnode_create ( ) returns the vnode with an iocount of +1; 137 // this routine returns the newly created vnode with this positive iocount. 138 result = vnode_create ( VNCREATE_FLAVOR, ( uint32_t ) VCREATESIZE, &vfsp, &vNodePtr ); 139 if ( result != 0 ) 140 { 141 142 DebugLog ( ( "getnewvnode failed with error code %d\n", result ) ); 143 goto FREE_CDDA_NODE_ERROR; 144 145 } 146 147 // Link the cddaNode to the vnode 148 cddaNodePtr->vNodePtr = vNodePtr; 149 150 vnode_addfsref ( vNodePtr ); 151 152 // Return the vnode to the caller 153 *vNodeHandle = vNodePtr; 154 155 return result; 156 157 158FREE_CDDA_NODE_ERROR: 159 160 161 // Free the allocated memory 162 FREE ( ( caddr_t ) cddaNodePtr, M_TEMP ); 163 cddaNodePtr = NULL; 164 165 return result; 166 167} 168 169 170//----------------------------------------------------------------------------- 171// DisposeCDDANode - This routine is responsible for cleaning up cdda nodes 172//----------------------------------------------------------------------------- 173 174int 175DisposeCDDANode ( vnode_t vNodePtr ) 176{ 177 178 AppleCDDANodePtr cddaNodePtr = NULL; 179 180 DebugAssert ( ( vNodePtr != NULL ) ); 181 182 cddaNodePtr = VTOCDDA ( vNodePtr ); 183 184 DebugAssert ( ( cddaNodePtr != NULL ) ); 185 186 if ( cddaNodePtr != NULL ) 187 { 188 189 // Free memory associated with our filesystem's internal data 190 FREE ( vnode_fsnode ( vNodePtr ), M_TEMP ); 191 vnode_clearfsnode ( vNodePtr ); 192 193 } 194 195 return ( 0 ); 196 197} 198 199 200//----------------------------------------------------------------------------- 201// CreateNewCDDAFile - This routine is responsible for creating new 202// files 203//----------------------------------------------------------------------------- 204 205errno_t 206CreateNewCDDAFile ( mount_t mountPtr, 207 UInt32 nodeID, 208 AppleCDDANodeInfoPtr nodeInfoPtr, 209 vnode_t parentVNodePtr, 210 struct componentname * compNamePtr, 211 vnode_t * vNodeHandle ) 212{ 213 214 errno_t result = 0; 215 vnode_t vNodePtr = NULLVP; 216 AppleCDDANodePtr cddaNodePtr = NULL; 217 AppleCDDANodePtr parentCDDANodePtr = NULL; 218 AppleCDDAMountPtr cddaMountPtr = NULL; 219 struct componentname cn; 220 221 bzero ( &cn, sizeof ( cn ) ); 222 223 DebugAssert ( ( mountPtr != NULL ) ); 224 DebugAssert ( ( nodeInfoPtr != NULL ) ); 225 DebugAssert ( ( vNodeHandle != NULL ) ); 226 227 cddaMountPtr = VFSTOCDDA ( mountPtr ); 228 parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); 229 230 DebugAssert ( ( cddaMountPtr != NULL ) ); 231 DebugAssert ( ( parentCDDANodePtr != NULL ) ); 232 233 if ( parentVNodePtr == NULL ) 234 { 235 236 DebugLog ( ( "CreateNewCDDAFile called with NULL parentVNodePtr\n" ) ); 237 parentVNodePtr = cddaMountPtr->root; 238 239 } 240 241 if ( compNamePtr == NULL ) 242 { 243 244 DebugLog ( ( "CreateNewCDDAFile called with NULL compNamePtr\n" ) ); 245 246 MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK ); 247 248 cn.cn_nameiop = LOOKUP; 249 cn.cn_flags = ISLASTCN | MAKEENTRY; 250 cn.cn_pnlen = MAXPATHLEN; 251 cn.cn_nameptr = cn.cn_pnbuf; 252 cn.cn_namelen = nodeInfoPtr->nameSize; 253 cn.cn_hash = 0; 254 cn.cn_consume = 0; 255 256 bcopy ( nodeInfoPtr->name, cn.cn_nameptr, nodeInfoPtr->nameSize + 1 ); 257 258 compNamePtr = &cn; 259 260 } 261 262 result = CreateNewCDDANode ( mountPtr, nodeID, VREG, parentVNodePtr, compNamePtr, &vNodePtr ); 263 if ( result != 0 ) 264 { 265 266 DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); 267 return result; 268 269 } 270 271 if ( cn.cn_pnbuf != NULL ) 272 { 273 274 DebugLog ( ( "CreateNewCDDAFile: freeing cn_pnbuf\n" ) ); 275 FREE ( cn.cn_pnbuf, M_TEMP ); 276 277 } 278 279 cddaNodePtr = VTOCDDA ( vNodePtr ); 280 281 DebugAssert ( ( cddaNodePtr != NULL ) ); 282 283 // Build the header. 284 BuildCDAIFFHeader ( &cddaNodePtr->u.file.aiffHeader, nodeInfoPtr->numBytes ); 285 286 // Fill in the miscellaneous fields for the cddaNode 287 cddaNodePtr->nodeType = kAppleCDDATrackType; 288 cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr; 289 290 // Set the back pointer 291 cddaNodePtr->u.file.nodeInfoPtr = nodeInfoPtr; 292 293 DebugLog ( ( "LBA of %d = %ld.\n", cddaNodePtr->nodeID, nodeInfoPtr->LBA ) ); 294 295 // stuff the vNode in 296 *vNodeHandle = vNodePtr; 297 298 return 0; 299 300} 301 302 303//----------------------------------------------------------------------------- 304// CreateNewXMLFile - This routine is responsible for creating the ".TOC.plist" 305// file which has XML data describing the CD layout. 306//----------------------------------------------------------------------------- 307 308errno_t 309CreateNewXMLFile ( mount_t mountPtr, 310 UInt32 xmlFileSize, 311 UInt8 * xmlData, 312 vnode_t parentVNodePtr, 313 struct componentname * compNamePtr, 314 vnode_t * vNodeHandle ) 315{ 316 317 errno_t result = 0; 318 vnode_t vNodePtr = NULLVP; 319 AppleCDDANodePtr cddaNodePtr = NULL; 320 AppleCDDANodePtr parentCDDANodePtr = NULL; 321 AppleCDDAMountPtr cddaMountPtr = NULL; 322 struct componentname cn; 323 324 bzero ( &cn, sizeof ( cn ) ); 325 326 DebugAssert ( ( mountPtr != NULL ) ); 327 DebugAssert ( ( vNodeHandle != NULL ) ); 328 329 cddaMountPtr = VFSTOCDDA ( mountPtr ); 330 parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); 331 332 DebugAssert ( ( cddaMountPtr != NULL ) ); 333 DebugAssert ( ( parentCDDANodePtr != NULL ) ); 334 335 if ( parentVNodePtr == NULL ) 336 { 337 338 DebugLog ( ( "CreateNewXMLFile called with NULL parentVNodePtr\n" ) ); 339 parentVNodePtr = cddaMountPtr->root; 340 341 } 342 343 if ( compNamePtr == NULL ) 344 { 345 346 DebugLog ( ( "CreateNewXMLFile called with NULL compNamePtr\n" ) ); 347 348 MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK ); 349 350 cn.cn_nameiop = LOOKUP; 351 cn.cn_flags = ISLASTCN | MAKEENTRY; 352 cn.cn_pnlen = MAXPATHLEN; 353 cn.cn_nameptr = cn.cn_pnbuf; 354 cn.cn_namelen = ( uint32_t ) strlen ( ".TOC.plist" ); 355 cn.cn_hash = 0; 356 cn.cn_consume = 0; 357 358 snprintf ( cn.cn_nameptr, MAXPATHLEN, "%s", ".TOC.plist" ); 359 360 compNamePtr = &cn; 361 362 } 363 364 result = CreateNewCDDANode ( mountPtr, kAppleCDDAXMLFileID, VREG, parentVNodePtr, compNamePtr, &vNodePtr ); 365 if ( result != 0 ) 366 { 367 368 DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); 369 return result; 370 371 } 372 373 if ( cn.cn_pnbuf != NULL ) 374 { 375 376 DebugLog ( ( "CreateNewXMLFile: freeing cn_pnbuf\n" ) ); 377 FREE ( cn.cn_pnbuf, M_TEMP ); 378 379 } 380 381 cddaNodePtr = VTOCDDA ( vNodePtr ); 382 383 DebugAssert ( ( cddaNodePtr != NULL ) ); 384 385 // Fill in the miscellaneous fields for the cddaNode 386 cddaNodePtr->nodeType = kAppleCDDAXMLFileType; 387 cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr; 388 389 // Point the xmlData to the correct place 390 cddaNodePtr->u.xmlFile.fileDataPtr = xmlData; 391 cddaNodePtr->u.xmlFile.fileSize = xmlFileSize; 392 393 #if 0 394 { 395 UInt32 count; 396 // Let's see if we got the right data mapped in 397 for ( count = 0; count < xmlFileSize; count = count + 8 ) 398 { 399 400 DebugLog ( ( "%x:%x:%x:%x %x:%x:%x:%x\n", 401 xmlData[count], 402 xmlData[count+1], 403 xmlData[count+2], 404 xmlData[count+3], 405 xmlData[count+4], 406 xmlData[count+5], 407 xmlData[count+6], 408 xmlData[count+7] ) ); 409 410 } 411 412 DebugLog ( ( "\n" ) ); 413 414 } 415 #endif 416 417 // stuff the vNode in 418 *vNodeHandle = vNodePtr; 419 420 return 0; 421 422} 423 424 425//----------------------------------------------------------------------------- 426// CreateNewCDDADirectory - This routine is responsible for creating new 427// directories (i.e. the root directory) 428//----------------------------------------------------------------------------- 429 430errno_t 431CreateNewCDDADirectory ( mount_t mountPtr, 432 UInt32 nodeID, 433 vnode_t * vNodeHandle ) 434{ 435 436 errno_t result = 0; 437 vnode_t vNodePtr = NULLVP; 438 AppleCDDANodePtr cddaNodePtr = NULL; 439 440 DebugAssert ( ( mountPtr != NULL ) ); 441 DebugAssert ( ( vNodeHandle != NULL ) ); 442 443 result = CreateNewCDDANode ( mountPtr, nodeID, VDIR, NULL, NULL, &vNodePtr ); 444 if ( result != 0 ) 445 { 446 447 DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) ); 448 return result; 449 450 } 451 452 cddaNodePtr = VTOCDDA ( vNodePtr ); 453 DebugAssert ( ( cddaNodePtr != NULL ) ); 454 455 // Set up the directory-specific fields 456 cddaNodePtr->nodeType = kAppleCDDADirectoryType; 457 cddaNodePtr->u.directory.directorySize = 0; 458 cddaNodePtr->u.directory.entryCount = kNumberOfFakeDirEntries; // ".", "..", and ".TOC.plist" 459 460 // stuff the vNode in 461 *vNodeHandle = vNodePtr; 462 463 return 0; 464 465} 466 467 468//----------------------------------------------------------------------------- 469// IsAudioTrack - Checks the arguments passed in to find out if specified 470// track is audio or not 471//----------------------------------------------------------------------------- 472 473boolean_t 474IsAudioTrack ( const SubQTOCInfoPtr trackDescriptorPtr ) 475{ 476 477 DebugAssert ( ( trackDescriptorPtr != NULL ) ); 478 479 // Check to make sure the point is between 1 and 99 (inclusive) 480 if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 ) 481 { 482 483 // Do we have digital data? 484 if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 ) 485 { 486 487 // Found an audio track 488 return TRUE; 489 490 } 491 492 } 493 494 return FALSE; 495 496} 497 498 499//----------------------------------------------------------------------------- 500// CalculateSize - Calculate the file size based on number of frames 501// (i.e. blocks) in the track 502//----------------------------------------------------------------------------- 503 504UInt32 505CalculateSize ( const QTOCDataFormat10Ptr TOCDataPtr, 506 UInt32 trackDescriptorOffset, 507 UInt32 currentA2Offset ) 508{ 509 510 UInt32 size = 0; 511 UInt32 offset = 0; 512 UInt32 numberOfDescriptors = 0; 513 UInt32 nextOffset = 0; 514 SubQTOCInfoPtr trackDescriptorPtr = NULL; 515 SubQTOCInfoPtr nextTrackDescriptorPtr = NULL; 516 517 DebugLog ( ( "CalculateSize: Entering...\n" ) ); 518 519 DebugAssert ( ( TOCDataPtr != NULL ) ); 520 521 // Find the number of descriptors 522 numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr ); 523 524 // Get the correct track descriptor 525 trackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset]; 526 527 // Are we past the total number of descriptors in TOC? 528 if ( trackDescriptorOffset + 1 >= numberOfDescriptors ) 529 { 530 531 // yes, so set the descriptor to the last leadout descriptor we hit 532 nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset]; 533 534 } 535 536 else 537 { 538 539 // no, so set the descriptor to the next entry in the TOC 540 nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset + 1]; 541 542 // Are we past the end of the session? 543 if ( trackDescriptorPtr->sessionNumber != nextTrackDescriptorPtr->sessionNumber || 544 !IsAudioTrack ( nextTrackDescriptorPtr ) ) 545 { 546 547 // yes, so set the descriptor to the last leadout descriptor we hit 548 nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset]; 549 550 } 551 552 } 553 554 // Calculate the LBAs for both tracks 555 offset = CalculateLBA ( trackDescriptorPtr ); 556 nextOffset = CalculateLBA ( nextTrackDescriptorPtr ); 557 558 // Multiply number of blocks by block size and add the header + pad (1 block) 559 size = ( ( nextOffset - offset ) * kPhysicalMediaBlockSize ) + kPhysicalMediaBlockSize; 560 561 DebugLog ( ( "CalculateSize: size = %ld.\n", size ) ); 562 563 DebugLog ( ( "CalculateSize: exiting...\n" ) ); 564 565 return size; 566 567} 568 569 570//----------------------------------------------------------------------------- 571// FindName - Parses the names data that gets passed in to the 572// filesystem, looking for the specified track's name. 573// All names look like the following packed structure: 574// 575// | 1 byte | 1 byte | number of bytes in 2nd byte | 576// Track # size of String String for Name 577// 578// Track # of zero corresponds to the album name (the mount point name). 579//----------------------------------------------------------------------------- 580 581 582int 583FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize ) 584{ 585 586 AppleCDDAMountPtr cddaMountPtr = NULL; 587 UInt8 * ptr = NULL; 588 UInt8 length = 0; 589 590 DebugLog ( ( "FindName: entering\n" ) ); 591 DebugLog ( ( "trackNumber = %d\n" ) ); 592 593 DebugAssert ( ( mountPtr != NULL ) ); 594 DebugAssert ( ( name != NULL ) ); 595 DebugAssert ( ( nameSize != NULL ) ); 596 597 cddaMountPtr = VFSTOCDDA ( mountPtr ); 598 DebugLog ( ( "cddaMountPtr->nameDataSize = %ld\n", cddaMountPtr->nameDataSize ) ); 599 600 ptr = cddaMountPtr->nameData; 601 602 if ( ptr == NULL ) 603 { 604 605 DebugLog ( ( "cddaMountPtr->nameData is NULL" ) ); 606 return ENOENT; 607 608 } 609 610 do 611 { 612 613 DebugLog ( ( "*ptr = %d\n", *ptr ) ); 614 615 if ( *ptr == trackNumber ) 616 { 617 618 char mylocalname[512]; 619 620 DebugLog ( ( "Found track = %d\n", trackNumber ) ); 621 622 *nameSize = ptr[1]; 623 *name = ( char * ) &ptr[2]; 624 625 bcopy ( &ptr[2], mylocalname, *nameSize ); 626 mylocalname[*nameSize] = 0; 627 628 DebugLog ( ( "NameSize = %d\n", *nameSize ) ); 629 DebugLog ( ( "Name = %s\n", mylocalname ) ); 630 631 break; 632 633 } 634 635 else 636 { 637 638 length = ptr[1]; 639 640 DebugLog ( ( "Didn't find it, keep looking\n" ) ); 641 ptr = &ptr[length + 2]; 642 643 } 644 645 } while ( ptr < ( cddaMountPtr->nameData + cddaMountPtr->nameDataSize ) ); 646 647 DebugLog ( ( "FindName: exiting\n" ) ); 648 649 return 0; 650 651} 652 653 654//----------------------------------------------------------------------------- 655// ParseTOC - Parses the TOC to find audio tracks. It figures out which 656// tracks are audio and what their offsets are and fills in the 657// cddaNode structures associated with each vnode 658//----------------------------------------------------------------------------- 659 660SInt32 661ParseTOC ( mount_t mountPtr, 662 UInt32 numTracks ) 663{ 664 665 QTOCDataFormat10Ptr TOCDataPtr = NULL; 666 SubQTOCInfoPtr trackDescriptorPtr = NULL; 667 AppleCDDAMountPtr cddaMountPtr = NULL; 668 AppleCDDANodeInfoPtr nodeInfoPtr = NULL; 669 AppleCDDADirectoryNodePtr rootDirNodePtr = NULL; 670 OSStatus error = 0; 671 UInt16 numberOfDescriptors = 0; 672 UInt32 currentA2Offset = 0; 673 UInt32 currentOffset = 0; 674 675 DebugLog ( ( "ParseTOC: Entering...\n" ) ); 676 677 DebugAssert ( ( mountPtr != NULL ) ); 678 679 cddaMountPtr = VFSTOCDDA ( mountPtr ); 680 rootDirNodePtr = &( ( VTOCDDA ( cddaMountPtr->root ) )->u.directory ); 681 682 DebugAssert ( ( cddaMountPtr != NULL ) ); 683 DebugAssert ( ( rootDirNodePtr != NULL ) ); 684 685 // Get the data from the registry entry 686 TOCDataPtr = CreateBufferFromIORegistry ( mountPtr ); 687 688 if ( TOCDataPtr != NULL ) 689 { 690 691 // calculate number of track descriptors 692 numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr ); 693 DebugLog ( ( "Number of descriptors = %d\n", numberOfDescriptors ) ); 694 695 if ( numberOfDescriptors <= 0 ) 696 { 697 698 // This is bad...no track descriptors, time to bail 699 error = EINVAL; 700 goto Exit; 701 702 } 703 704 trackDescriptorPtr = TOCDataPtr->trackDescriptors; 705 706 while ( numberOfDescriptors > 0 && rootDirNodePtr->entryCount < ( numTracks + kNumberOfFakeDirEntries ) ) 707 { 708 709 if ( trackDescriptorPtr->point == 0xA2 ) 710 { 711 712 // Set the a2 offset when we find an a2 point 713 currentA2Offset = currentOffset; 714 715 } 716 717 // Is this an audio track? 718 if ( IsAudioTrack ( trackDescriptorPtr ) ) 719 { 720 721 // Make this easier to read by getting a pointer to the nodeInfo 722 nodeInfoPtr = &cddaMountPtr->nodeInfoArrayPtr[rootDirNodePtr->entryCount - kNumberOfFakeDirEntries]; 723 724 // Copy this trackDescriptor into the AppleCDDANodeInfo array 725 nodeInfoPtr->trackDescriptor = *trackDescriptorPtr; 726 727 // Get the LogicalBlockAddress and number of bytes in the track 728 nodeInfoPtr->LBA = CalculateLBA ( trackDescriptorPtr ); 729 nodeInfoPtr->numBytes = CalculateSize ( TOCDataPtr, currentOffset, currentA2Offset ); 730 731 // Add this node's size to the root directory's directorySize field 732 rootDirNodePtr->directorySize += nodeInfoPtr->numBytes; 733 734 // Increment the number of audio tracks 735 rootDirNodePtr->entryCount++; 736 737 ( void ) BuildTrackName ( mountPtr, nodeInfoPtr ); 738 739 DebugLog ( ( "LBA of %d = %ld.\n", trackDescriptorPtr->point, nodeInfoPtr->LBA ) ); 740 741 } 742 743 // Advance the pointers and decrement the count 744 trackDescriptorPtr++; 745 numberOfDescriptors--; 746 currentOffset++; 747 748 } 749 750 if ( ( numberOfDescriptors != 0 ) && ( rootDirNodePtr->entryCount == ( numTracks + kNumberOfFakeDirEntries ) ) ) 751 { 752 753 // Oops...the parsing routine in userland must've screwed up 754 DebugLog ( ( "ParseTOC: userland utility sent wrong number of audio tracks in at mount time.\n" ) ); 755 756 } 757 758 } 759 760 else 761 { 762 763 // Couldn't parse the TOC, so return an error 764 return ENOMEM; 765 766 } 767 768 769Exit: 770 771 772 if ( TOCDataPtr != NULL ) 773 { 774 775 // Free the buffer allocated earlier 776 DisposeBufferFromIORegistry ( TOCDataPtr ); 777 778 } 779 780 DebugLog ( ( "ParseTOC: exiting...\n" ) ); 781 782 return error; 783 784} 785 786 787//----------------------------------------------------------------------------- 788// BuildTrackName - This routine is responsible for building a track 789// name based on its number 790//----------------------------------------------------------------------------- 791 792int 793BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr ) 794{ 795 796 UInt8 trackNumber = 0; 797 char * name = NULL; 798 UInt8 nameSize = 0; 799 int error = 0; 800 801 DebugLog ( ( "BuildTrackName: entering.\n" ) ); 802 803 DebugAssert ( ( nodeInfoPtr != NULL ) ); 804 805 // Get the track number for which to find the name 806 trackNumber = nodeInfoPtr->trackDescriptor.point; 807 808 // Find the name 809 error = FindName ( mountPtr, trackNumber, &name, &nameSize ); 810 if ( error != 0 ) 811 { 812 813 DebugLog ( ( "cddafs : FindName returned error = %d\n", error ) ); 814 // Buffer copied in was formatted incorrectly. We'll just use 815 // track numbers on this CD. 816 817 } 818 819 // Set the size of the name 820 nodeInfoPtr->nameSize = nameSize; 821 822 // If we got here, then we have a valid track and the nodeInfoArrayPtr points to our 823 // offset into the array. So, MALLOC the name here 824 MALLOC ( nodeInfoPtr->name, char *, nodeInfoPtr->nameSize + 1, M_TEMP, M_WAITOK ); 825 826 // Copy the name 827 bcopy ( name, &nodeInfoPtr->name[0], nameSize ); 828 829 // Don't forget NULL byte 830 nodeInfoPtr->name[nameSize] = 0; 831 832 DebugLog ( ( "BuildTrackName: fileName = %s\n", nodeInfoPtr->name ) ); 833 834 return 0; 835 836} 837 838 839//----------------------------------------------------------------------------- 840// CalculateNumberOfDescriptors - Calculate the number of SubQTOCInfo entries 841// in the given TOC 842//----------------------------------------------------------------------------- 843 844UInt32 845CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr ) 846{ 847 848 UInt32 numberOfDescriptors = 0; 849 UInt32 length = 0; 850 851 DebugLog ( ( "CalculateNumberOfDescriptors: Entering...\n" ) ); 852 853 DebugAssert ( ( TOCDataPtr != NULL ) ); 854 855 // Get the length of the TOC 856 length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength ); 857 858 // Remove the first and last session numbers so all we are left with are track descriptors 859 length -= ( UInt32 ) ( ( sizeof ( TOCDataPtr->firstSessionNumber ) + sizeof ( TOCDataPtr->lastSessionNumber ) ) ); 860 861 // Divide the length by the size of a single track descriptor to get total number 862 numberOfDescriptors = ( length / ( ( UInt32 ) sizeof ( SubQTOCInfo ) ) ); 863 864 DebugLog ( ( "CalculateNumberOfDescriptors: exiting...\n" ) ); 865 866 return numberOfDescriptors; 867 868} 869 870 871//----------------------------------------------------------------------------- 872// CalculateLBA - Convert the frames offset of the file (from the TOC) to 873// the LBA of the device 874// 875// NB: this is a workaround because the first 2 seconds of a CD are unreadable 876// and defined as off-limits. So we convert our absolute MSF to an actual 877// logical block which can be addressed through the BSD layer. 878//----------------------------------------------------------------------------- 879 880UInt32 881CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr ) 882{ 883 884 UInt32 frames = 0; 885 886 DebugAssert ( ( trackDescriptorPtr != NULL ) ); 887 888 frames = ( ( ( trackDescriptorPtr->PMSF.startPosition.minutes * kSecondsPerMinute ) + 889 trackDescriptorPtr->PMSF.startPosition.seconds ) * kFramesPerSecond ) + 890 trackDescriptorPtr->PMSF.startPosition.frames; 891 892 if ( frames < kMSFToLBA ) 893 frames = kMSFToLBA; 894 895 // Simply convert MSF to LBA 896 return frames - kMSFToLBA; 897 898} 899 900 901//----------------------------------------------------------------------------- 902// End Of File 903//----------------------------------------------------------------------------- 904