#include <servers/netname.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sysctl.h>
#include <dev/disk.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <mach/mach_init.h>
#include <sys/loadable_fs.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <dirent.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include "cddafs_util.h"
#include "mntopts.h"
#include "AppleCDDAFileSystemDefines.h"
#define DISK_ARB_COMPATIBILITY_MODE 0
#define DEBUG 0
#if DEBUG
#define DebugLog(x) printf x
#else
#define DebugLog(x)
#endif
static int
UtilityMain ( int argc, const char * argv[] );
static int
MountMain ( int argc, const char * argv[] );
static CFDataRef
GetTrackData ( const char * bsdDevNode,
const QTOCDataFormat10Ptr TOCData );
struct mntopt gMountOptions[] =
{
MOPT_STDOPTS,
{ NULL }
};
static char gAppleCDDAName[MFSNAMELEN] = "cddafs";
int
main ( int argc, const char * argv[] )
{
int result = -1;
#if DEBUG
int index = 0;
for ( index = 0; index < argc; index++ )
{
printf ( "[%d] = %s\n", index, argv[index] );
}
#endif
if ( strcmp ( argv[0], kUtilExecutableName ) == 0 )
{
result = UtilityMain ( argc, argv );
}
else
{
result = MountMain ( argc, argv );
}
return result;
}
#if 0
#pragma mark -
#pragma mark - Utility Code
#pragma mark -
#endif
static int
UtilityMain ( int argc, const char * argv[] )
{
char rawDeviceName[MAXPATHLEN];
char blockDeviceName[MAXPATHLEN];
const char * actionPtr = NULL;
const char * mountPointPtr = NULL;
int result = FSUR_IO_SUCCESS;
boolean_t isLocked = 0;
boolean_t isEjectable = 0;
int mountFlags = MNT_RDONLY;
result = ParseUtilityArgs ( argc, argv, &actionPtr, &mountPointPtr, &isEjectable, &isLocked );
if ( result != 0 )
{
goto Exit;
}
sprintf ( rawDeviceName, "/dev/r%s", argv[2] );
sprintf ( blockDeviceName, "/dev/%s", argv[2] );
result = seteuid ( 0 );
if ( result )
{
DebugLog ( ( "cddafs.util: ERROR: seteuid(0): %s\n", strerror ( errno ) ) );
result = FSUR_INVAL;
goto Exit;
}
result = setegid ( 0 );
if ( result )
{
DebugLog ( ( "cddafs.util: ERROR: setegid: %s\n", strerror ( errno ) ) );
}
DebugLog ( ( "Entering the switch with action = %s\n", actionPtr ) );
switch ( *actionPtr )
{
case FSUC_PROBE:
result = Probe ( rawDeviceName );
break;
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
result = Mount ( blockDeviceName, mountPointPtr, mountFlags );
break;
case FSUC_UNMOUNT:
result = Unmount ( mountPointPtr );
break;
default:
DisplayUsage ( kUsageTypeUtility, argv );
result = FSUR_INVAL;
break;
}
Exit:
DebugLog ( ( "cddafs.util: EXIT: %d = ", result ) );
switch ( result )
{
case FSUR_LOADERR:
DebugLog ( ( "FSUR_LOADERR\n" ) );
break;
case FSUR_INVAL:
DebugLog ( ( "FSUR_INVAL\n" ) );
break;
case FSUR_IO_SUCCESS:
DebugLog ( ( "FSUR_IO_SUCCESS\n" ) );
break;
case FSUR_IO_FAIL:
DebugLog ( ( "FSUR_IO_FAIL\n" ) );
break;
case FSUR_RECOGNIZED:
DebugLog ( ( "FSUR_RECOGNIZED\n" ) );
break;
case FSUR_MOUNT_HIDDEN:
DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) );
break;
case FSUR_UNRECOGNIZED:
DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) );
break;
default:
DebugLog ( ( "default\n" ) );
break;
}
exit ( result );
return result;
}
int
ParseUtilityArgs ( int argc,
const char * argv[],
const char ** actionPtr,
const char ** mountPointPtr,
boolean_t * isEjectablePtr,
boolean_t * isLockedPtr )
{
int result = FSUR_INVAL;
int deviceLength = 0;
int index = 0;
if ( ( argc < 3 ) || ( argv[1][0] != '-' ) )
{
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
}
*actionPtr = &argv[1][1];
switch ( argv[1][1] )
{
case FSUC_PROBE:
if ( argc < 5 )
{
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
}
else
{
index = 3;
}
break;
case FSUC_UNMOUNT:
*mountPointPtr = argv[3];
index = 0; break;
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
if ( argc < 6 )
{
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
}
else
{
*mountPointPtr = argv[3];
index = 4;
}
break;
default:
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
break;
}
deviceLength = strlen ( argv[2] );
if ( deviceLength < 5 )
{
DisplayUsage ( kUsageTypeUtility, argv );
goto Exit;
}
if ( index )
{
if ( !strcmp ( argv[index], "removable" ) )
{
*isEjectablePtr = 1;
}
else if ( !strcmp ( argv[index], "fixed" ) )
{
*isEjectablePtr = 0;
}
else
{
DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (removable/fixed) argv[%d]='%s'\n",
index, argv[index] ) );
}
if ( !strcmp ( argv[index + 1], "readonly" ) )
{
*isLockedPtr = 1;
}
else if ( !strcmp ( argv[index + 1], "writable" ) )
{
*isLockedPtr = 0;
}
else
{
DebugLog ( ( "cddafs.util: ERROR: unrecognized flag (readonly/writable) argv[%d]='%s'\n",
index, argv[index + 1] ) );
}
}
result = 0;
Exit:
return result;
}
int
Probe ( char * deviceNamePtr )
{
int result = FSUR_UNRECOGNIZED;
UInt8 * ptr = NULL;
DebugLog ( ( "ENTER: Probe('%s')\n", deviceNamePtr ) );
ptr = GetTOCDataPtr ( deviceNamePtr );
if ( ptr != NULL )
{
result = ParseTOC ( ptr );
}
else
{
DebugLog ( ( "GetTOCDataPtr returned NULL.\n" ) );
}
if ( result == FSUR_RECOGNIZED )
{
CFStringRef albumName = 0;
UInt8 albumNameSize = 0;
CDDATrackName * database = NULL;
char name[2048];
database = new CDDATrackName;
if ( database != NULL )
{
DebugLog ( ( "database != NULL\n" ) );
database->Init ( deviceNamePtr, ptr );
DebugLog ( ( "Init called\n" ) );
albumName = database->GetAlbumName ( );
DebugLog ( ( "GetAlbumName called\n" ) );
}
#if DEBUG
CFShow ( albumName );
#endif
if ( albumName != 0 )
{
albumNameSize = CFStringGetLength ( albumName );
}
if ( ( albumNameSize < MAXNAMLEN ) && ( albumNameSize != 0 ) )
{
Boolean result;
result = CFStringGetCString ( albumName, name, sizeof ( name ), kCFStringEncodingUTF8 );
if ( result == true )
{
WriteDiskLabel ( name );
}
else
{
WriteDiskLabel ( kMountPointName );
}
}
else
{
WriteDiskLabel ( kMountPointName );
}
if ( albumName != 0 )
{
CFRelease ( albumName );
}
if ( database != NULL )
{
delete database;
database = NULL;
}
}
if ( ptr != NULL )
{
free ( ptr );
ptr = NULL;
}
DebugLog ( ( "Probe: returns " ) );
switch ( result )
{
case FSUR_IO_FAIL:
DebugLog ( ( "FSUR_IO_FAIL\n" ) );
break;
case FSUR_RECOGNIZED:
DebugLog ( ( "FSUR_RECOGNIZED\n" ) );
break;
case FSUR_MOUNT_HIDDEN:
DebugLog ( ( "FSUR_MOUNT_HIDDEN\n" ) );
break;
case FSUR_UNRECOGNIZED:
DebugLog ( ( "FSUR_UNRECOGNIZED\n" ) );
break;
default:
DebugLog ( ( "default\n" ) );
break;
}
return result;
}
int
Unmount ( const char * theMountPointPtr )
{
int result;
int mountflags = 0;
result = unmount ( theMountPointPtr, mountflags );
if ( result != 0 )
{
result = FSUR_IO_FAIL;
DebugLog ( ( "cddafs.util: ERROR: Unmount('%s') returned %d\n", theMountPointPtr, result ) );
}
else
{
result = FSUR_IO_SUCCESS;
}
return result;
}
#if 0
#pragma mark -
#pragma mark - Mount Code
#pragma mark -
#endif
static int
MountMain ( int argc, const char * argv[] )
{
int error = 0;
int mountFlags = 0;
error = ParseMountArgs ( &argc, &argv, &mountFlags );
if ( error != 0 )
{
DisplayUsage ( kUsageTypeMount, argv );
goto Exit;
}
error = Mount ( argv[0], argv[1], mountFlags );
Exit:
return error;
}
int
ParseMountArgs ( int * argc, const char ** argv[], int * mountFlags )
{
int error = 0;
int ch;
*mountFlags = 0;
*mountFlags |= MNT_RDONLY;
if ( *argc < 3 )
{
error = -1;
goto Exit;
}
while ( ( ch = getopt ( *argc, ( char * const * ) *argv, "o:" ) ) != -1 )
{
switch ( ch )
{
case 'o':
getmntopts ( optarg, gMountOptions, mountFlags, 0 );
break;
default:
error = 1;
break;
}
}
*argc -= optind;
*argv += optind;
Exit:
return error;
}
void
WriteDiskLabel ( char * contentsPtr )
{
#if DISK_ARB_COMPATIBILITY_MODE
int fileToWrite;
#endif
StripTrailingSpaces ( contentsPtr );
write ( 1, contentsPtr, strlen ( contentsPtr ) );
#if DISK_ARB_COMPATIBILITY_MODE
for ( fileToWrite = 0; fileToWrite < 2; fileToWrite++ )
{
char fileName[MAXPATHLEN];
int fd;
sprintf ( &fileName[0], "%s/%s%s/%s", FS_DIR_LOCATION, kCDDAFileSystemName,
FS_DIR_SUFFIX, kCDDAFileSystemName );
if ( fileToWrite == 0 )
strcat ( &fileName[0], FS_NAME_SUFFIX );
else
strcat ( &fileName[0], FS_LABEL_SUFFIX );
unlink ( &fileName[0] );
int oldMask = umask ( 0 );
fd = open ( &fileName[0], O_CREAT | O_TRUNC | O_WRONLY, 0644 );
umask ( oldMask );
if ( fd > 0 )
{
write ( fd, contentsPtr, strlen ( contentsPtr ) );
close ( fd );
}
else
{
perror ( fileName );
}
}
#endif
return;
}
void
StripTrailingSpaces ( char * theContentsPtr )
{
if ( strlen ( theContentsPtr ) )
{
char *myPtr;
myPtr = theContentsPtr + strlen( theContentsPtr ) - 1;
while ( *myPtr == ' ' && myPtr >= theContentsPtr )
{
*myPtr = 0x00;
myPtr--;
}
}
}
int
Mount ( const char * deviceNamePtr,
const char * mountPointPtr,
int mountFlags )
{
AppleCDDAArguments args;
struct vfsconf vfc;
int result;
int error = 0;
QTOCDataFormat10Ptr TOCDataPtr = NULL;
UInt8 * xmlDataPtr = NULL;
CFDataRef data = 0;
CFDataRef xmlDataRef = 0;
DebugLog ( ( "Mount('%s','%s')\n", deviceNamePtr, mountPointPtr ) );
if ( mountPointPtr == NULL || *mountPointPtr == '\0' )
{
result = FSUR_IO_FAIL;
return result;
}
( void ) memset ( &args, 0L, sizeof ( AppleCDDAArguments ) );
args.device = ( char * ) deviceNamePtr;
args.fileType = ( UInt32 ) 'AIFC';
args.fileCreator = ( UInt32 ) '????';
error = GetVFSConfigurationByName ( gAppleCDDAName, &vfc );
if ( error )
{
error = LoadKernelExtension ( );
if ( error != 0 )
{
return error;
}
else
{
error = GetVFSConfigurationByName ( gAppleCDDAName, &vfc );
if ( error != 0 )
{
return error;
}
}
}
TOCDataPtr = ( QTOCDataFormat10Ptr ) GetTOCDataPtr ( args.device );
if ( TOCDataPtr != NULL )
{
data = GetTrackData ( args.device, TOCDataPtr );
if ( data != 0 )
{
UInt32 size = CFDataGetLength ( data );
DebugLog ( ( "CFDataGetLength returned size = %ld\n", size ) );
args.nameData = ( char * ) malloc ( size );
args.nameDataSize = size;
CFDataGetBytes ( data, CFRangeMake ( 0, size ), ( UInt8 * ) args.nameData );
CFRelease ( data );
data = 0;
}
else
{
DebugLog ( ( "data is null\n" ) );
}
args.numTracks = FindNumberOfAudioTracks ( TOCDataPtr );
xmlDataRef = CreateXMLFileInPListFormat ( TOCDataPtr );
xmlDataPtr = ( UInt8 * ) CFDataGetBytePtr ( xmlDataRef );
args.xmlFileSize = CFDataGetLength ( xmlDataRef );
args.xmlData = ( UInt8 * ) malloc ( args.xmlFileSize );
if ( args.xmlData != NULL )
{
memcpy ( args.xmlData, xmlDataPtr, args.xmlFileSize );
#if 0
{
UInt32 count = 0;
for ( ; count < args.xmlFileSize; count = count + 8 )
{
DebugLog ( ("%x:%x:%x:%x %x:%x:%x:%x\n",
xmlDataPtr[count],
xmlDataPtr[count+1],
xmlDataPtr[count+2],
xmlDataPtr[count+3],
xmlDataPtr[count+4],
xmlDataPtr[count+5],
xmlDataPtr[count+6],
xmlDataPtr[count+7] ) );
}
DebugLog ( ( "\n" ) );
DebugLog ( ( "XML File Size = %ld\n", args.xmlFileSize ) );
}
#endif
}
free ( ( char * ) TOCDataPtr );
}
DebugLog ( ( "DeviceName = %s\n", args.device ) );
DebugLog ( ( "numTracks = %d\n", args.numTracks ) );
if ( args.nameData == NULL || args.nameDataSize == 0 )
return FSUR_IO_FAIL;
result = mount ( vfc.vfc_name, mountPointPtr, mountFlags, &args );
if ( args.xmlData != NULL )
{
free ( ( char * ) xmlDataPtr );
}
if ( args.nameData != NULL )
{
free ( ( char * ) args.nameData );
}
if ( result == 0 )
result = FSUR_IO_SUCCESS;
return result;
}
int
ParseTOC ( UInt8 * TOCInfoPtr )
{
int result = FSUR_UNRECOGNIZED;
int error = 0;
QTOCDataFormat10Ptr TOCDataPtr = NULL;
UInt8 index = 0;
UInt8 numberOfDescriptors = 0;
if ( TOCInfoPtr != NULL )
{
TOCDataPtr = ( QTOCDataFormat10Ptr ) TOCInfoPtr;
error = GetNumberOfTrackDescriptors ( TOCDataPtr, &numberOfDescriptors );
if ( error == 0 )
{
for ( index = 0; index < numberOfDescriptors; index++ )
{
if ( IsAudioTrack ( index, TOCDataPtr ) )
{
return FSUR_RECOGNIZED;
}
}
}
}
return result;
}
int
GetVFSConfigurationByName ( const char * fileSystemName, struct vfsconf * vfsConfPtr )
{
int name[4], maxtypenum, cnt, error;
size_t buflen;
name[0] = CTL_VFS;
name[1] = VFS_GENERIC;
name[2] = VFS_MAXTYPENUM;
buflen = 4;
error = sysctl ( name, 3, &maxtypenum, &buflen, ( void * ) 0, ( size_t ) 0 );
if ( error < 0 )
return ( -1 );
name[2] = VFS_CONF;
buflen = sizeof ( *vfsConfPtr );
for ( cnt = 0; cnt < maxtypenum; cnt++ )
{
name[3] = cnt;
error = sysctl ( name, 4, vfsConfPtr, &buflen, ( void * ) 0, ( size_t ) 0 );
if ( error < 0 )
{
if ( errno != EOPNOTSUPP && errno != ENOENT )
{
return ( -1 );
}
continue;
}
if ( !strcmp ( fileSystemName, vfsConfPtr->vfc_name ) )
{
return ( 0 );
}
}
errno = ENOENT;
return ( -1 );
}
CFDataRef
GetTrackData ( const char * bsdDevNode,
const QTOCDataFormat10Ptr TOCData )
{
CFMutableDataRef data = 0;
CFStringRef trackString = 0;
UInt8 numTracks = 0;
UInt32 trackIndex = 0;
UInt8 currentTrack = 0;
SInt32 error = 0;
CDDATrackName * database = NULL;
data = CFDataCreateMutable ( kCFAllocatorDefault, 0 );
database->Init ( bsdDevNode, TOCData );
error = GetNumberOfTrackDescriptors ( ( QTOCDataFormat10Ptr ) TOCData, &numTracks );
if ( error != 0 )
{
DebugLog ( ( "Error = %ld on GetNumberOfTrackDescriptors\n", error ) );
exit ( 1 );
}
for ( trackIndex = 0; trackIndex < numTracks; trackIndex++ )
{
if ( IsAudioTrack ( trackIndex, TOCData ) == false )
continue;
currentTrack = GetPointValue ( trackIndex, TOCData );
trackString = ( database )->GetTrackName ( currentTrack );
if ( trackString != 0 )
{
CFIndex numCharsConverted = 0;
CFIndex numChars = 0;
UInt32 size = 0;
UInt8 tmp = 0;
char buffer[MAXNAMLEN];
size = CFStringGetLength ( trackString );
DebugLog ( ( "size = %ld\n", size ) );
numCharsConverted = CFStringGetBytes (
trackString,
CFRangeMake ( 0, CFStringGetLength ( trackString ) ),
kCFStringEncodingUTF8,
0,
false,
( UInt8 * ) buffer,
MAXNAMLEN,
&numChars );
DebugLog ( ( "numChars = %ld, numCharsConverted = %ld\n", numChars, numCharsConverted ) );
CFDataAppendBytes ( data,
¤tTrack,
1 );
tmp = numChars & 0xFF;
CFDataAppendBytes ( data,
&tmp,
1 );
CFDataAppendBytes ( data,
( UInt8 * ) buffer,
tmp );
CFRelease ( trackString );
}
}
if ( database != NULL )
{
delete database;
database = NULL;
}
return data;
}
int
LoadKernelExtension ( void )
{
int pid;
int result = -1;
union wait status;
pid = fork ( );
if ( pid == 0 )
{
result = execl ( kLoadCommand, kLoadCommand,
kCDDAFileSystemExtensionPath, NULL );
goto Return;
}
if ( pid == -1 )
{
result = errno;
goto Return;
}
if ( ( wait4 ( pid, ( int * ) &status, 0, NULL ) == pid ) &&
( WIFEXITED ( status ) ) )
{
result = status.w_retcode;
}
else
{
result = -1;
}
Return:
return result;
}
CFDataRef
CreateXMLFileInPListFormat ( QTOCDataFormat10Ptr TOCDataPtr )
{
SubQTOCInfoPtr trackDescriptorPtr = NULL;
SubQTOCInfoPtr lastTrackDescriptorPtr = NULL;
UInt16 numSessions = 0;
UInt16 length = 0;
UInt16 numberOfDescriptors = 0;
CFMutableDictionaryRef theCDDictionaryRef = 0;
CFMutableArrayRef theSessionArrayRef = 0;
CFDataRef theRawTOCDataRef = 0;
UInt32 index = 0;
CFDataRef xmlData = 0;
DebugLog ( ( "CreateXMLFileInPListFormat called\n" ) );
if ( TOCDataPtr != NULL )
{
theCDDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
length = TOCDataPtr->TOCDataLength;
theRawTOCDataRef = CFDataCreate ( kCFAllocatorDefault,
( UInt8 * ) TOCDataPtr,
length + sizeof ( TOCDataPtr->TOCDataLength ) );
CFDictionarySetValue ( theCDDictionaryRef,
CFSTR ( kRawTOCDataString ),
theRawTOCDataRef );
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
numSessions = TOCDataPtr->lastSessionNumber - TOCDataPtr->firstSessionNumber + 1;
if ( numberOfDescriptors <= 0 )
{
DebugLog ( ( "No tracks on this CD...\n" ) );
}
theSessionArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault, numSessions, NULL );
trackDescriptorPtr = TOCDataPtr->trackDescriptors;
lastTrackDescriptorPtr = TOCDataPtr->trackDescriptors + numberOfDescriptors - 1;
for ( index = 0; trackDescriptorPtr <= lastTrackDescriptorPtr; index++ )
{
CFMutableDictionaryRef theSessionDictionaryRef = 0;
CFMutableArrayRef theTrackArrayRef = 0;
UInt32 trackIndex = 0;
theSessionDictionaryRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
theTrackArrayRef = CFArrayCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks );
while ( ( trackDescriptorPtr <= lastTrackDescriptorPtr ) &&
( trackDescriptorPtr->sessionNumber == ( index + 1 ) ) )
{
CFMutableDictionaryRef theTrackRef = 0;
CFBooleanRef isDigitalData = kCFBooleanFalse;
CFNumberRef startBlock;
CFNumberRef sessionNumber;
CFNumberRef point;
SInt16 pointValue;
UInt32 blockAddress;
pointValue = trackDescriptorPtr->point;
if ( pointValue == 0x00A0 )
{
CFNumberRef sessionType = 0;
CFNumberRef firstTrackNum = 0;
CFNumberRef sessionNumber = 0;
firstTrackNum = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A0PMSF.firstTrackNum );
sessionType = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A0PMSF.discType );
sessionNumber = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->sessionNumber );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kFirstTrackInSessionString ),
firstTrackNum );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kSessionTypeString ),
sessionType );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kSessionNumberString ),
sessionNumber );
CFRelease ( firstTrackNum );
CFRelease ( sessionType );
CFRelease ( sessionNumber );
goto nextIteration;
}
if ( pointValue == 0x00A1 )
{
CFNumberRef lastTrackNum = 0;
lastTrackNum = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->PMSF.A1PMSF.lastTrackNum );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kLastTrackInSessionString ),
lastTrackNum );
CFRelease ( lastTrackNum );
goto nextIteration;
}
if ( pointValue == 0x00A2 )
{
CFNumberRef leadoutBlock = 0;
UInt32 blockAddress = 0;
blockAddress = ( ( trackDescriptorPtr->PMSF.leadOutStartPosition.minutes * 60 ) +
trackDescriptorPtr->PMSF.leadOutStartPosition.seconds ) * 75 +
trackDescriptorPtr->PMSF.leadOutStartPosition.frames;
leadoutBlock = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberIntType,
&blockAddress );
CFDictionarySetValue ( theSessionDictionaryRef,
CFSTR ( kLeadoutBlockString ),
leadoutBlock );
CFRelease ( leadoutBlock );
goto nextIteration;
}
if ( pointValue > 0x63 )
{
goto nextIteration;
}
theTrackRef = CFDictionaryCreateMutable ( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
point = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberSInt16Type,
&pointValue );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kPointString ),
point );
CFRelease ( point );
blockAddress = ( ( trackDescriptorPtr->PMSF.startPosition.minutes * 60 ) +
trackDescriptorPtr->PMSF.startPosition.seconds ) * 75 +
trackDescriptorPtr->PMSF.startPosition.frames;
DebugLog ( ( "track = %d, blockAddress = %ld\n", pointValue, blockAddress ) );
startBlock = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberLongType,
&blockAddress );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kStartBlockString ),
startBlock );
CFRelease ( startBlock );
sessionNumber = CFNumberCreate ( kCFAllocatorDefault,
kCFNumberCharType,
&trackDescriptorPtr->sessionNumber );
CFDictionarySetValue ( theTrackRef,
CFSTR ( kSessionNumberString ),
sessionNumber );
CFRelease ( sessionNumber );
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == kDigitalDataMask )
{
isDigitalData = kCFBooleanTrue;
}
CFDictionarySetValue ( theTrackRef,
CFSTR ( kDataString ),
isDigitalData );
CFArraySetValueAtIndex ( theTrackArrayRef, trackIndex, theTrackRef );
CFRelease ( theTrackRef );
trackIndex++;
nextIteration:
trackDescriptorPtr++;
}
CFDictionarySetValue ( theSessionDictionaryRef, CFSTR ( kTrackArrayString ), theTrackArrayRef );
CFArraySetValueAtIndex ( theSessionArrayRef, index, theSessionDictionaryRef );
}
CFDictionarySetValue ( theCDDictionaryRef, CFSTR ( kSessionsString ), theSessionArrayRef );
CFRelease ( theSessionArrayRef );
xmlData = CFPropertyListCreateXMLData ( kCFAllocatorDefault, theCDDictionaryRef );
CFRelease ( theCDDictionaryRef );
}
return xmlData;
}
#if 0
#pragma mark -
#pragma mark - Shared Code
#pragma mark -
#endif
void
DisplayUsage ( int usageType, const char * argv[] )
{
if ( usageType == kUsageTypeMount )
{
printf ( "usage: mount_cddafs [-o options] device-name mount-point\n" );
}
else if ( usageType == kUsageTypeUtility )
{
printf ( "usage: %s action_arg device_arg [mount_point_arg] [Flags] \n", argv[0] );
printf ( "action_arg:\n" );
printf ( " -%c (Probe for mounting)\n", FSUC_PROBE );
printf ( " -%c (Mount)\n", FSUC_MOUNT );
printf ( " -%c (Unmount)\n", FSUC_UNMOUNT );
printf ( " -%c (Force Mount)\n", FSUC_MOUNT_FORCE );
printf ( "device_arg:\n" );
printf ( " device we are acting upon (for example, 'sd2')\n" );
printf ( "mount_point_arg:\n" );
printf ( " required for Mount and Force Mount \n" );
printf ( "Flags:\n" );
printf ( " required for Mount, Force Mount and Probe\n" );
printf ( " indicates removable or fixed (for example 'fixed')\n" );
printf ( " indicates readonly or writable (for example 'readonly')\n" );
printf ( "Examples:\n");
printf ( " %s -p sd2 fixed writable\n", argv[0] );
printf ( " %s -m sd2 /my/hfs removable readonly\n", argv[0] );
}
return;
}
UInt8 *
GetTOCDataPtr ( const char * deviceNamePtr )
{
UInt8 * ptr = NULL;
kern_return_t error = 0;
mach_port_t masterPort = 0;
io_iterator_t iterator = 0;
io_registry_entry_t registryEntry = 0;
CFMutableDictionaryRef properties = 0;
char * bsdName = NULL;
if ( !strncmp ( deviceNamePtr, "/dev/r", 6 ) )
{
bsdName = ( char * ) &deviceNamePtr[6];
}
else if ( !strncmp ( deviceNamePtr, "/dev/", 5 ) )
{
bsdName = ( char * ) &deviceNamePtr[5];
}
else
{
DebugLog ( ( "GetTOCDataPtr: ERROR: not /dev/something...\n" ) );
goto Exit;
}
error = IOMasterPort ( bootstrap_port, &masterPort );
if ( error != KERN_SUCCESS )
{
DebugLog ( ( "GetTOCDataPtr: ERROR: couldn't create master port...\n" ) );
goto Exit;
}
error = IOServiceGetMatchingServices ( masterPort,
IOBSDNameMatching ( masterPort, 0, bsdName ),
&iterator );
if ( error != KERN_SUCCESS )
{
DebugLog ( ( "GetTOCDataPtr: ERROR: no matching services...\n" ) );
goto Exit;
}
registryEntry = IOIteratorNext ( iterator );
if ( registryEntry != NULL )
{
if ( IOObjectConformsTo ( registryEntry, kIOCDMediaString ) )
{
error = IORegistryEntryCreateCFProperties ( registryEntry, &properties,
kCFAllocatorDefault, kNilOptions );
if ( error == KERN_SUCCESS )
{
CFDataRef data = 0;
data = ( CFDataRef ) CFDictionaryGetValue ( properties,
CFSTR ( kIOCDMediaTOC ) );
if ( data != NULL )
{
ptr = CreateBufferFromCFData ( data );
}
CFRelease ( properties );
}
}
else
{
DebugLog ( ( "Dynamic Cast failed.\n" ) );
goto Exit;
}
error = IOObjectRelease ( registryEntry );
}
else
{
DebugLog ( ( "Registry entry is NULL.\n" ) );
}
error = IOObjectRelease ( iterator );
Exit:
return ptr;
}
Boolean
IsAudioTrack ( UInt32 trackNumber, QTOCDataFormat10Ptr TOCData )
{
SubQTOCInfoPtr trackDescriptorPtr;
trackDescriptorPtr = TOCData->trackDescriptors;
trackDescriptorPtr = trackDescriptorPtr + trackNumber;
if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 )
{
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 )
{
return true;
}
}
return false;
}
SInt32
GetNumberOfTrackDescriptors ( QTOCDataFormat10Ptr TOCDataPtr,
UInt8 * numberOfDescriptors )
{
UInt16 length = 0;
if ( ( TOCDataPtr == NULL ) || ( numberOfDescriptors == NULL ) )
{
return -1;
}
length = TOCDataPtr->TOCDataLength;
DebugLog ( ( "Length = %d\n", length ) );
if ( length <= 4 )
return -1;
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
*numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
DebugLog ( ( "Number of descriptors = %d\n", *numberOfDescriptors ) );
return 0;
}
UInt8
GetPointValue ( UInt32 trackIndex, QTOCDataFormat10Ptr TOCData )
{
SubQTOCInfoPtr trackDescriptorPtr;
trackDescriptorPtr = TOCData->trackDescriptors;
trackDescriptorPtr = trackDescriptorPtr + trackIndex;
return trackDescriptorPtr->point;
}
UInt8 *
CreateBufferFromCFData ( CFDataRef theData )
{
CFRange range;
CFIndex bufferLength = CFDataGetLength ( theData );
UInt8 * buffer = ( UInt8 * ) malloc ( bufferLength );
range = CFRangeMake ( 0, bufferLength );
if ( buffer != NULL )
CFDataGetBytes ( theData, range, buffer );
return buffer;
}
UInt32
FindNumberOfAudioTracks ( QTOCDataFormat10Ptr TOCDataPtr )
{
UInt32 result = 0;
SubQTOCInfoPtr trackDescriptorPtr = NULL;
UInt16 length = 0;
UInt16 numberOfDescriptors = 0;
DebugLog ( ( "FindNumberOfAudioTracks called\n" ) );
if ( TOCDataPtr != NULL )
{
length = TOCDataPtr->TOCDataLength;
length -= ( sizeof ( TOCDataPtr->firstSessionNumber ) +
sizeof ( TOCDataPtr->lastSessionNumber ) );
numberOfDescriptors = length / ( sizeof ( SubQTOCInfo ) );
DebugLog ( ( "numberOfDescriptors = %d\n", numberOfDescriptors ) );
if ( numberOfDescriptors <= 0 )
{
return result;
}
trackDescriptorPtr = TOCDataPtr->trackDescriptors;
while ( numberOfDescriptors > 0 )
{
if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 )
{
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 )
{
result++;
}
}
trackDescriptorPtr++;
numberOfDescriptors--;
}
}
DebugLog ( ( "numberOfTracks = %ld\n", result ) );
return result;
}