AppleCDDAFileSystemVNodeOps.c [plain text]
#ifndef __APPLE_CDDA_FS_VNODE_OPS_H__
#include "AppleCDDAFileSystemVNodeOps.h"
#endif
#ifndef __APPLE_CDDA_FS_DEBUG_H__
#include "AppleCDDAFileSystemDebug.h"
#endif
#ifndef __APPLE_CDDA_FS_DEFINES_H__
#include "AppleCDDAFileSystemDefines.h"
#endif
#ifndef __APPLE_CDDA_FS_UTILS_H__
#include "AppleCDDAFileSystemUtils.h"
#endif
#ifndef __APPLE_CDDA_FS_VFS_OPS_H__
#include "AppleCDDAFileSystemVFSOps.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/paths.h>
#include <sys/errno.h>
#include <sys/uio.h>
#include <sys/ubc.h>
#include <sys/xattr.h>
#include <vfs/vfs_support.h>
#include <string.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/IOLib.h>
const char gAIFFHeaderPadData[kPhysicalMediaBlockSize - sizeof(CDAIFFHeader)] = { 0 };
static SInt32
AddDirectoryEntry ( UInt32 nodeID, UInt8 type, const char * name, uio_t uio );
static inline uint64_t
__u64min(uint64_t a, uint64_t b)
{
return (a > b ? b : a);
}
static SInt32
AddDirectoryEntry ( UInt32 nodeID,
UInt8 type,
const char * name,
uio_t uio )
{
struct dirent directoryEntry;
SInt32 nameLength = 0;
UInt16 directoryEntryLength = 0;
DebugAssert ( ( name != NULL ) );
DebugAssert ( ( uio != NULL ) );
DebugLog ( ( "fileName = %s\n", name ) );
nameLength = ( SInt32 ) strlen ( name );
DebugAssert ( ( nameLength < MAXNAMLEN + 1 ) );
directoryEntry.d_fileno = nodeID;
directoryEntry.d_reclen = sizeof ( directoryEntry );
directoryEntry.d_type = type;
directoryEntry.d_namlen = nameLength;
directoryEntryLength = directoryEntry.d_reclen;
strncpy ( directoryEntry.d_name, name, MAXNAMLEN );
bzero ( &directoryEntry.d_name[nameLength], MAXNAMLEN + 1 - nameLength );
if ( uio_resid ( uio ) < directoryEntry.d_reclen )
{
directoryEntryLength = 0;
}
else
{
uiomove ( ( caddr_t ) &directoryEntry, ( int ) sizeof ( directoryEntry ), uio );
}
return directoryEntryLength;
}
int
CDDA_Lookup ( struct vnop_lookup_args * lookupArgsPtr )
{
struct mount * mountPtr = NULL;
struct componentname * compNamePtr = NULL;
vnode_t * vNodeHandle = NULL;
vnode_t parentVNodePtr = NULLVP;
AppleCDDANodePtr parentCDDANodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
int error = 0;
int flags = 0;
DebugLog ( ( "CDDA_Lookup: Entering.\n" ) );
DebugAssert ( ( lookupArgsPtr != NULL ) );
compNamePtr = lookupArgsPtr->a_cnp;
vNodeHandle = lookupArgsPtr->a_vpp;
parentVNodePtr = lookupArgsPtr->a_dvp;
mountPtr = vnode_mount ( parentVNodePtr );
DebugAssert ( ( compNamePtr != NULL ) );
DebugAssert ( ( vNodeHandle != NULL ) );
DebugAssert ( ( parentVNodePtr != NULL ) );
parentCDDANodePtr = VTOCDDA ( parentVNodePtr );
cddaMountPtr = VFSTOCDDA ( mountPtr );
DebugAssert ( ( parentCDDANodePtr != NULL ) );
DebugAssert ( ( cddaMountPtr != NULL ) );
*vNodeHandle = NULL;
flags = compNamePtr->cn_flags;
if ( compNamePtr->cn_namelen > NAME_MAX )
{
error = ENAMETOOLONG;
goto Exit;
}
if ( compNamePtr->cn_nameiop == CREATE ||
compNamePtr->cn_nameiop == RENAME ||
compNamePtr->cn_nameiop == DELETE )
{
DebugLog ( ( "Can't CREATE, RENAME or DELETE %s, returning EROFS\n", compNamePtr->cn_nameptr ) );
error = EROFS;
goto Exit;
}
if ( ( flags & ISLASTCN ) == 0 && bcmp ( &compNamePtr->cn_nameptr[compNamePtr->cn_namelen],
_PATH_RSRCFORKSPEC,
sizeof ( _PATH_RSRCFORKSPEC ) - 1 ) == 0 )
{
DebugLog ( ( "No resource forks available, return ENOTDIR.\n" ) );
compNamePtr->cn_consume = ( uint32_t ) sizeof ( _PATH_RSRCFORKSPEC ) - 1;
error = ENOTDIR;
goto Exit;
}
DebugLog ( ( "Looking for name = %s.\n", compNamePtr->cn_nameptr ) );
if ( compNamePtr->cn_nameptr[0] == '.' )
{
if ( compNamePtr->cn_namelen == 1 )
{
DebugLog ( ( ". was requested\n" ) );
error = CDDA_VGetInternal ( mountPtr, kAppleCDDARootFileID, parentVNodePtr, compNamePtr, vNodeHandle );
goto Exit;
}
else if ( ( compNamePtr->cn_namelen == 10 ) && ( !strncmp ( &compNamePtr->cn_nameptr[1], "TOC.plist", 9 ) ) )
{
DebugLog ( ( ".TOC.plist was requested\n" ) );
error = CDDA_VGetInternal ( mountPtr, kAppleCDDAXMLFileID, parentVNodePtr, compNamePtr, vNodeHandle );
goto Exit;
}
else
{
error = ENOENT;
goto Exit;
}
}
if ( strncmp ( &compNamePtr->cn_nameptr[compNamePtr->cn_namelen - 5], ".aiff", 5 ) != 0 )
{
error = ENOENT;
goto Exit;
}
{
ino64_t inode = 0;
if ( compNamePtr->cn_nameptr[1] == ' ' )
{
inode = ( ino64_t ) ( compNamePtr->cn_nameptr[0] - '0' );
}
else if ( compNamePtr->cn_nameptr[2] == ' ' )
{
inode = ( ino64_t ) ( ( ( compNamePtr->cn_nameptr[0] - '0' ) * 10 ) + ( compNamePtr->cn_nameptr[1] - '0' ) );
}
DebugLog ( ( "Track %lld was requested\n", inode ) );
inode += kOffsetForFiles;
error = CDDA_VGetInternal ( mountPtr, inode, parentVNodePtr, compNamePtr, vNodeHandle );
goto Exit;
}
Exit:
return ( error );
}
int
CDDA_Open ( struct vnop_open_args * openArgsPtr )
{
vnode_t vNodePtr = NULLVP;
int error = 0;
DebugLog ( ( "CDDA_Open: Entering.\n" ) );
DebugAssert ( ( openArgsPtr != NULL ) );
vNodePtr = openArgsPtr->a_vp;
DebugAssert ( ( vNodePtr != NULL ) );
if ( ! vnode_isreg ( vNodePtr ) && ! vnode_isdir ( vNodePtr ) )
{
DebugLog ( ( "Error = %d, wrong vnode type.\n", ENOTSUP ) );
error = ENOTSUP;
goto ERROR;
}
vnode_setnoreadahead ( vNodePtr );
ERROR:
DebugLog ( ( "CDDA_Open: exiting with error = %d.\n", error ) );
return ( error );
}
int
CDDA_Close ( struct vnop_close_args * closeArgsPtr )
{
#pragma unused (closeArgsPtr)
return ( 0 );
}
int
CDDA_Read ( struct vnop_read_args * readArgsPtr )
{
vnode_t vNodePtr = NULLVP;
uio_t uio = NULL;
AppleCDDANodePtr cddaNodePtr = NULL;
int error = 0;
DebugLog ( ( "CDDA_Read: Entering.\n" ) );
DebugAssert ( ( readArgsPtr ) );
vNodePtr = readArgsPtr->a_vp;
uio = readArgsPtr->a_uio;
DebugAssert ( ( vNodePtr != NULL ) );
DebugAssert ( ( uio != NULL ) );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
if ( ! vnode_isreg ( vNodePtr ) )
{
DebugLog ( ( "CDDA_Read: not a file, exiting with error = %d.\n", EISDIR ) );
return ( EISDIR );
}
if ( uio_resid ( uio ) == 0 )
{
DebugLog ( ( "CDDA_Read: uio_resid = 0, no data requested" ) );
return ( 0 );
}
if ( uio_offset ( uio ) < 0 )
{
DebugLog ( ( "CDDA_Read: Can't read from a negative offset..." ) );
return ( EINVAL );
}
if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
off_t offset = uio_offset ( uio );
UInt32 amountToCopy = 0;
UInt32 numBytes = 0;
numBytes = cddaNodePtr->u.xmlFile.fileSize;
if ( uio_offset ( uio ) > numBytes )
{
DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) );
return ( 0 );
}
amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), numBytes - offset );
error = uiomove ( ( caddr_t ) &cddaNodePtr->u.xmlFile.fileDataPtr[offset],
amountToCopy,
uio );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
return ( 0 );
}
else if ( cddaNodePtr->nodeType == kAppleCDDATrackType )
{
UInt32 headerSize = 0;
UInt32 count = 0;
UInt64 blockNumber = 0;
off_t offset = 0;
off_t sectorOffset = 0;
buf_t bufPtr = NULL;
offset = uio_offset ( uio );
if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes )
{
DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) );
return ( 0 );
}
headerSize = ( UInt32 ) sizeof ( cddaNodePtr->u.file.aiffHeader );
if ( offset < headerSize )
{
UInt32 amountToCopy = 0;
UInt8 * bytes = NULL;
bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader;
amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), headerSize - offset );
error = uiomove ( ( caddr_t ) &bytes[offset],
amountToCopy,
uio );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
offset += amountToCopy;
}
if ( ( uio_resid ( uio ) > 0 ) &&
( offset < kPhysicalMediaBlockSize ) )
{
UInt32 amountToCopy = 0;
amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), kPhysicalMediaBlockSize - offset );
error = uiomove ( ( caddr_t ) &gAIFFHeaderPadData[offset - headerSize],
amountToCopy,
uio );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
offset += amountToCopy;
}
if ( ( uio_resid ( uio ) > 0 ) &&
( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
offset -= kPhysicalMediaBlockSize;
sectorOffset = offset % kPhysicalMediaBlockSize;
blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA;
{
count = ( UInt32 ) __u64min ( uio_resid ( uio ), ( kPhysicalMediaBlockSize - sectorOffset ) );
count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) );
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
kPhysicalMediaBlockSize,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
error = uiomove ( ( caddr_t ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ), count, uio );
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
blockNumber++;
}
while ( ( uio_resid ( uio ) > kPhysicalMediaBlockSize ) &&
( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
UInt64 blocksToRead = 0;
if ( uio_resid ( uio ) > kMaxBytesPerRead )
{
blocksToRead = kMaxBlocksPerRead;
count = kMaxBytesPerRead;
}
else
{
blocksToRead = uio_resid ( uio ) / kPhysicalMediaBlockSize;
count = ( UInt32 ) ( blocksToRead * kPhysicalMediaBlockSize );
}
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
count,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) );
error = uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio );
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
blockNumber += blocksToRead;
}
if ( ( uio_resid ( uio ) > 0 ) &&
( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
count = ( UInt32 ) __u64min ( uio_resid ( uio ), cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) );
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
kPhysicalMediaBlockSize,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
error = uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio );
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
if ( error != 0 )
{
DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) );
return ( error );
}
}
}
}
DebugLog ( ( "CDDA_Read: exiting.\n" ) );
return ( error );
}
int
CDDA_ReadDir ( struct vnop_readdir_args * readDirArgsPtr )
{
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
AppleCDDANodeInfoPtr nodeInfoArrayPtr = NULL;
uio_t uio = NULL;
UInt32 index = 0;
int error = 0;
SInt32 offsetValue = 0;
UInt32 direntSize = 0;
DebugLog ( ( "CDDA_ReadDir: Entering.\n" ) );
DebugAssert ( ( readDirArgsPtr != NULL ) );
vNodePtr = readDirArgsPtr->a_vp;
uio = readDirArgsPtr->a_uio;
DebugAssert ( ( vNodePtr != NULL ) );
DebugAssert ( ( uio != NULL ) );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
if ( readDirArgsPtr->a_flags & ( VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF ) )
return ( EINVAL );
if ( ! vnode_isdir ( vNodePtr ) )
{
DebugLog ( ( "CDDA_ReadDir: not a directory, exiting with error = %d.\n", ENOTDIR ) );
return ( ENOTDIR );
}
if ( cddaNodePtr->nodeID != kAppleCDDARootFileID )
{
DebugLog ( ( "CDDA_ReadDir: not root directory, exiting with error = %d.\n", EINVAL ) );
return ( EINVAL );
}
if ( uio_iovcnt ( uio ) > 1 )
{
DebugLog ( ( "More than one buffer, exiting with error = %d.\n", EINVAL ) );
return ( EINVAL );
}
if ( ( uint32_t ) uio_resid ( uio ) < sizeof ( struct dirent ) )
{
DebugLog ( ( "resid < dirent size, exiting with error = %d.\n", EINVAL ) );
return ( EINVAL );
}
direntSize = ( UInt32 ) sizeof ( struct dirent );
if ( uio_offset ( uio ) == 0 )
{
offsetValue = AddDirectoryEntry ( cddaNodePtr->nodeID, DT_DIR, ".", uio );
if ( offsetValue == 0 )
{
DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) );
return 0;
}
}
if ( uio_offset ( uio ) == direntSize )
{
offsetValue = AddDirectoryEntry ( cddaNodePtr->nodeID, DT_DIR, "..", uio );
if ( offsetValue == 0 )
{
DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) );
return 0;
}
}
if ( uio_offset ( uio ) == direntSize * kAppleCDDARootFileID )
{
offsetValue += AddDirectoryEntry ( kAppleCDDAXMLFileID, DT_REG, ".TOC.plist", uio );
if ( offsetValue == 0 )
{
DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) );
return 0;
}
}
nodeInfoArrayPtr = VFSTONODEINFO ( vnode_mount ( vNodePtr ) );
cddaMountPtr = VFSTOCDDA ( vnode_mount ( vNodePtr ) );
DebugAssert ( ( nodeInfoArrayPtr != NULL ) );
DebugAssert ( ( cddaMountPtr != NULL ) );
DebugLog ( ( "cddaMountPtr->numTracks = %ld.\n", cddaMountPtr->numTracks ) );
DebugLog ( ( "buffer size needed = %ld.\n", direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) );
for ( index = 0; index < cddaMountPtr->numTracks; index++, nodeInfoArrayPtr++ )
{
DebugLog ( ( "uio_offset ( uio ) = %ld.\n", uio_offset ( uio ) ) );
DebugLog ( ( "uio_resid ( uio ) = %ld.\n", uio_resid ( uio ) ) );
if ( uio_offset ( uio ) == direntSize * ( index + kNumberOfFakeDirEntries ) )
{
DebugLog ( ( "index = %ld.\n", index ) );
offsetValue = AddDirectoryEntry ( nodeInfoArrayPtr->trackDescriptor.point,
DT_REG,
nodeInfoArrayPtr->name,
uio );
if ( offsetValue == 0 )
{
DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) );
return 0;
}
}
}
if ( readDirArgsPtr->a_eofflag )
{
DebugLog ( ( "eofflag = %d.\n", ( uio_offset ( uio ) >= direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) ? 1 : 0 ) );
*readDirArgsPtr->a_eofflag = ( uio_offset ( uio ) >= direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) ? 1 : 0;
error = 0;
}
DebugLog ( ( "CDDA_ReadDir: exiting with error = %d.\n", error ) );
return ( error );
}
int
CDDA_PageIn ( struct vnop_pagein_args * pageInArgsPtr )
{
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
int error = 0;
int nocommit = 0;
UInt32 numBytes = 0;
DebugLog ( ( "CDDA_PageIn: Entering.\n" ) );
DebugAssert ( ( pageInArgsPtr != NULL ) );
vNodePtr = pageInArgsPtr->a_vp;
nocommit = pageInArgsPtr->a_flags & UPL_NOCOMMIT;
DebugAssert ( ( vNodePtr != NULL ) );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
numBytes = cddaNodePtr->u.xmlFile.fileSize;
}
else if ( cddaNodePtr->nodeType == kAppleCDDATrackType )
{
numBytes = cddaNodePtr->u.file.nodeInfoPtr->numBytes;
}
if ( pageInArgsPtr->a_size == 0 )
{
if ( !nocommit )
{
ubc_upl_abort_range ( pageInArgsPtr->a_pl,
pageInArgsPtr->a_pl_offset,
( upl_size_t ) pageInArgsPtr->a_size,
UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY );
}
return ( error );
}
if ( pageInArgsPtr->a_f_offset < 0 )
{
if ( !nocommit )
{
ubc_upl_abort_range ( pageInArgsPtr->a_pl,
pageInArgsPtr->a_pl_offset,
( upl_size_t ) pageInArgsPtr->a_size,
UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY );
}
error = EINVAL;
DebugLog ( ( "CDDA_PageIn: trying to page in from a negative offset.\n" ) );
return ( error );
}
if ( pageInArgsPtr->a_f_offset > numBytes )
{
if ( !nocommit )
{
ubc_upl_abort_range ( pageInArgsPtr->a_pl,
pageInArgsPtr->a_pl_offset,
( upl_size_t ) pageInArgsPtr->a_size,
UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY );
}
return ( error );
}
if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
kern_return_t kret = 0;
vm_offset_t vmOffsetPtr = 0;
UInt32 amountToCopy = 0;
kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr );
if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 )
{
panic ( "CDDA_PageIn: error mapping buffer into kernel space!" );
}
bzero ( ( caddr_t )( vmOffsetPtr + pageInArgsPtr->a_pl_offset ), PAGE_SIZE );
amountToCopy = ( UInt32 ) __u64min ( PAGE_SIZE, numBytes - pageInArgsPtr->a_f_offset );
bcopy ( &cddaNodePtr->u.xmlFile.fileDataPtr[pageInArgsPtr->a_f_offset],
( void * ) vmOffsetPtr,
amountToCopy );
kret = ubc_upl_unmap ( pageInArgsPtr->a_pl );
if ( kret != KERN_SUCCESS )
{
panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" );
}
if ( !nocommit )
{
ubc_upl_commit_range ( pageInArgsPtr->a_pl,
pageInArgsPtr->a_pl_offset,
PAGE_SIZE,
UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_CLEAR_DIRTY );
}
return 0;
}
else if ( cddaNodePtr->nodeType == kAppleCDDATrackType )
{
UInt32 headerSize = 0;
UInt64 blockNumber = 0;
UInt32 count = 0;
off_t offset = 0;
off_t sectorOffset = 0;
off_t residual = 0;
kern_return_t kret = 0;
vm_offset_t vmOffsetPtr = 0;
buf_t bufPtr = NULL;
residual = pageInArgsPtr->a_size;
offset = pageInArgsPtr->a_f_offset;
if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes )
{
DebugLog ( ( "CDDA_PageIn: Can't read past end of file..." ) );
return ( 0 );
}
headerSize = ( UInt32 ) sizeof ( cddaNodePtr->u.file.aiffHeader );
kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr );
if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 )
{
panic ( "CDDA_PageIn: error mapping buffer into kernel space!" );
}
vmOffsetPtr += pageInArgsPtr->a_pl_offset;
if ( offset < headerSize )
{
UInt32 amountToCopy = 0;
UInt8 * bytes = NULL;
amountToCopy = ( UInt32 ) __u64min ( pageInArgsPtr->a_size, headerSize - offset );
bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader;
bcopy ( &bytes[offset],
( void * ) vmOffsetPtr,
amountToCopy );
offset += amountToCopy;
residual -= amountToCopy;
vmOffsetPtr += amountToCopy;
}
if ( ( residual > 0 ) &&
( offset < kPhysicalMediaBlockSize ) )
{
UInt32 amountToCopy = 0;
amountToCopy = ( UInt32 ) __u64min ( residual, kPhysicalMediaBlockSize - offset );
bcopy ( &gAIFFHeaderPadData[offset - headerSize],
( void * ) vmOffsetPtr,
amountToCopy );
offset += amountToCopy;
residual -= amountToCopy;
vmOffsetPtr += amountToCopy;
}
if ( ( residual > 0 ) &&
( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
offset -= kPhysicalMediaBlockSize;
sectorOffset = offset % kPhysicalMediaBlockSize;
blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA;
{
count = ( UInt32 ) __u64min ( residual, ( kPhysicalMediaBlockSize - sectorOffset ) );
count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset );
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
kPhysicalMediaBlockSize,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
bcopy ( ( void * ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ),
( void * ) vmOffsetPtr,
count );
offset += count;
residual -= count;
vmOffsetPtr += count;
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
blockNumber++;
}
while ( ( residual > kPhysicalMediaBlockSize ) &&
( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
UInt64 blocksToRead = 0;
if ( residual > kMaxBytesPerRead )
{
blocksToRead = kMaxBlocksPerRead;
count = kMaxBytesPerRead;
}
else
{
blocksToRead = residual / kPhysicalMediaBlockSize;
count = ( UInt32 ) ( blocksToRead * kPhysicalMediaBlockSize );
}
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
count,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset );
bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count );
offset += count;
residual -= count;
vmOffsetPtr += count;
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
blockNumber += blocksToRead;
}
if ( ( residual > 0 ) &&
( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) )
{
count = ( UInt32 ) __u64min ( residual, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset );
error = ( int ) buf_meta_bread (
cddaNodePtr->blockDeviceVNodePtr,
blockNumber,
kPhysicalMediaBlockSize,
NOCRED,
&bufPtr );
if ( error != 0 )
{
buf_brelse ( bufPtr );
return ( error );
}
bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count );
offset += count;
residual -= count;
vmOffsetPtr += count;
buf_markinvalid ( bufPtr );
buf_brelse ( bufPtr );
}
}
kret = ubc_upl_unmap ( pageInArgsPtr->a_pl );
if ( kret != KERN_SUCCESS )
{
panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" );
}
if ( !nocommit )
{
ubc_upl_commit_range ( pageInArgsPtr->a_pl,
pageInArgsPtr->a_pl_offset,
( upl_size_t ) pageInArgsPtr->a_size,
UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_CLEAR_DIRTY );
}
}
DebugLog ( ( "CDDA_PageIn: exiting...\n" ) );
return ( error );
}
int
CDDA_GetAttributes ( struct vnop_getattr_args * getAttrArgsPtr )
{
vnode_t vNodePtr = NULLVP;
mount_t mountPtr = NULL;
struct vnode_attr * attributesPtr = NULL;
AppleCDDANodePtr cddaNodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
struct timespec nullTime = { 0, 0 };
DebugLog ( ( "CDDA_GetAttributes: Entering.\n" ) );
DebugAssert ( ( getAttrArgsPtr != NULL ) );
vNodePtr = getAttrArgsPtr->a_vp;
mountPtr = vnode_mount ( vNodePtr );
attributesPtr = getAttrArgsPtr->a_vap;
DebugAssert ( ( vNodePtr != NULL ) );
DebugAssert ( ( attributesPtr != NULL ) );
cddaMountPtr = VFSTOCDDA ( mountPtr );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
DebugAssert ( ( cddaMountPtr != NULL ) );
DebugLog ( ( "nodeID = %ld.\n", cddaNodePtr->nodeID ) );
if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType )
{
VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDARootFileID );
}
else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDAXMLFileID );
}
else
{
VATTR_RETURN ( attributesPtr, va_fileid, cddaNodePtr->nodeID );
}
if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType )
{
VATTR_RETURN ( attributesPtr, va_parentid, 1 );
}
else
{
VATTR_RETURN ( attributesPtr, va_parentid, kAppleCDDARootFileID );
}
VATTR_RETURN ( attributesPtr, va_type, vnode_vtype ( vNodePtr ) ); VATTR_RETURN ( attributesPtr, va_iosize, kPhysicalMediaBlockSize );
VATTR_RETURN ( attributesPtr, va_create_time, cddaMountPtr->mountTime ); VATTR_RETURN ( attributesPtr, va_modify_time, cddaMountPtr->mountTime ); VATTR_RETURN ( attributesPtr, va_change_time, nullTime ); VATTR_RETURN ( attributesPtr, va_access_time, nullTime ); VATTR_RETURN ( attributesPtr, va_backup_time, nullTime );
VATTR_RETURN ( attributesPtr, va_fsid, vfs_statfs ( mountPtr )->f_fsid.val[0] );
VATTR_RETURN ( attributesPtr, va_uid, kUnknownUserID ); VATTR_RETURN ( attributesPtr, va_gid, kUnknownGroupID ); VATTR_RETURN ( attributesPtr, va_filerev, 0 );
VATTR_RETURN ( attributesPtr, va_gen, 0 );
VATTR_RETURN ( attributesPtr, va_flags, 0 );
VATTR_RETURN ( attributesPtr, va_rdev, 0 );
VATTR_RETURN ( attributesPtr, va_encoding, 0 );
VATTR_RETURN ( attributesPtr, va_mode, S_IRUSR | S_IRGRP | S_IROTH );
if ( vnode_isvroot ( vNodePtr ) )
{
attributesPtr->va_mode |= S_IFDIR; attributesPtr->va_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfRootDirReferences );
VATTR_RETURN ( attributesPtr, va_nchildren, cddaNodePtr->u.directory.entryCount - kAppleCDDANumberOfRootDirReferences );
VATTR_RETURN ( attributesPtr, va_data_size, ( cddaNodePtr->u.directory.entryCount ) * sizeof ( struct dirent ) );
}
else
{
attributesPtr->va_mode |= DEFFILEMODE;
VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfFileReferences );
if ( cddaNodePtr->nodeType == kAppleCDDATrackType )
{
VATTR_RETURN ( attributesPtr, va_data_size, cddaNodePtr->u.file.nodeInfoPtr->numBytes );
VATTR_RETURN ( attributesPtr, va_data_alloc, cddaNodePtr->u.file.nodeInfoPtr->numBytes );
}
else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
VATTR_RETURN ( attributesPtr, va_data_size, cddaNodePtr->u.xmlFile.fileSize );
VATTR_RETURN ( attributesPtr, va_data_alloc, cddaNodePtr->u.xmlFile.fileSize );
}
}
DebugLog ( ( "CDDA_GetAttributes: exiting...\n" ) );
return ( 0 );
}
int
CDDA_Inactive ( struct vnop_inactive_args * inactiveArgsPtr )
{
DebugLog ( ( "CDDA_Inactive: Entering.\n" ) );
DebugAssert ( ( inactiveArgsPtr != NULL ) );
( void ) nop_inactive ( inactiveArgsPtr );
DebugLog ( ( "CDDA_Inactive: exiting...\n" ) );
return ( 0 );
}
int
CDDA_Remove ( struct vnop_remove_args * removeArgsPtr )
{
DebugLog ( ( "CDDA_Remove: Entering.\n" ) );
DebugAssert ( ( removeArgsPtr != NULL ) );
( void ) nop_remove ( removeArgsPtr );
DebugLog ( ( "CDDA_Remove: exiting...\n" ) );
return ( EROFS );
}
int
CDDA_RmDir ( struct vnop_rmdir_args * removeDirArgsPtr )
{
DebugLog ( ( "CDDA_RmDir: Entering.\n" ) );
DebugAssert ( ( removeDirArgsPtr != NULL ) );
( void ) nop_rmdir ( removeDirArgsPtr );
DebugLog ( ( "CDDA_RmDir: exiting...\n" ) );
return ( EROFS );
}
int
CDDA_Reclaim ( struct vnop_reclaim_args * reclaimArgsPtr )
{
vnode_t vNodePtr = NULLVP;
AppleCDDANodePtr cddaNodePtr = NULL;
AppleCDDAMountPtr cddaMountPtr = NULL;
AppleCDDANodeInfoPtr nodeInfoPtr = NULL;
int error = 0;
DebugLog ( ( "CDDA_Reclaim: Entering.\n" ) );
DebugAssert ( ( reclaimArgsPtr != NULL ) );
vNodePtr = reclaimArgsPtr->a_vp;
DebugAssert ( ( vNodePtr != NULL ) );
cddaNodePtr = VTOCDDA ( vNodePtr );
DebugAssert ( ( cddaNodePtr != NULL ) );
cddaMountPtr = VFSTOCDDA ( vnode_mount ( vNodePtr ) );
lck_mtx_lock ( cddaMountPtr->cddaMountLock );
if ( cddaNodePtr->nodeType == kAppleCDDATrackType )
{
nodeInfoPtr = CDDATONODEINFO ( cddaNodePtr );
nodeInfoPtr->vNodePtr = NULL;
}
else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType )
{
cddaMountPtr->xmlFileVNodePtr = NULL;
}
lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
vnode_removefsref ( vNodePtr );
error = DisposeCDDANode ( vNodePtr );
DebugLog ( ( "CDDA_Reclaim: exiting...\n" ) );
return ( error );
}
int
CDDA_BlockToOffset ( struct vnop_blktooff_args * blockToOffsetArgsPtr )
{
DebugLog ( ( "CDDA_BlockToOffset: Entering.\n" ) );
DebugAssert ( ( blockToOffsetArgsPtr != NULL ) );
if ( blockToOffsetArgsPtr->a_vp == NULL )
{
DebugLog ( ( "CDDA_BlockToOffset: incoming vnode is NULL.\n" ) );
return ( EINVAL );
}
*( blockToOffsetArgsPtr->a_offset ) =
( off_t ) ( blockToOffsetArgsPtr->a_lblkno * PAGE_SIZE );
DebugLog ( ( "CDDA_BlockToOffset: exiting...\n" ) );
return ( 0 );
}
int
CDDA_OffsetToBlock ( struct vnop_offtoblk_args * offsetToBlockArgsPtr )
{
DebugLog ( ( "CDDA_OffsetToBlock: Entering.\n" ) );
DebugAssert ( ( offsetToBlockArgsPtr != NULL ) );
if ( offsetToBlockArgsPtr->a_vp == NULL )
{
DebugLog ( ( "CDDA_OffsetToBlock: incoming vnode is NULL.\n" ) );
return ( EINVAL );
}
*( offsetToBlockArgsPtr->a_lblkno ) = ( offsetToBlockArgsPtr->a_offset / PAGE_SIZE );
DebugLog ( ( "CDDA_OffsetToBlock: exiting...\n" ) );
return ( 0 );
}
int
CDDA_Pathconf ( struct vnop_pathconf_args * pathConfArgsPtr )
{
int returnValue = 0;
DebugLog ( ( "CDDA_Pathconf: Entering.\n" ) );
DebugAssert ( ( pathConfArgsPtr != NULL ) );
switch ( pathConfArgsPtr->a_name )
{
case _PC_LINK_MAX:
*pathConfArgsPtr->a_retval = 1;
break;
case _PC_NAME_MAX:
*pathConfArgsPtr->a_retval = NAME_MAX;
break;
case _PC_PATH_MAX:
*pathConfArgsPtr->a_retval = PATH_MAX;
break;
case _PC_CHOWN_RESTRICTED:
*pathConfArgsPtr->a_retval = 1;
break;
case _PC_NO_TRUNC:
*pathConfArgsPtr->a_retval = 0;
break;
case _PC_XATTR_SIZE_BITS:
*pathConfArgsPtr->a_retval = 0;
break;
default:
returnValue = EINVAL;
break;
}
DebugLog ( ( "CDDA_Pathconf: exiting with returnValue = %d.\n", returnValue ) );
return ( returnValue );
}
int
CDDA_GetXAttr ( struct vnop_getxattr_args * getXAttrArgsPtr )
{
AppleCDDANodePtr cddaNodePtr = NULL;
FinderInfo * finderInfoPtr = NULL;
char buf[32] = { 0 };
DebugLog ( ( "CDDA_GetXAttr: Entering.\n" ) );
DebugAssert ( ( getXAttrArgsPtr != NULL ) );
if ( strncmp ( getXAttrArgsPtr->a_name, XATTR_FINDERINFO_NAME, sizeof ( XATTR_FINDERINFO_NAME ) ) != 0 )
{
return ( ENOATTR );
}
cddaNodePtr = VTOCDDA ( getXAttrArgsPtr->a_vp );
finderInfoPtr = ( FinderInfo * ) buf;
if ( !vnode_isvroot ( getXAttrArgsPtr->a_vp ) )
{
if ( cddaNodePtr->nodeID == kAppleCDDAXMLFileID )
{
DebugLog ( ( "kFinderInfoInvisibleMask\n" ) );
finderInfoPtr->finderFlags = kFinderInfoInvisibleMask;
}
else
{
finderInfoPtr->finderFlags = kFinderInfoNoFileExtensionMask;
}
finderInfoPtr->location.v = -1;
finderInfoPtr->location.h = -1;
if ( vnode_isreg ( getXAttrArgsPtr->a_vp ) && ( cddaNodePtr->nodeID != kAppleCDDAXMLFileID ) )
{
DebugLog ( ( "fileType, creator\n" ) );
finderInfoPtr->fileType = VFSTOCDDA ( vnode_mount ( cddaNodePtr->vNodePtr ) )->fileType;
finderInfoPtr->fileCreator = VFSTOCDDA ( vnode_mount ( cddaNodePtr->vNodePtr ) )->fileCreator;
}
finderInfoPtr->fileType = OSSwapHostToBigInt32 ( finderInfoPtr->fileType );
finderInfoPtr->fileCreator = OSSwapHostToBigInt32 ( finderInfoPtr->fileCreator );
finderInfoPtr->finderFlags = OSSwapHostToBigInt16 ( finderInfoPtr->finderFlags );
finderInfoPtr->location.v = OSSwapHostToBigInt16 ( finderInfoPtr->location.v );
finderInfoPtr->location.h = OSSwapHostToBigInt16 ( finderInfoPtr->location.h );
}
return ( uiomove ( ( caddr_t ) buf, ( int ) sizeof ( buf ), getXAttrArgsPtr->a_uio ) );
}
int ( **gCDDA_VNodeOp_p )( void * );
typedef int (*VNOPFUNC) ( void * );
#if 0
#pragma mark -
#endif
struct vnodeopv_entry_desc gCDDA_VNodeOperationEntries[] =
{
{ &vnop_default_desc, ( VNOPFUNC ) vn_default_error },
{ &vnop_lookup_desc, ( VNOPFUNC ) CDDA_Lookup }, { &vnop_open_desc, ( VNOPFUNC ) CDDA_Open }, { &vnop_close_desc, ( VNOPFUNC ) CDDA_Close }, { &vnop_getattr_desc, ( VNOPFUNC ) CDDA_GetAttributes }, { &vnop_setattr_desc, ( VNOPFUNC ) nop_setattr }, { &vnop_read_desc, ( VNOPFUNC ) CDDA_Read }, { &vnop_fsync_desc, ( VNOPFUNC ) nop_fsync }, { &vnop_remove_desc, ( VNOPFUNC ) CDDA_Remove }, { &vnop_rmdir_desc, ( VNOPFUNC ) CDDA_RmDir }, { &vnop_readdir_desc, ( VNOPFUNC ) CDDA_ReadDir }, { &vnop_inactive_desc, ( VNOPFUNC ) CDDA_Inactive }, { &vnop_reclaim_desc, ( VNOPFUNC ) CDDA_Reclaim }, { &vnop_pathconf_desc, ( VNOPFUNC ) CDDA_Pathconf }, { &vnop_pagein_desc, ( VNOPFUNC ) CDDA_PageIn }, { &vnop_blktooff_desc, ( VNOPFUNC ) CDDA_BlockToOffset }, { &vnop_offtoblk_desc, ( VNOPFUNC ) CDDA_OffsetToBlock }, { &vnop_getxattr_desc, ( VNOPFUNC ) CDDA_GetXAttr }, { NULL, ( VNOPFUNC ) NULL }
};
struct vnodeopv_desc gCDDA_VNodeOperationsDesc =
{
&gCDDA_VNodeOp_p,
gCDDA_VNodeOperationEntries
};