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// cddafs_util.c created by CJS on Mon 10-Apr-2000 25 26 27//----------------------------------------------------------------------------- 28// Includes 29//----------------------------------------------------------------------------- 30 31// System Includes 32#include <stdio.h> 33#include <unistd.h> 34#include <string.h> 35#include <stdlib.h> 36#include <fcntl.h> 37#include <dirent.h> 38#include <libgen.h> 39#include <mntopts.h> 40#include <mach/mach_init.h> 41#include <servers/netname.h> 42#include <sys/types.h> 43#include <sys/wait.h> 44#include <sys/sysctl.h> 45#include <sys/disk.h> 46#include <sys/errno.h> 47#include <sys/param.h> 48#include <sys/paths.h> 49#include <sys/stat.h> 50#include <sys/time.h> 51#include <sys/mount.h> 52#include <sys/loadable_fs.h> 53 54// Libkern includes 55#include <libkern/OSByteOrder.h> 56 57// CoreFoundation Includes 58#include <CoreFoundation/CoreFoundation.h> 59#include <CoreFoundation/CFPriv.h> 60 61// IOKit Includes 62#include <IOKit/IOKitLib.h> 63#include <IOKit/storage/IOCDTypes.h> 64#include <IOKit/storage/IOCDMedia.h> 65 66// Project includes 67#include "cddafs_util.h" 68#include "AppleCDDAFileSystemDefines.h" 69 70 #include "CDDATrackName.h" 71 72 73//----------------------------------------------------------------------------- 74// Macros 75//----------------------------------------------------------------------------- 76 77#define DEBUG 0 78#define DEBUG_LEVEL 0 79 80#ifndef DEBUG_ASSERT_COMPONENT_NAME_STRING 81 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "cddafs.util" 82#endif 83 84#include <AssertMacros.h> 85 86#if (DEBUG_LEVEL > 3) 87#define DebugLog(x) printf x 88#else 89#define DebugLog(x) 90#endif 91 92static int 93UtilityMain ( int argc, const char * argv[] ); 94 95static int 96MountMain ( int argc, const char * argv[] ); 97 98static CFDataRef 99GetTrackData ( const char * bsdDevNode, 100 const QTOCDataFormat10Ptr TOCData ); 101 102//----------------------------------------------------------------------------- 103// Globals 104//----------------------------------------------------------------------------- 105 106struct mntopt gMountOptions[] = 107{ 108 MOPT_STDOPTS, 109 { NULL } 110}; 111 112static char gAppleCDDAName[MFSNAMELEN] = "cddafs"; 113static char gFileSuffix[] = ".aiff"; 114 115#define kMaxPrefixSize 3 116#define kASCIINumberZero 0x30 117#define kASCIISpace 0x20 118 119//----------------------------------------------------------------------------- 120// main - This our main entry point to this utility. We get called by 121// autodiskmount. 122//----------------------------------------------------------------------------- 123 124int 125main ( int argc, const char * argv[] ) 126{ 127 128 int result = -1; 129 char * executableName = NULL; 130 131 #if DEBUG 132 int index = 0; 133 134 for ( index = 0; index < argc; index++ ) 135 { 136 printf ( "[%d] = %s\n", index, argv[index] ); 137 } 138 #endif 139 140 executableName = basename ( ( char * ) argv[0] ); 141 if ( executableName == NULL ) 142 exit ( 1 ); 143 144 if ( strcmp ( executableName, kUtilExecutableName ) == 0 ) 145 { 146 147 result = UtilityMain ( argc, argv ); 148 149 } 150 151 else 152 { 153 result = MountMain ( argc, argv ); 154 } 155 156 return result; 157 158} 159 160 161#if 0 162#pragma mark - 163#pragma mark - Utility Code 164#pragma mark - 165#endif 166 167 168//----------------------------------------------------------------------------- 169// UtilityMain - Returns FSUR_IO_SUCCESS if everything works, else it 170// returns one of the FSUR_XXX errors in loadable_fs.h 171//----------------------------------------------------------------------------- 172 173static int 174UtilityMain ( int argc, const char * argv[] ) 175{ 176 177 char rawDeviceName[MAXPATHLEN]; 178 char blockDeviceName[MAXPATHLEN]; 179 const char * actionPtr = NULL; 180 const char * mountPointPtr = NULL; 181 int result = FSUR_IO_SUCCESS; 182 boolean_t isLocked = 0; 183 boolean_t isEjectable = 0; 184 int mountFlags = MNT_RDONLY; 185 186 // Verify our arguments 187 result = ParseUtilityArgs ( argc, argv, &actionPtr, &mountPointPtr, &isEjectable, &isLocked ); 188 require ( ( result == 0 ), Exit ); 189 190 // Build our device name (full path), should end up with something like: 191 // -- "/dev/disk1" or "/dev/disk2" or "/dev/disk3" 192 193 snprintf ( rawDeviceName, MAXPATHLEN, "/dev/r%s", argv[2] ); 194 snprintf ( blockDeviceName, MAXPATHLEN, "/dev/%s", argv[2] ); 195 196 // call the appropriate routine to handle the given action argument after becoming root 197 result = seteuid ( 0 ); 198 require_action ( ( result == 0 ), Exit, result = FSUR_INVAL ); 199 200 result = setegid ( 0 ); 201 202 if ( result ) 203 { 204 DebugLog ( ( "cddafs.util: ERROR: setegid: %s\n", strerror ( errno ) ) ); 205 } 206 207 DebugLog ( ( "Entering the switch with action = %s\n", actionPtr ) ); 208 209 switch ( *actionPtr ) 210 { 211 212 case FSUC_PROBE: 213 result = Probe ( rawDeviceName ); 214 break; 215 216 case FSUC_MOUNT: 217 case FSUC_MOUNT_FORCE: 218 result = Mount ( blockDeviceName, mountPointPtr, mountFlags ); 219 break; 220 221 case FSUC_UNMOUNT: 222 result = Unmount ( mountPointPtr ); 223 break; 224 225 default: 226 // should never get here since DoVerifyArgs should handle this situation 227 DisplayUsage ( kUsageTypeUtility, argv ); 228 result = FSUR_INVAL; 229 break; 230 231 } 232 233 234Exit: 235 236 237 DebugLog ( ( "cddafs.util: EXIT: %d = ", result ) ); 238 switch ( result ) 239 { 240 241 case FSUR_LOADERR: 242 DebugLog ( ( "FSUR_LOADERR\n" ) ); 243 break; 244 245 case FSUR_INVAL: 246 DebugLog ( ( "FSUR_INVAL\n" ) ); 247 break; 248 249 case FSUR_IO_SUCCESS: 250 DebugLog ( ( "FSUR_IO_SUCCESS\n" ) ); 251 break; 252 253 case FSUR_IO_FAIL: 254 DebugLog ( ( "FSUR_IO_FAIL\n" ) ); 255 break; 256 257 case FSUR_RECOGNIZED: 258 DebugLog ( ( "FSUR_RECOGNIZED\n" ) ); 259 break; 260 261 case FSUR_MOUNT_HIDDEN: 262 DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) ); 263 break; 264 265 case FSUR_UNRECOGNIZED: 266 DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) ); 267 break; 268 269 default: 270 DebugLog ( ( "default\n" ) ); 271 break; 272 273 } 274 275 check ( result == FSUR_IO_SUCCESS ); 276 exit ( result ); 277 278 return result; // ...and make main fit the ANSI spec. 279 280} 281 282 283//----------------------------------------------------------------------------- 284// ParseUtilityArgs - This routine will make sure the arguments passed 285// in to us are copacetic. Here is how this utility is used: 286// 287// usage: cddafs.util actionArg deviceArg [mountPointArg] [flagsArg] 288// actionArg: 289// -p (Probe for mounting) 290// -P (Probe for initializing - not supported) 291// -m (Mount) 292// -r (Repair - not supported) 293// -u (Unmount) 294// -M (Force Mount) 295// -i (Initialize - not supported) 296// 297// deviceArg: 298// sd2 (for example) 299// 300// mountPointArg: 301// /foo/bar/ (required for Mount and Force Mount actions) 302// 303// flagsArg: 304// (these are ignored for CDROMs) 305// 306// examples: 307// cddafs.util -p sd2 removable writable 308// cddafs.util -p sd2 removable readonly 309// cddafs.util -m sd2 /my/cddafs 310// 311// Returns FSUR_INVAL if we find a bad argument, else 0. 312//----------------------------------------------------------------------------- 313 314int 315ParseUtilityArgs ( int argc, 316 const char * argv[], 317 const char ** actionPtr, 318 const char ** mountPointPtr, 319 boolean_t * isEjectablePtr, 320 boolean_t * isLockedPtr ) 321{ 322 323 int result = FSUR_INVAL; 324 int deviceLength = 0; 325 int index = 0; 326 327 // Must have at least 3 arguments and the action argument must start with a '-' 328 require_action ( ( argc >= 3 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) ); 329 require_action ( ( argv[1][0] == '-' ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) ); 330 331 // we only support actions Probe, Mount, Force Mount, and Unmount 332 *actionPtr = &argv[1][1]; 333 334 switch ( argv[1][1] ) 335 { 336 337 case FSUC_PROBE: 338 // action Probe and requires 5 arguments (need the flags) 339 require_action ( ( argc >= 5 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) ); 340 index = 3; 341 break; 342 343 case FSUC_UNMOUNT: 344 *mountPointPtr = argv[3]; 345 index = 0; // No isEjectable/isLocked flags for unmount. 346 break; 347 348 case FSUC_MOUNT: 349 case FSUC_MOUNT_FORCE: 350 // action Mount and ForceMount require 6 arguments 351 // ( need the mountpoint and the flags ) 352 require_action ( ( argc >= 6 ), Exit, DisplayUsage ( kUsageTypeUtility, argv ) ); 353 354 *mountPointPtr = argv[3]; 355 index = 4; 356 break; 357 358 default: 359 DisplayUsage ( kUsageTypeUtility, argv ); 360 goto Exit; 361 break; 362 363 } 364 365 // Make sure device (argv[2]) is something reasonable 366 // (we expect something like "disk1") 367 deviceLength = ( int ) strlen ( argv[2] ); 368 require ( ( deviceLength >= 5 ), Exit ); 369 370 result = 0; 371 372 // If index is zero, no more work to do... 373 require ( ( index != 0 ), Exit ); 374 375 // Flags: removable/fixed 376 if ( !strcmp ( argv[index], "removable" ) ) 377 { 378 379 *isEjectablePtr = 1; 380 381 } 382 383 else if ( !strcmp ( argv[index], "fixed" ) ) 384 { 385 386 *isEjectablePtr = 0; 387 388 } 389 390 else 391 { 392 393 DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (removable/fixed) argv[%d]='%s'\n", 394 index, argv[index] ) ); 395 396 } 397 398 // Flags: readonly/writable 399 if ( !strcmp ( argv[index + 1], "readonly" ) ) 400 { 401 *isLockedPtr = 1; 402 } 403 404 else if ( !strcmp ( argv[index + 1], "writable" ) ) 405 { 406 *isLockedPtr = 0; 407 } 408 409 else 410 { 411 DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (readonly/writable) argv[%d]='%s'\n", 412 index, argv[index + 1] ) ); 413 } 414 415 416Exit: 417 418 return result; 419 420} 421 422 423//----------------------------------------------------------------------------- 424// Probe - This routine will open the given raw device and check to 425// make sure there is media that looks like an Audio CD. Returns 426// FSUR_MOUNT_HIDDEN if everything works, else FSUR_IO_FAIL. 427// 428// deviceNamePtr - pointer to the raw device name (full path, like /dev/rdisk1) 429//----------------------------------------------------------------------------- 430 431int 432Probe ( char * deviceNamePtr ) 433{ 434 435 int result = FSUR_UNRECOGNIZED; 436 UInt8 * ptr = NULL; 437 438 DebugLog ( ( "ENTER: Probe('%s')\n", deviceNamePtr ) ); 439 440 ptr = GetTOCDataPtr ( deviceNamePtr ); 441 if ( ptr != NULL ) 442 { 443 444 // Parse the TOC for Audio Tracks 445 result = ParseTOC ( ptr ); 446 447 } 448 449 else 450 { 451 452 DebugLog ( ( "GetTOCDataPtr returned NULL.\n" ) ); 453 454 } 455 456 // if we recognized the disc, create the name and suffix files 457 if ( result == FSUR_RECOGNIZED ) 458 { 459 460 CFStringRef albumName = 0; 461 CDDATrackName * database = NULL; 462 463 database = new CDDATrackName; 464 465 if ( database != NULL ) 466 { 467 468 DebugLog ( ( "database != NULL\n" ) ); 469 470 database->Init ( deviceNamePtr, ptr ); 471 472 DebugLog ( ( "Init called\n" ) ); 473 474 albumName = database->GetAlbumName ( ); 475 DebugLog ( ( "GetAlbumName called\n" ) ); 476 477 } 478 479 if ( albumName != 0 ) 480 { 481 482 Boolean success = false; 483 char buffer[MAXNAMLEN]; 484 485 #if DEBUG 486 CFShow ( albumName ); 487 #endif 488 489 success = _CFStringGetFileSystemRepresentation ( albumName, 490 ( UInt8 * ) buffer, 491 MAXNAMLEN ); 492 493 if ( success == true ) 494 { 495 496 WriteDiskLabel ( buffer ); 497 498 } 499 500 else 501 { 502 503 // Good old "Audio CD" should work... 504 WriteDiskLabel ( ( char * ) kMountPointName ); 505 506 } 507 508 // release it 509 CFRelease ( albumName ); 510 albumName = 0; 511 512 } 513 514 else 515 { 516 517 // Good old "Audio CD" should work... 518 WriteDiskLabel ( ( char * ) kMountPointName ); 519 520 } 521 522 if ( database != NULL ) 523 { 524 525 delete database; 526 database = NULL; 527 528 } 529 530 } 531 532 if ( ptr != NULL ) 533 { 534 535 // free the memory 536 free ( ptr ); 537 ptr = NULL; 538 539 } 540 541 DebugLog ( ( "Probe: returns " ) ); 542 543 switch ( result ) 544 { 545 546 case FSUR_IO_FAIL: 547 DebugLog ( ( "FSUR_IO_FAIL\n" ) ); 548 break; 549 550 case FSUR_RECOGNIZED: 551 DebugLog ( ( "FSUR_RECOGNIZED\n" ) ); 552 break; 553 554 case FSUR_MOUNT_HIDDEN: 555 DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) ); 556 break; 557 558 case FSUR_UNRECOGNIZED: 559 DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) ); 560 break; 561 562 default: 563 DebugLog ( ( "default\n" ) ); 564 break; 565 566 } 567 568 return result; 569 570} 571 572 573//----------------------------------------------------------------------------- 574// Unmount - This routine will fire off a system command to unmount the 575// given device. Returns FSUR_IO_SUCCESS if everything works, 576// else FSUR_IO_FAIL. 577// 578// theDeviceNamePtr - pointer to the device name (full path, like /dev/disk1s2). 579//----------------------------------------------------------------------------- 580 581 582int 583Unmount ( const char * theMountPointPtr ) 584{ 585 586 int result; 587 int mountflags = 0; 588 589 result = unmount ( theMountPointPtr, mountflags ); 590 require_action ( ( result == 0 ), Exit, result = FSUR_IO_FAIL ); 591 592 result = FSUR_IO_SUCCESS; 593 594 595Exit: 596 597 598 return result; 599 600} 601 602 603#if 0 604#pragma mark - 605#pragma mark - Mount Code 606#pragma mark - 607#endif 608 609 610//----------------------------------------------------------------------------- 611// MountMain - returns 0 if successful 612//----------------------------------------------------------------------------- 613 614static int 615MountMain ( int argc, const char * argv[] ) 616{ 617 618 int error = 0; 619 int mountFlags = 0; 620 621 error = ParseMountArgs ( &argc, &argv, &mountFlags ); 622 require_action ( ( error == 0 ), Exit, DisplayUsage ( kUsageTypeMount, argv ) ); 623 624 error = Mount ( argv[0], argv[1], mountFlags ); 625 check ( error == FSUR_IO_SUCCESS ); 626 627 // mount_cddafs must return 0 for successful mounts 628 if ( error == FSUR_IO_SUCCESS ) 629 error = 0; 630 631Exit: 632 633 634 return error; 635 636} 637 638 639//----------------------------------------------------------------------------- 640// ParseMountArgs - Parses mount arguments 641//----------------------------------------------------------------------------- 642 643int 644ParseMountArgs ( int * argc, const char ** argv[], int * mountFlags ) 645{ 646 647 int error = 0; 648 int ch = 0; 649 int altFlags = 0; 650 mntoptparse_t parse = NULL; 651 652 *mountFlags = 0; 653 654 // Audio CD's are read-only 655 *mountFlags |= MNT_RDONLY; 656 657 // Must have at least 3 arguments and the action argument must start with a '-' 658 require_action ( ( *argc > 2 ), Exit, error = 1 ); 659 660 // Check command line args 661 while ( ( ch = getopt ( *argc, ( char * const * ) *argv, "o:" ) ) != -1 ) 662 { 663 664 switch ( ch ) 665 { 666 667 case 'o': 668 parse = getmntopts ( optarg, gMountOptions, mountFlags, &altFlags ); 669 if ( parse != NULL ) 670 { 671 freemntopts ( parse ); 672 } 673 674 else 675 { 676 error = 1; 677 } 678 break; 679 680 default: 681 error = 1; 682 break; 683 684 } 685 686 } 687 688 *argc -= optind; 689 *argv += optind; 690 691 692Exit: 693 694 695 return error; 696 697} 698 699 700//----------------------------------------------------------------------------- 701// WriteDiskLabel - This routine will create a file system info file that 702// is used by autodiskmount. After creating the file it will 703// write whatever contentsPtr points to the new file. 704// 705// We end up with a file something like: 706// /usr/filesystems/cddafs.fs/cddafs.name 707// 708// when our file system name is "cddafs" and suffixPtr points 709// to ".name" or ".label" 710//----------------------------------------------------------------------------- 711 712void 713WriteDiskLabel ( char * contentsPtr ) 714{ 715 716 StripTrailingSpaces ( contentsPtr ); 717 write ( STDOUT_FILENO, contentsPtr, strlen ( contentsPtr ) ); 718 719} 720 721 722//----------------------------------------------------------------------------- 723// StripTrailingSpaces - Strips trailing white spaces from character array 724//----------------------------------------------------------------------------- 725 726void 727StripTrailingSpaces ( char * theContentsPtr ) 728{ 729 730 check ( theContentsPtr ); 731 check ( strlen ( theContentsPtr ) > 0 ); 732 733 if ( strlen ( theContentsPtr ) > 0 ) 734 { 735 736 char *myPtr; 737 738 myPtr = theContentsPtr + strlen ( theContentsPtr ) - 1; 739 while ( *myPtr == kASCIISpace && myPtr >= theContentsPtr ) 740 { 741 742 *myPtr = 0x00; 743 myPtr--; 744 745 } 746 747 } 748 749} 750 751 752//----------------------------------------------------------------------------- 753// Mount - Attempts to mount on our filesystem if possible 754//----------------------------------------------------------------------------- 755 756int 757Mount ( const char * deviceNamePtr, 758 const char * mountPointPtr, 759 int mountFlags ) 760{ 761 762 AppleCDDAArguments args = { 0 }; 763 struct vfsconf vfc = { 0 }; 764 int result = FSUR_IO_FAIL; 765 int error = 0; 766 CFDataRef nameDataRef = NULL; 767 CFDataRef xmlDataRef = NULL; 768 QTOCDataFormat10Ptr TOCDataPtr = NULL; 769 UInt8 * xmlDataPtr = NULL; 770 UInt8 * nameDataPtr = NULL; 771 char realMountPoint[PATH_MAX]; 772 char * realMountPointPtr; 773 774 DebugLog ( ( "Mount('%s','%s')\n", deviceNamePtr, mountPointPtr ) ); 775 776 require ( ( mountPointPtr != NULL ), Exit ); 777 require ( ( *mountPointPtr != '\0' ), Exit ); 778 779 args.device = ( char * ) deviceNamePtr; 780 args.fileType = 0x41494643; // 'AIFC' 781 args.fileCreator = 0x3F3F3F3F; // '????' 782 783 784 // Check if we're loaded into vfs or not. 785 error = getvfsbyname ( gAppleCDDAName, &vfc ); 786 if ( error != 0 ) 787 { 788 // Kernel extension wasn't loaded, so try to load it... 789 error = LoadKernelExtension ( ); 790 require ( ( error == 0 ), Exit ); 791 792 // Now try again since we loaded our extension 793 error = getvfsbyname ( gAppleCDDAName, &vfc ); 794 require ( ( error == 0 ), Exit ); 795 796 } 797 798 TOCDataPtr = ( QTOCDataFormat10Ptr ) GetTOCDataPtr ( deviceNamePtr ); 799 require ( ( TOCDataPtr != NULL ), Exit ); 800 801 nameDataRef = GetTrackData ( deviceNamePtr, TOCDataPtr ); 802 require ( ( nameDataRef != NULL ), ReleaseTOCData ); 803 804 // Get the number of audio tracks 805 args.numTracks = FindNumberOfAudioTracks ( TOCDataPtr ); 806 807 // Build the XML file ".TOC.plist" 808 xmlDataRef = CreateXMLFileInPListFormat ( TOCDataPtr ); 809 require ( ( xmlDataRef != NULL ), ReleaseNameData ); 810 811 // Get the pointers. 812 nameDataPtr = ( UInt8 * ) CFDataGetBytePtr ( nameDataRef ); 813 xmlDataPtr = ( UInt8 * ) CFDataGetBytePtr ( xmlDataRef ); 814 815 args.nameData = ( user_addr_t ) nameDataPtr; 816 args.nameDataSize = ( uint32_t ) CFDataGetLength ( nameDataRef ); 817 args.xmlData = ( user_addr_t ) xmlDataPtr; 818 args.xmlFileSize = ( uint32_t ) CFDataGetLength ( xmlDataRef ); 819 820#if ( DEBUG_LEVEL > 3 ) 821 { 822 UInt32 count = 0; 823 824 for ( ; count < args.xmlFileSize; count = count + 8 ) 825 { 826 827 DebugLog ( ("%02x:%02x:%02x:%02x %02x:%02x:%02x:%02x\n", 828 xmlDataPtr[count], 829 xmlDataPtr[count+1], 830 xmlDataPtr[count+2], 831 xmlDataPtr[count+3], 832 xmlDataPtr[count+4], 833 xmlDataPtr[count+5], 834 xmlDataPtr[count+6], 835 xmlDataPtr[count+7] ) ); 836 837 } 838 839 DebugLog ( ( "\n" ) ); 840 DebugLog ( ( "XML File Size = %d\n", ( int ) args.xmlFileSize ) ); 841 842 } 843#endif 844 845 // Print out the device name for debug purposes 846 DebugLog ( ( "DeviceName = %s\n", deviceNamePtr ) ); 847 DebugLog ( ( "numTracks = %d\n", ( int ) args.numTracks ) ); 848 849 require ( ( args.nameData != 0 ), ReleaseXMLData ); 850 require ( ( args.nameDataSize != 0 ), ReleaseXMLData ); 851 require ( ( args.xmlData != 0 ), ReleaseXMLData ); 852 853 DebugLog ( ( "args.nameData = %qx\n", args.nameData ) ); 854 DebugLog ( ( "args.xmlData = %qx\n", args.xmlData ) ); 855 DebugLog ( ( "sizeof(args) = %ld\n", sizeof ( args ) ) ); 856 857 // Obtain the real path. 858 realMountPointPtr = realpath ( mountPointPtr, realMountPoint ); 859 require ( ( realMountPointPtr != NULL ), ReleaseXMLData ); 860 861 // Issue the system mount command 862 result = mount ( vfc.vfc_name, realMountPoint, mountFlags, &args ); 863 require ( ( result == 0 ), ReleaseXMLData ); 864 865 result = FSUR_IO_SUCCESS; 866 867 868ReleaseXMLData: 869 870 871 CFRelease ( xmlDataRef ); 872 xmlDataRef = NULL; 873 874 875ReleaseNameData: 876 877 878 CFRelease ( nameDataRef ); 879 nameDataRef = NULL; 880 881 882ReleaseTOCData: 883 884 885 // free the memory 886 require_quiet ( ( TOCDataPtr != NULL ), Exit ); 887 free ( ( char * ) TOCDataPtr ); 888 TOCDataPtr = NULL; 889 890 891Exit: 892 893 894 return result; 895 896} 897 898 899//----------------------------------------------------------------------------- 900// ParseTOC - Parses the TOC to find audio tracks. If it finds one or more 901// audio tracks, it returns FSUR_RECOGNIZED, 902// else FSUR_UNRECOGNIZED 903// 904//----------------------------------------------------------------------------- 905 906int 907ParseTOC ( UInt8 * TOCInfoPtr ) 908{ 909 910 int result = FSUR_UNRECOGNIZED; 911 int error = 0; 912 QTOCDataFormat10Ptr TOCDataPtr = NULL; 913 UInt8 index = 0; 914 UInt8 numberOfDescriptors = 0; 915 916 require ( ( TOCInfoPtr != NULL ), Exit ); 917 918 // Set our pointer to the TOCInfoPtr 919 TOCDataPtr = ( QTOCDataFormat10Ptr ) TOCInfoPtr; 920 921 error = GetNumberOfTrackDescriptors ( TOCDataPtr, &numberOfDescriptors ); 922 require_quiet ( ( error == 0 ), Exit ); 923 924 for ( index = 0; index < numberOfDescriptors; index++ ) 925 { 926 927 if ( IsAudioTrack ( index, TOCDataPtr ) ) 928 { 929 930 // Found an audio cd 931 return FSUR_RECOGNIZED; 932 933 } 934 935 } 936 937 938Exit: 939 940 941 return result; 942 943} 944 945 946//----------------------------------------------------------------------------- 947// GetTrackData - Loads databases and calls them for Track Name info. 948//----------------------------------------------------------------------------- 949 950CFDataRef 951GetTrackData ( const char * bsdDevNode, 952 const QTOCDataFormat10Ptr TOCData ) 953{ 954 955 CFMutableDataRef data = 0; 956 CFStringRef trackString = 0; 957 UInt8 numTracks = 0; 958 UInt32 trackIndex = 0; 959 UInt8 currentTrack = 0; 960 SInt32 error = 0; 961 CDDATrackName * database = NULL; 962 963 data = CFDataCreateMutable ( kCFAllocatorDefault, 0 ); 964 965 database = new CDDATrackName; 966 967 database->Init ( bsdDevNode, TOCData ); 968 969 error = GetNumberOfTrackDescriptors ( ( QTOCDataFormat10Ptr ) TOCData, &numTracks ); 970 if ( error != 0 ) 971 { 972 973 DebugLog ( ( "Error = %d on GetNumberOfTrackDescriptors\n", ( int ) error ) ); 974 exit ( 1 ); 975 976 } 977 978 for ( trackIndex = 0; trackIndex < numTracks; trackIndex++ ) 979 { 980 981 if ( IsAudioTrack ( trackIndex, TOCData ) == false ) 982 continue; 983 984 currentTrack = GetPointValue ( trackIndex, TOCData ); 985 trackString = ( database )->GetTrackName ( currentTrack ); 986 987 if ( trackString != 0 ) 988 { 989 990 UInt8 size = 0; 991 UInt8 suffixSize = 0; 992 UInt8 prefixSize = 2; 993 UInt8 bufferSize = 0; 994 UInt8 offset = 0; 995 Boolean success = false; 996 char * buffer = NULL; 997 char prefix[kMaxPrefixSize]; 998 999 if ( currentTrack > 9 ) 1000 { 1001 prefixSize++; 1002 prefix[offset++] = currentTrack / 10 + kASCIINumberZero; 1003 } 1004 1005 prefix[offset++] = currentTrack % 10 + kASCIINumberZero; 1006 prefix[offset] = kASCIISpace; 1007 1008 suffixSize = strlen ( gFileSuffix ); 1009 bufferSize = MAXNAMLEN - prefixSize - suffixSize - 1; 1010 1011 buffer = ( char * ) calloc ( 1, bufferSize ); 1012 1013 success = _CFStringGetFileSystemRepresentation ( trackString, 1014 ( UInt8 * ) buffer, 1015 bufferSize ); 1016 1017 buffer[bufferSize - 1] = 0; 1018 size = strlen ( buffer ) + prefixSize + suffixSize; 1019 1020 DebugLog ( ( "size = %d\n", size ) ); 1021 DebugLog ( ( "buffer = %s\n", buffer ) ); 1022 1023 // Add the track number to the data object 1024 CFDataAppendBytes ( data, 1025 ¤tTrack, 1026 1 ); 1027 1028 // Add the size to the data object 1029 CFDataAppendBytes ( data, 1030 &size, 1031 1 ); 1032 1033 // Add the prefix to the data object 1034 CFDataAppendBytes ( data, 1035 ( UInt8 * ) prefix, 1036 prefixSize ); 1037 1038 // add the string to the data object 1039 CFDataAppendBytes ( data, 1040 ( UInt8 * ) buffer, 1041 strlen ( buffer ) ); 1042 1043 // add the suffix to the data object 1044 CFDataAppendBytes ( data, 1045 ( UInt8 * ) gFileSuffix, 1046 suffixSize ); 1047 1048 free ( buffer ); 1049 1050 // release it 1051 CFRelease ( trackString ); 1052 1053 } 1054 1055 } 1056 1057 if ( database != NULL ) 1058 { 1059 1060 delete database; 1061 database = NULL; 1062 1063 } 1064 1065 return data; 1066 1067} 1068 1069 1070//----------------------------------------------------------------------------- 1071// LoadKernelExtension - Loads our filesystem kernel extension. 1072//----------------------------------------------------------------------------- 1073 1074int 1075LoadKernelExtension ( void ) 1076{ 1077 1078 int pid; 1079 int result = -1; 1080 union wait status; 1081 1082 pid = fork ( ); 1083 1084 if ( pid == 0 ) 1085 { 1086 1087 result = execl ( kLoadCommand, kLoadCommand, 1088 kCDDAFileSystemExtensionPath, NULL ); 1089 1090 // We can only get here if the exec failed 1091 goto Exit; 1092 1093 } 1094 1095 if ( pid == -1 ) 1096 { 1097 1098 // fork() didn't work, so we grab the error from errno 1099 // to return as our error 1100 result = errno; 1101 goto Exit; 1102 1103 } 1104 1105 // Success! 1106 if ( ( wait4 ( pid, ( int * ) &status, 0, NULL ) == pid ) && 1107 ( WIFEXITED ( status ) ) ) 1108 { 1109 1110 // Stuff the status return code into our result 1111 result = status.w_retcode; 1112 1113 } 1114 1115 else 1116 { 1117 1118 // else return -1 1119 result = -1; 1120 1121 } 1122 1123 1124 check ( result == 0 ); 1125 1126 1127Exit: 1128 1129 1130 return result; 1131 1132} 1133 1134 1135//----------------------------------------------------------------------------- 1136// CreateXMLFileInPListFormat - Makes a plist-style XML file which has a 1137// parsed TOC. This makes it easy for 1138// applications to get TOC info without having 1139// to deal with the IOKit registry. 1140// 1141// TOCDataPtr - pointer to a QTOCDataFormat10 structure 1142//----------------------------------------------------------------------------- 1143 1144CFDataRef 1145CreateXMLFileInPListFormat ( QTOCDataFormat10Ptr TOCDataPtr ) 1146{ 1147 1148 SubQTOCInfoPtr trackDescriptorPtr = NULL; 1149 SubQTOCInfoPtr lastTrackDescriptorPtr = NULL; 1150 UInt16 numSessions = 0; 1151 UInt16 length = 0; 1152 UInt16 numberOfDescriptors = 0; 1153 CFMutableDictionaryRef theCDDictionaryRef = 0; 1154 CFMutableArrayRef theSessionArrayRef = 0; 1155 CFDataRef theRawTOCDataRef = 0; 1156 UInt32 index = 0; 1157 CFDataRef xmlData = 0; 1158 1159 DebugLog ( ( "CreateXMLFileInPListFormat called\n" ) ); 1160 1161 if ( TOCDataPtr != NULL ) 1162 { 1163 1164 // Create the master dictionary inside which all elements go 1165 theCDDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault, 1166 0, 1167 &kCFTypeDictionaryKeyCallBacks, 1168 &kCFTypeDictionaryValueCallBacks ); 1169 1170 // Grab the length and advance 1171 length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength ); 1172 1173 // Add the Raw TOC Data 1174 theRawTOCDataRef = CFDataCreate ( kCFAllocatorDefault, 1175 ( UInt8 * ) TOCDataPtr, 1176 length + sizeof ( TOCDataPtr->TOCDataLength ) ); 1177 1178 CFDictionarySetValue ( theCDDictionaryRef, 1179 CFSTR ( kRawTOCDataString ), 1180 theRawTOCDataRef ); 1181 1182 CFRelease ( theRawTOCDataRef ); 1183 1184 length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) + 1185 sizeof ( TOCDataPtr->lastSessionNumber ) ); 1186 1187 numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) ); 1188 numSessions = TOCDataPtr->lastSessionNumber - TOCDataPtr->firstSessionNumber + 1; 1189 1190 if ( numberOfDescriptors <= 0 ) 1191 { 1192 1193 DebugLog ( ( "No tracks on this CD...\n" ) ); 1194 1195 } 1196 1197 // Create the array of sessions 1198 theSessionArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault, numSessions, &kCFTypeArrayCallBacks ); 1199 trackDescriptorPtr = TOCDataPtr->trackDescriptors; 1200 lastTrackDescriptorPtr = TOCDataPtr->trackDescriptors + numberOfDescriptors - 1; 1201 1202 for ( index = 0; trackDescriptorPtr <= lastTrackDescriptorPtr; index++ ) 1203 { 1204 1205 CFMutableDictionaryRef theSessionDictionaryRef = 0; 1206 CFMutableArrayRef theTrackArrayRef = 0; 1207 UInt32 trackIndex = 0; 1208 1209 theSessionDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault, 1210 0, 1211 &kCFTypeDictionaryKeyCallBacks, 1212 &kCFTypeDictionaryValueCallBacks ); 1213 1214 theTrackArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault, 1215 0, 1216 &kCFTypeArrayCallBacks ); 1217 1218 while ( ( trackDescriptorPtr <= lastTrackDescriptorPtr ) && 1219 ( trackDescriptorPtr->sessionNumber == ( index + 1 ) ) ) 1220 { 1221 1222 CFMutableDictionaryRef theTrackRef = 0; 1223 CFBooleanRef isDigitalData = kCFBooleanFalse; 1224 CFBooleanRef preEmphasis = kCFBooleanFalse; 1225 CFNumberRef startBlock; 1226 CFNumberRef sessionNumber; 1227 CFNumberRef point; 1228 SInt16 pointValue; 1229 UInt32 blockAddress; 1230 1231 pointValue = trackDescriptorPtr->point; 1232 1233 if ( pointValue == 0x00A0 ) 1234 { 1235 1236 CFNumberRef sessionType = 0; 1237 CFNumberRef firstTrackNum = 0; 1238 CFNumberRef sessionNumber = 0; 1239 1240 firstTrackNum = CFNumberCreate ( kCFAllocatorDefault, 1241 kCFNumberCharType, 1242 &trackDescriptorPtr->PMSF.A0PMSF.firstTrackNum ); 1243 1244 sessionType = CFNumberCreate ( kCFAllocatorDefault, 1245 kCFNumberCharType, 1246 &trackDescriptorPtr->PMSF.A0PMSF.discType ); 1247 1248 sessionNumber = CFNumberCreate ( kCFAllocatorDefault, 1249 kCFNumberCharType, 1250 &trackDescriptorPtr->sessionNumber ); 1251 1252 CFDictionarySetValue ( theSessionDictionaryRef, 1253 CFSTR ( kFirstTrackInSessionString ), 1254 firstTrackNum ); 1255 1256 CFDictionarySetValue ( theSessionDictionaryRef, 1257 CFSTR ( kSessionTypeString ), 1258 sessionType ); 1259 1260 CFDictionarySetValue ( theSessionDictionaryRef, 1261 CFSTR ( kSessionNumberString ), 1262 sessionNumber ); 1263 1264 CFRelease ( firstTrackNum ); 1265 CFRelease ( sessionType ); 1266 CFRelease ( sessionNumber ); 1267 1268 goto nextIteration; 1269 1270 } 1271 1272 if ( pointValue == 0x00A1 ) 1273 { 1274 1275 CFNumberRef lastTrackNum = 0; 1276 1277 lastTrackNum = CFNumberCreate ( kCFAllocatorDefault, 1278 kCFNumberCharType, 1279 &trackDescriptorPtr->PMSF.A1PMSF.lastTrackNum ); 1280 1281 CFDictionarySetValue ( theSessionDictionaryRef, 1282 CFSTR ( kLastTrackInSessionString ), 1283 lastTrackNum ); 1284 1285 CFRelease ( lastTrackNum ); 1286 1287 goto nextIteration; 1288 1289 } 1290 1291 if ( pointValue == 0x00A2 ) 1292 { 1293 1294 CFNumberRef leadoutBlock = 0; 1295 UInt32 blockAddress = 0; 1296 1297 blockAddress = ( ( trackDescriptorPtr->PMSF.leadOutStartPosition.minutes * 60 ) + 1298 trackDescriptorPtr->PMSF.leadOutStartPosition.seconds ) * 75 + 1299 trackDescriptorPtr->PMSF.leadOutStartPosition.frames; 1300 1301 leadoutBlock = CFNumberCreate ( kCFAllocatorDefault, 1302 kCFNumberIntType, 1303 &blockAddress ); 1304 1305 CFDictionarySetValue ( theSessionDictionaryRef, 1306 CFSTR ( kLeadoutBlockString ), 1307 leadoutBlock ); 1308 1309 CFRelease ( leadoutBlock ); 1310 1311 goto nextIteration; 1312 1313 } 1314 1315 if ( pointValue > 0x63 ) 1316 { 1317 1318 // Skip the B0-C1 identifiers 1319 goto nextIteration; 1320 1321 } 1322 1323 1324 theTrackRef = CFDictionaryCreateMutable ( kCFAllocatorDefault, 1325 0, 1326 &kCFTypeDictionaryKeyCallBacks, 1327 &kCFTypeDictionaryValueCallBacks ); 1328 1329 point = CFNumberCreate ( kCFAllocatorDefault, 1330 kCFNumberSInt16Type, 1331 &pointValue ); 1332 1333 CFDictionarySetValue ( theTrackRef, 1334 CFSTR ( kPointString ), 1335 point ); 1336 1337 CFRelease ( point ); 1338 1339 1340 blockAddress = ( ( trackDescriptorPtr->PMSF.startPosition.minutes * 60 ) + 1341 trackDescriptorPtr->PMSF.startPosition.seconds ) * 75 + 1342 trackDescriptorPtr->PMSF.startPosition.frames; 1343 1344 DebugLog ( ( "track = %d, blockAddress = %d\n", pointValue, ( int ) blockAddress ) ); 1345 1346 startBlock = CFNumberCreate ( kCFAllocatorDefault, 1347 kCFNumberSInt32Type, 1348 &blockAddress ); 1349 1350 CFDictionarySetValue ( theTrackRef, 1351 CFSTR ( kStartBlockString ), 1352 startBlock ); 1353 1354 CFRelease ( startBlock ); 1355 1356 sessionNumber = CFNumberCreate ( kCFAllocatorDefault, 1357 kCFNumberCharType, 1358 &trackDescriptorPtr->sessionNumber ); 1359 1360 CFDictionarySetValue ( theTrackRef, 1361 CFSTR ( kSessionNumberString ), 1362 sessionNumber ); 1363 1364 CFRelease ( sessionNumber ); 1365 1366 if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == kDigitalDataMask ) 1367 { 1368 1369 isDigitalData = kCFBooleanTrue; 1370 1371 } 1372 1373 CFDictionarySetValue ( theTrackRef, 1374 CFSTR ( kDataString ), 1375 isDigitalData ); 1376 1377 if ( ( trackDescriptorPtr->control & kPreEmphasisMask ) == kPreEmphasisMask ) 1378 { 1379 1380 preEmphasis = kCFBooleanTrue; 1381 1382 } 1383 1384 CFDictionarySetValue ( theTrackRef, 1385 CFSTR ( kPreEmphasisString ), 1386 preEmphasis ); 1387 1388 // Add the dictionary to the array 1389 CFArraySetValueAtIndex ( theTrackArrayRef, trackIndex, theTrackRef ); 1390 1391 CFRelease ( theTrackRef ); 1392 trackIndex++; 1393 1394 1395nextIteration: 1396 1397 1398 // Advance to next track 1399 trackDescriptorPtr++; 1400 1401 } 1402 1403 // Set the array inside of the dictionary for the session 1404 CFDictionarySetValue ( theSessionDictionaryRef, CFSTR ( kTrackArrayString ), theTrackArrayRef ); 1405 CFArraySetValueAtIndex ( theSessionArrayRef, index, theSessionDictionaryRef ); 1406 1407 CFRelease ( theSessionDictionaryRef ); 1408 CFRelease ( theTrackArrayRef ); 1409 1410 } 1411 1412 CFDictionarySetValue ( theCDDictionaryRef, CFSTR ( kSessionsString ), theSessionArrayRef ); 1413 1414 CFRelease ( theSessionArrayRef ); 1415 1416 xmlData = CFPropertyListCreateXMLData ( kCFAllocatorDefault, theCDDictionaryRef ); 1417 1418 CFRelease ( theCDDictionaryRef ); 1419 1420 } 1421 1422 return xmlData; 1423 1424} 1425 1426 1427#if 0 1428#pragma mark - 1429#pragma mark - Shared Code 1430#pragma mark - 1431#endif 1432 1433 1434//----------------------------------------------------------------------------- 1435// DisplayUsage - This routine will do a printf of the correct usage 1436// for whichever utility was launched. 1437//----------------------------------------------------------------------------- 1438 1439void 1440DisplayUsage ( int usageType, const char * argv[] ) 1441{ 1442 1443 if ( usageType == kUsageTypeMount ) 1444 { 1445 1446 printf ( "usage: mount_cddafs [-o options] device-name mount-point\n" ); 1447 1448 } 1449 1450 else if ( usageType == kUsageTypeUtility ) 1451 { 1452 1453 printf ( "usage: %s action_arg device_arg [mount_point_arg] [Flags] \n", argv[0] ); 1454 printf ( "action_arg:\n" ); 1455 printf ( " -%c (Probe for mounting)\n", FSUC_PROBE ); 1456 printf ( " -%c (Mount)\n", FSUC_MOUNT ); 1457 printf ( " -%c (Unmount)\n", FSUC_UNMOUNT ); 1458 printf ( " -%c (Force Mount)\n", FSUC_MOUNT_FORCE ); 1459 printf ( "device_arg:\n" ); 1460 printf ( " device we are acting upon (for example, 'sd2')\n" ); 1461 printf ( "mount_point_arg:\n" ); 1462 printf ( " required for Mount and Force Mount \n" ); 1463 printf ( "Flags:\n" ); 1464 printf ( " required for Mount, Force Mount and Probe\n" ); 1465 printf ( " indicates removable or fixed (for example 'fixed')\n" ); 1466 printf ( " indicates readonly or writable (for example 'readonly')\n" ); 1467 printf ( "Examples:\n"); 1468 printf ( " %s -p sd2 fixed writable\n", argv[0] ); 1469 printf ( " %s -m sd2 /my/hfs removable readonly\n", argv[0] ); 1470 1471 } 1472 1473 return; 1474 1475} 1476 1477 1478//----------------------------------------------------------------------------- 1479// GetTOCDataPtr - Gets a pointer to the TOCData 1480// 1481// deviceNamePtr - pointer to the device name (full path, like /dev/rdisk1) 1482//----------------------------------------------------------------------------- 1483 1484UInt8 * 1485GetTOCDataPtr ( const char * deviceNamePtr ) 1486{ 1487 1488 UInt8 * ptr = NULL; 1489 IOReturn error = 0; 1490 io_iterator_t iterator = MACH_PORT_NULL; 1491 io_registry_entry_t registryEntry = MACH_PORT_NULL; 1492 CFMutableDictionaryRef properties = 0; 1493 CFDataRef data = 0; 1494 char * bsdName = NULL; 1495 1496 if ( !strncmp ( deviceNamePtr, "/dev/r", 6 ) ) 1497 { 1498 1499 // Strip off the /dev/ from /dev/rdiskX 1500 bsdName = ( char * ) &deviceNamePtr[6]; 1501 1502 } 1503 1504 else if ( !strncmp ( deviceNamePtr, "/dev/", 5 ) ) 1505 { 1506 1507 // Strip off the /dev/ from /dev/diskX 1508 bsdName = ( char * ) &deviceNamePtr[5]; 1509 1510 } 1511 1512 else 1513 { 1514 1515 DebugLog ( ( "GetTOCDataPtr: ERROR: not /dev/something...\n" ) ); 1516 goto Exit; 1517 1518 } 1519 1520 error = IOServiceGetMatchingServices ( kIOMasterPortDefault, 1521 IOBSDNameMatching ( kIOMasterPortDefault, 0, bsdName ), 1522 &iterator ); 1523 require ( ( error == kIOReturnSuccess ), Exit ); 1524 1525 // Only expect one entry since there is a 1:1 correspondence between bsd names 1526 // and IOKit storage objects 1527 registryEntry = IOIteratorNext ( iterator ); 1528 require ( ( registryEntry != MACH_PORT_NULL ), ReleaseIterator ); 1529 1530 require ( IOObjectConformsTo ( registryEntry, kIOCDMediaString ), ReleaseEntry ); 1531 1532 error = IORegistryEntryCreateCFProperties ( registryEntry, 1533 &properties, 1534 kCFAllocatorDefault, 1535 kNilOptions ); 1536 require ( ( error == kIOReturnSuccess ), ReleaseEntry ); 1537 1538 // Get the TOCInfo 1539 data = ( CFDataRef ) CFDictionaryGetValue ( properties, 1540 CFSTR ( kIOCDMediaTOCKey ) ); 1541 if ( data != NULL ) 1542 { 1543 1544 ptr = CreateBufferFromCFData ( data ); 1545 1546 } 1547 1548 // Release the properties 1549 CFRelease ( properties ); 1550 1551 1552ReleaseEntry: 1553 1554 1555 // release the object 1556 error = IOObjectRelease ( registryEntry ); 1557 1558 1559ReleaseIterator: 1560 1561 1562 // relese the iterator 1563 error = IOObjectRelease ( iterator ); 1564 1565 1566Exit: 1567 1568 1569 return ptr; 1570 1571} 1572 1573 1574//----------------------------------------------------------------------------- 1575// IsAudioTrack - Figures out if a track is audio or not. 1576//----------------------------------------------------------------------------- 1577 1578Boolean 1579IsAudioTrack ( UInt32 trackNumber, QTOCDataFormat10Ptr TOCData ) 1580{ 1581 1582 SubQTOCInfoPtr trackDescriptorPtr; 1583 1584 trackDescriptorPtr = TOCData->trackDescriptors; 1585 trackDescriptorPtr = trackDescriptorPtr + trackNumber; 1586 1587 if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 ) 1588 { 1589 1590 if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 ) 1591 { 1592 1593 // Found an audio track 1594 return true; 1595 1596 } 1597 1598 } 1599 1600 return false; 1601 1602} 1603 1604 1605//----------------------------------------------------------------------------- 1606// GetNumberOfTrackDescriptors - Gets the number of track descriptors 1607//----------------------------------------------------------------------------- 1608 1609SInt32 1610GetNumberOfTrackDescriptors ( QTOCDataFormat10Ptr TOCDataPtr, 1611 UInt8 * numberOfDescriptors ) 1612{ 1613 1614 UInt16 length = 0; 1615 SInt32 result = 0; 1616 1617 require_action ( ( TOCDataPtr != NULL ), Exit, result = -1 ); 1618 require_action ( ( numberOfDescriptors != NULL ), Exit, result = -1 ); 1619 1620 // Grab the length and advance 1621 length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength ); 1622 DebugLog ( ( "Length = %d\n", length ) ); 1623 1624 require_action ( ( length > sizeof ( CDTOC ) ), Exit, result = -1 ); 1625 1626 length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) + 1627 sizeof ( TOCDataPtr->lastSessionNumber ) ); 1628 1629 *numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) ); 1630 DebugLog ( ( "Number of descriptors = %d\n", *numberOfDescriptors ) ); 1631 1632 1633Exit: 1634 1635 1636 return result; 1637 1638} 1639 1640 1641//----------------------------------------------------------------------------- 1642// GetPointValue - Gets the track's point value 1643//----------------------------------------------------------------------------- 1644 1645UInt8 1646GetPointValue ( UInt32 trackIndex, QTOCDataFormat10Ptr TOCData ) 1647{ 1648 1649 SubQTOCInfoPtr trackDescriptorPtr; 1650 1651 trackDescriptorPtr = TOCData->trackDescriptors; 1652 trackDescriptorPtr = trackDescriptorPtr + trackIndex; 1653 1654 return trackDescriptorPtr->point; 1655 1656} 1657 1658 1659//----------------------------------------------------------------------------- 1660// CreateBufferFromCFData - Allocates memory for a chunk of memory and copies 1661// the contents of the CFData to it. 1662// 1663// NB: The calling function should dispose of the memory 1664//----------------------------------------------------------------------------- 1665 1666UInt8 * 1667CreateBufferFromCFData ( CFDataRef theData ) 1668{ 1669 1670 CFRange range; 1671 CFIndex bufferLength = 0; 1672 UInt8 * buffer = NULL; 1673 1674 bufferLength = CFDataGetLength ( theData ); 1675 buffer = ( UInt8 * ) malloc ( bufferLength ); 1676 1677 range = CFRangeMake ( 0, bufferLength ); 1678 1679 if ( buffer != NULL ) 1680 CFDataGetBytes ( theData, range, buffer ); 1681 1682 return buffer; 1683 1684} 1685 1686 1687//----------------------------------------------------------------------------- 1688// FindNumberOfAudioTracks - Parses the TOC to find the number of audio 1689// tracks. 1690//----------------------------------------------------------------------------- 1691 1692UInt32 1693FindNumberOfAudioTracks ( QTOCDataFormat10Ptr TOCDataPtr ) 1694{ 1695 1696 UInt32 result = 0; 1697 SubQTOCInfoPtr trackDescriptorPtr = NULL; 1698 UInt16 length = 0; 1699 UInt16 numberOfDescriptors = 0; 1700 1701 DebugLog ( ( "FindNumberOfAudioTracks called\n" ) ); 1702 1703 require ( ( TOCDataPtr != NULL ), Exit ); 1704 1705 // Grab the length and advance 1706 length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength ); 1707 require ( ( length > sizeof ( CDTOC ) ), Exit ); 1708 1709 length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) + 1710 sizeof ( TOCDataPtr->lastSessionNumber ) ); 1711 1712 numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) ); 1713 require ( ( numberOfDescriptors != 0 ), Exit ); 1714 1715 DebugLog ( ( "numberOfDescriptors = %d\n", numberOfDescriptors ) ); 1716 1717 trackDescriptorPtr = TOCDataPtr->trackDescriptors; 1718 1719 while ( numberOfDescriptors > 0 ) 1720 { 1721 1722 if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 ) 1723 { 1724 1725 if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 ) 1726 { 1727 1728 // Found an audio track 1729 result++; 1730 1731 } 1732 1733 } 1734 1735 trackDescriptorPtr++; 1736 numberOfDescriptors--; 1737 1738 } 1739 1740 1741Exit: 1742 1743 1744 DebugLog ( ( "numberOfTracks = %d\n", ( int ) result ) ); 1745 1746 return result; 1747 1748} 1749 1750 1751//----------------------------------------------------------------------------- 1752// End Of File 1753//----------------------------------------------------------------------------- 1754