AppleCDDAFileSystemUtils.c [plain text]
#ifndef __APPLE_CDDA_FS_UTILS_H__
#include "AppleCDDAFileSystemUtils.h"
#endif
#ifndef __APPLE_CDDA_FS_DEBUG_H__
#include "AppleCDDAFileSystemDebug.h"
#endif
#ifndef __APPLE_CDDA_FS_DEFINES_H__
#include "AppleCDDAFileSystemDefines.h"
#endif
#ifndef __AIFF_SUPPORT_H__
#include "AIFFSupport.h"
#endif
#ifndef __APPLE_CDDA_FS_VFS_OPS_H__
#include "AppleCDDAFileSystemVFSOps.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/stat.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/attr.h>
#include <sys/time.h>
#include <sys/ubc.h>
#include <sys/unistd.h>
static int BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr );
static UInt32 CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr );
static UInt32 CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr );
static int FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize );
errno_t
CreateNewCDDANode ( mount_t mountPtr,
UInt32 nodeID,
enum vtype vNodeType,
vnode_t parentVNodePtr,
struct componentname * compNamePtr,
vnode_t * vNodeHandle )
{
errno_t result = 0;
AppleCDDANodePtr cddaNodePtr = NULL;
vnode_t vNodePtr = NULLVP;
struct vnode_fsparam vfsp;
DebugAssert ( ( mountPtr != NULL ) );
DebugAssert ( ( vNodeHandle != NULL ) );
MALLOC ( cddaNodePtr, AppleCDDANodePtr, sizeof ( AppleCDDANode ), M_TEMP, M_WAITOK );
bzero ( cddaNodePtr, sizeof ( AppleCDDANode ) );
cddaNodePtr->nodeID = nodeID;
bzero ( &vfsp, sizeof ( vfsp ) );
vfsp.vnfs_mp = mountPtr;
vfsp.vnfs_vtype = vNodeType;
vfsp.vnfs_str = "cddafs";
vfsp.vnfs_dvp = parentVNodePtr;
vfsp.vnfs_fsnode = cddaNodePtr;
vfsp.vnfs_cnp = compNamePtr;
vfsp.vnfs_vops = gCDDA_VNodeOp_p;
vfsp.vnfs_rdev = 0;
#if DEBUG
if ( compNamePtr != NULL )
{
DebugLog ( ( "compNamePtr->cn_flags = 0x%08x\n", ( int ) compNamePtr->cn_flags ) );
DebugLog ( ( "compNamePtr->cn_nameiop = 0x%08x\n", ( int ) compNamePtr->cn_nameiop ) );
DebugLog ( ( "compNamePtr->cn_pnbuf = %s\n", compNamePtr->cn_pnbuf ) );
DebugLog ( ( "compNamePtr->cn_nameptr = %s\n", compNamePtr->cn_nameptr ) );
DebugLog ( ( "compNamePtr->cn_namelen = %ld\n", compNamePtr->cn_namelen ) );
DebugLog ( ( "compNamePtr->cn_hash = 0x%08x\n", ( int ) compNamePtr->cn_hash ) );
DebugLog ( ( "compNamePtr->cn_consume = %ld\n\n", compNamePtr->cn_consume ) );
}
#endif
if ( ( parentVNodePtr != NULL ) && ( compNamePtr != NULL ) && ( compNamePtr->cn_flags & MAKEENTRY ) )
vfsp.vnfs_flags = 0;
else
vfsp.vnfs_flags = VNFS_NOCACHE;
vfsp.vnfs_markroot = ( nodeID == kAppleCDDARootFileID );
vfsp.vnfs_marksystem = 0;
result = vnode_create ( VNCREATE_FLAVOR, ( uint32_t ) VCREATESIZE, &vfsp, &vNodePtr );
if ( result != 0 )
{
DebugLog ( ( "getnewvnode failed with error code %d\n", result ) );
goto FREE_CDDA_NODE_ERROR;
}
cddaNodePtr->vNodePtr = vNodePtr;
vnode_addfsref ( vNodePtr );
*vNodeHandle = vNodePtr;
return result;
FREE_CDDA_NODE_ERROR:
FREE ( ( caddr_t ) cddaNodePtr, M_TEMP );
cddaNodePtr = NULL;
return result;
}
int
DisposeCDDANode ( vnode_t vNodePtr )
{
AppleCDDANodePtr cddaNodePtr = NULL;
DebugAssert ( ( vNodePtr != NULL ) );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
if ( cddaNodePtr != NULL )
{
FREE ( vnode_fsnode ( vNodePtr ), M_TEMP );
vnode_clearfsnode ( vNodePtr );
}
return ( 0 );
}
errno_t
CreateNewCDDAFile ( mount_t mountPtr,
UInt32 nodeID,
AppleCDDANodeInfoPtr nodeInfoPtr,
vnode_t parentVNodePtr,
struct componentname * compNamePtr,
vnode_t * vNodeHandle )
{
errno_t result = 0;
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
AppleCDDANodePtr parentCDDANodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
struct componentname cn;
bzero ( &cn, sizeof ( cn ) );
DebugAssert ( ( mountPtr != NULL ) );
DebugAssert ( ( nodeInfoPtr != NULL ) );
DebugAssert ( ( vNodeHandle != NULL ) );
cddaMountPtr = VFSTOCDDA ( mountPtr );
parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root );
DebugAssert ( ( cddaMountPtr != NULL ) );
DebugAssert ( ( parentCDDANodePtr != NULL ) );
if ( parentVNodePtr == NULL )
{
DebugLog ( ( "CreateNewCDDAFile called with NULL parentVNodePtr\n" ) );
parentVNodePtr = cddaMountPtr->root;
}
if ( compNamePtr == NULL )
{
DebugLog ( ( "CreateNewCDDAFile called with NULL compNamePtr\n" ) );
MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK );
cn.cn_nameiop = LOOKUP;
cn.cn_flags = ISLASTCN | MAKEENTRY;
cn.cn_pnlen = MAXPATHLEN;
cn.cn_nameptr = cn.cn_pnbuf;
cn.cn_namelen = nodeInfoPtr->nameSize;
cn.cn_hash = 0;
cn.cn_consume = 0;
bcopy ( nodeInfoPtr->name, cn.cn_nameptr, nodeInfoPtr->nameSize + 1 );
compNamePtr = &cn;
}
result = CreateNewCDDANode ( mountPtr, nodeID, VREG, parentVNodePtr, compNamePtr, &vNodePtr );
if ( result != 0 )
{
DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) );
return result;
}
if ( cn.cn_pnbuf != NULL )
{
DebugLog ( ( "CreateNewCDDAFile: freeing cn_pnbuf\n" ) );
FREE ( cn.cn_pnbuf, M_TEMP );
}
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
BuildCDAIFFHeader ( &cddaNodePtr->u.file.aiffHeader, nodeInfoPtr->numBytes );
cddaNodePtr->nodeType = kAppleCDDATrackType;
cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr;
cddaNodePtr->u.file.nodeInfoPtr = nodeInfoPtr;
DebugLog ( ( "LBA of %d = %ld.\n", cddaNodePtr->nodeID, nodeInfoPtr->LBA ) );
*vNodeHandle = vNodePtr;
return 0;
}
errno_t
CreateNewXMLFile ( mount_t mountPtr,
UInt32 xmlFileSize,
UInt8 * xmlData,
vnode_t parentVNodePtr,
struct componentname * compNamePtr,
vnode_t * vNodeHandle )
{
errno_t result = 0;
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
AppleCDDANodePtr parentCDDANodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
struct componentname cn;
bzero ( &cn, sizeof ( cn ) );
DebugAssert ( ( mountPtr != NULL ) );
DebugAssert ( ( vNodeHandle != NULL ) );
cddaMountPtr = VFSTOCDDA ( mountPtr );
parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root );
DebugAssert ( ( cddaMountPtr != NULL ) );
DebugAssert ( ( parentCDDANodePtr != NULL ) );
if ( parentVNodePtr == NULL )
{
DebugLog ( ( "CreateNewXMLFile called with NULL parentVNodePtr\n" ) );
parentVNodePtr = cddaMountPtr->root;
}
if ( compNamePtr == NULL )
{
DebugLog ( ( "CreateNewXMLFile called with NULL compNamePtr\n" ) );
MALLOC ( cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_TEMP, M_WAITOK );
cn.cn_nameiop = LOOKUP;
cn.cn_flags = ISLASTCN | MAKEENTRY;
cn.cn_pnlen = MAXPATHLEN;
cn.cn_nameptr = cn.cn_pnbuf;
cn.cn_namelen = ( uint32_t ) strlen ( ".TOC.plist" );
cn.cn_hash = 0;
cn.cn_consume = 0;
snprintf ( cn.cn_nameptr, MAXPATHLEN, "%s", ".TOC.plist" );
compNamePtr = &cn;
}
result = CreateNewCDDANode ( mountPtr, kAppleCDDAXMLFileID, VREG, parentVNodePtr, compNamePtr, &vNodePtr );
if ( result != 0 )
{
DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) );
return result;
}
if ( cn.cn_pnbuf != NULL )
{
DebugLog ( ( "CreateNewXMLFile: freeing cn_pnbuf\n" ) );
FREE ( cn.cn_pnbuf, M_TEMP );
}
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
cddaNodePtr->nodeType = kAppleCDDAXMLFileType;
cddaNodePtr->blockDeviceVNodePtr = parentCDDANodePtr->blockDeviceVNodePtr;
cddaNodePtr->u.xmlFile.fileDataPtr = xmlData;
cddaNodePtr->u.xmlFile.fileSize = xmlFileSize;
#if 0
{
UInt32 count;
for ( count = 0; count < xmlFileSize; count = count + 8 )
{
DebugLog ( ( "%x:%x:%x:%x %x:%x:%x:%x\n",
xmlData[count],
xmlData[count+1],
xmlData[count+2],
xmlData[count+3],
xmlData[count+4],
xmlData[count+5],
xmlData[count+6],
xmlData[count+7] ) );
}
DebugLog ( ( "\n" ) );
}
#endif
*vNodeHandle = vNodePtr;
return 0;
}
errno_t
CreateNewCDDADirectory ( mount_t mountPtr,
UInt32 nodeID,
vnode_t * vNodeHandle )
{
errno_t result = 0;
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
DebugAssert ( ( mountPtr != NULL ) );
DebugAssert ( ( vNodeHandle != NULL ) );
result = CreateNewCDDANode ( mountPtr, nodeID, VDIR, NULL, NULL, &vNodePtr );
if ( result != 0 )
{
DebugLog ( ( "Error = %d returned from CreatNewCDDANode\n", result ) );
return result;
}
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
cddaNodePtr->nodeType = kAppleCDDADirectoryType;
cddaNodePtr->u.directory.directorySize = 0;
cddaNodePtr->u.directory.entryCount = kNumberOfFakeDirEntries;
*vNodeHandle = vNodePtr;
return 0;
}
boolean_t
IsAudioTrack ( const SubQTOCInfoPtr trackDescriptorPtr )
{
DebugAssert ( ( trackDescriptorPtr != NULL ) );
if ( trackDescriptorPtr->point < 100 && trackDescriptorPtr->point > 0 )
{
if ( ( trackDescriptorPtr->control & kDigitalDataMask ) == 0 )
{
return TRUE;
}
}
return FALSE;
}
UInt32
CalculateSize ( const QTOCDataFormat10Ptr TOCDataPtr,
UInt32 trackDescriptorOffset,
UInt32 currentA2Offset )
{
UInt32 size = 0;
UInt32 offset = 0;
UInt32 numberOfDescriptors = 0;
UInt32 nextOffset = 0;
SubQTOCInfoPtr trackDescriptorPtr = NULL;
SubQTOCInfoPtr nextTrackDescriptorPtr = NULL;
DebugLog ( ( "CalculateSize: Entering...\n" ) );
DebugAssert ( ( TOCDataPtr != NULL ) );
numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr );
trackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset];
if ( trackDescriptorOffset + 1 >= numberOfDescriptors )
{
nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset];
}
else
{
nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[trackDescriptorOffset + 1];
if ( trackDescriptorPtr->sessionNumber != nextTrackDescriptorPtr->sessionNumber ||
!IsAudioTrack ( nextTrackDescriptorPtr ) )
{
nextTrackDescriptorPtr = &TOCDataPtr->trackDescriptors[currentA2Offset];
}
}
offset = CalculateLBA ( trackDescriptorPtr );
nextOffset = CalculateLBA ( nextTrackDescriptorPtr );
size = ( ( nextOffset - offset ) * kPhysicalMediaBlockSize ) + kPhysicalMediaBlockSize;
DebugLog ( ( "CalculateSize: size = %ld.\n", size ) );
DebugLog ( ( "CalculateSize: exiting...\n" ) );
return size;
}
int
FindName ( mount_t mountPtr, UInt8 trackNumber, char ** name, UInt8 * nameSize )
{
AppleCDDAMountPtr cddaMountPtr = NULL;
UInt8 * ptr = NULL;
UInt8 length = 0;
DebugLog ( ( "FindName: entering\n" ) );
DebugLog ( ( "trackNumber = %d\n" ) );
DebugAssert ( ( mountPtr != NULL ) );
DebugAssert ( ( name != NULL ) );
DebugAssert ( ( nameSize != NULL ) );
cddaMountPtr = VFSTOCDDA ( mountPtr );
DebugLog ( ( "cddaMountPtr->nameDataSize = %ld\n", cddaMountPtr->nameDataSize ) );
ptr = cddaMountPtr->nameData;
if ( ptr == NULL )
{
DebugLog ( ( "cddaMountPtr->nameData is NULL" ) );
return ENOENT;
}
do
{
DebugLog ( ( "*ptr = %d\n", *ptr ) );
if ( *ptr == trackNumber )
{
char mylocalname[512];
DebugLog ( ( "Found track = %d\n", trackNumber ) );
*nameSize = ptr[1];
*name = ( char * ) &ptr[2];
bcopy ( &ptr[2], mylocalname, *nameSize );
mylocalname[*nameSize] = 0;
DebugLog ( ( "NameSize = %d\n", *nameSize ) );
DebugLog ( ( "Name = %s\n", mylocalname ) );
break;
}
else
{
length = ptr[1];
DebugLog ( ( "Didn't find it, keep looking\n" ) );
ptr = &ptr[length + 2];
}
} while ( ptr < ( cddaMountPtr->nameData + cddaMountPtr->nameDataSize ) );
DebugLog ( ( "FindName: exiting\n" ) );
return 0;
}
SInt32
ParseTOC ( mount_t mountPtr,
UInt32 numTracks )
{
QTOCDataFormat10Ptr TOCDataPtr = NULL;
SubQTOCInfoPtr trackDescriptorPtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
AppleCDDANodeInfoPtr nodeInfoPtr = NULL;
AppleCDDADirectoryNodePtr rootDirNodePtr = NULL;
OSStatus error = 0;
UInt16 numberOfDescriptors = 0;
UInt32 currentA2Offset = 0;
UInt32 currentOffset = 0;
DebugLog ( ( "ParseTOC: Entering...\n" ) );
DebugAssert ( ( mountPtr != NULL ) );
cddaMountPtr = VFSTOCDDA ( mountPtr );
rootDirNodePtr = &( ( VTOCDDA ( cddaMountPtr->root ) )->u.directory );
DebugAssert ( ( cddaMountPtr != NULL ) );
DebugAssert ( ( rootDirNodePtr != NULL ) );
TOCDataPtr = CreateBufferFromIORegistry ( mountPtr );
if ( TOCDataPtr != NULL )
{
numberOfDescriptors = CalculateNumberOfDescriptors ( TOCDataPtr );
DebugLog ( ( "Number of descriptors = %d\n", numberOfDescriptors ) );
if ( numberOfDescriptors <= 0 )
{
error = EINVAL;
goto Exit;
}
trackDescriptorPtr = TOCDataPtr->trackDescriptors;
while ( numberOfDescriptors > 0 && rootDirNodePtr->entryCount < ( numTracks + kNumberOfFakeDirEntries ) )
{
if ( trackDescriptorPtr->point == 0xA2 )
{
currentA2Offset = currentOffset;
}
if ( IsAudioTrack ( trackDescriptorPtr ) )
{
nodeInfoPtr = &cddaMountPtr->nodeInfoArrayPtr[rootDirNodePtr->entryCount - kNumberOfFakeDirEntries];
nodeInfoPtr->trackDescriptor = *trackDescriptorPtr;
nodeInfoPtr->LBA = CalculateLBA ( trackDescriptorPtr );
nodeInfoPtr->numBytes = CalculateSize ( TOCDataPtr, currentOffset, currentA2Offset );
rootDirNodePtr->directorySize += nodeInfoPtr->numBytes;
rootDirNodePtr->entryCount++;
( void ) BuildTrackName ( mountPtr, nodeInfoPtr );
DebugLog ( ( "LBA of %d = %ld.\n", trackDescriptorPtr->point, nodeInfoPtr->LBA ) );
}
trackDescriptorPtr++;
numberOfDescriptors--;
currentOffset++;
}
if ( ( numberOfDescriptors != 0 ) && ( rootDirNodePtr->entryCount == ( numTracks + kNumberOfFakeDirEntries ) ) )
{
DebugLog ( ( "ParseTOC: userland utility sent wrong number of audio tracks in at mount time.\n" ) );
}
}
else
{
return ENOMEM;
}
Exit:
if ( TOCDataPtr != NULL )
{
DisposeBufferFromIORegistry ( TOCDataPtr );
}
DebugLog ( ( "ParseTOC: exiting...\n" ) );
return error;
}
int
BuildTrackName ( mount_t mountPtr, AppleCDDANodeInfoPtr nodeInfoPtr )
{
UInt8 trackNumber = 0;
char * name = NULL;
UInt8 nameSize = 0;
int error = 0;
DebugLog ( ( "BuildTrackName: entering.\n" ) );
DebugAssert ( ( nodeInfoPtr != NULL ) );
trackNumber = nodeInfoPtr->trackDescriptor.point;
error = FindName ( mountPtr, trackNumber, &name, &nameSize );
if ( error != 0 )
{
DebugLog ( ( "cddafs : FindName returned error = %d\n", error ) );
}
nodeInfoPtr->nameSize = nameSize;
MALLOC ( nodeInfoPtr->name, char *, nodeInfoPtr->nameSize + 1, M_TEMP, M_WAITOK );
bcopy ( name, &nodeInfoPtr->name[0], nameSize );
nodeInfoPtr->name[nameSize] = 0;
DebugLog ( ( "BuildTrackName: fileName = %s\n", nodeInfoPtr->name ) );
return 0;
}
UInt32
CalculateNumberOfDescriptors ( const QTOCDataFormat10Ptr TOCDataPtr )
{
UInt32 numberOfDescriptors = 0;
UInt32 length = 0;
DebugLog ( ( "CalculateNumberOfDescriptors: Entering...\n" ) );
DebugAssert ( ( TOCDataPtr != NULL ) );
length = OSSwapBigToHostInt16 ( TOCDataPtr->TOCDataLength );
length -= ( UInt32 ) ( ( sizeof ( TOCDataPtr->firstSessionNumber ) + sizeof ( TOCDataPtr->lastSessionNumber ) ) );
numberOfDescriptors = ( length / ( ( UInt32 ) sizeof ( SubQTOCInfo ) ) );
DebugLog ( ( "CalculateNumberOfDescriptors: exiting...\n" ) );
return numberOfDescriptors;
}
UInt32
CalculateLBA ( SubQTOCInfoPtr trackDescriptorPtr )
{
UInt32 frames = 0;
DebugAssert ( ( trackDescriptorPtr != NULL ) );
frames = ( ( ( trackDescriptorPtr->PMSF.startPosition.minutes * kSecondsPerMinute ) +
trackDescriptorPtr->PMSF.startPosition.seconds ) * kFramesPerSecond ) +
trackDescriptorPtr->PMSF.startPosition.frames;
if ( frames < kMSFToLBA )
frames = kMSFToLBA;
return frames - kMSFToLBA;
}