/* * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // AppleCDDAFileSystemVNodeOps.c created by CJS on Mon 10-Apr-2000 // Project Includes #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 // System Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // Globals //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ const char gAIFFHeaderPadData[kPhysicalMediaBlockSize - sizeof(CDAIFFHeader)] = { 0 }; //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // Static Function Prototypes //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ static SInt32 AddDirectoryEntry ( UInt32 nodeID, UInt8 type, const char * name, uio_t uio ); //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // AddDirectoryEntry - This routine adds a directory entry to the uio buffer //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ 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 = 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; // Copy the string strncpy ( directoryEntry.d_name, name, MAXNAMLEN ); // Zero the rest of the array for safe-keeping bzero ( &directoryEntry.d_name[nameLength], MAXNAMLEN + 1 - nameLength ); if ( uio_resid ( uio ) < directoryEntry.d_reclen ) { // We can't copy because there isn't enough room in the buffer, // so set the directoryEntryLength to zero so the caller knows // an error occurred directoryEntryLength = 0; } else { // Move the data uiomove ( ( caddr_t ) &directoryEntry, sizeof ( directoryEntry ), uio ); } return directoryEntryLength; } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Lookup - This routine performs a lookup //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Lookup ( struct vnop_lookup_args * lookupArgsPtr ) /* struct vnop_lookup_args { struct vnodeop_desc *a_desc; vnode_t a_dvp; vnode_t *a_vpp; struct componentname *a_cnp; vfs_context_t a_context; }; */ { 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; } // Check if process wants to create, delete or rename anything 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; } // Determine if we're looking for a resource fork. // NB: this could cause a read off the end of the component name buffer in some rare cases. 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 = sizeof ( _PATH_RSRCFORKSPEC ) - 1; error = ENOTDIR; goto Exit; } DebugLog ( ( "Looking for name = %s.\n", compNamePtr->cn_nameptr ) ); // first check for "." and ".TOC.plist" 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 { // Not going to find anything prefixed with "." other than the above. error = ENOENT; goto Exit; } } // At this point, we better be fetching a file which ends in ".aiff". if ( strcmp ( &compNamePtr->cn_nameptr[compNamePtr->cn_namelen - 5], ".aiff" ) != 0 ) { error = ENOENT; goto Exit; } // Find out which inode they want. The first two bytes will tell us the track number which // we can convert to an inode number by adding the kOffsetForFiles constant. Beware lame string // parsing ahead... { ino64_t inode = 0; if ( compNamePtr->cn_nameptr[1] == ' ' ) { // It's asking about track 1-9. inode = ( ino64_t ) ( compNamePtr->cn_nameptr[0] - '0' ); } else if ( compNamePtr->cn_nameptr[2] == ' ' ) { // It's asking about track 10-99. inode = ( ino64_t ) ( ( ( compNamePtr->cn_nameptr[0] - '0' ) * 10 ) + ( compNamePtr->cn_nameptr[1] - '0' ) ); } DebugLog ( ( "Track %lld was requested\n", inode ) ); // Add the offset for a CD Track... inode += kOffsetForFiles; // Call the internal vget routine. Make sure to pass the parentVNode and compNamePtr so they // can be passed to the CreateXXX routines if a vnode needs to be created. error = CDDA_VGetInternal ( mountPtr, inode, parentVNodePtr, compNamePtr, vNodeHandle ); goto Exit; } Exit: return ( error ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Open - This routine opens a file //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Open ( struct vnop_open_args * openArgsPtr ) /* struct vnop_open_args { struct vnodeop_desc *a_desc; vnode_t a_vp; int a_mode; vfs_context_t a_context; }; */ { vnode_t vNodePtr = NULLVP; int error = 0; DebugLog ( ( "CDDA_Open: Entering.\n" ) ); DebugAssert ( ( openArgsPtr != NULL ) ); vNodePtr = openArgsPtr->a_vp; DebugAssert ( ( vNodePtr != NULL ) ); // Set the vNodeOperationType to tell the user process if we are going to open a // file or a directory if ( ! vnode_isreg ( vNodePtr ) && ! vnode_isdir ( vNodePtr ) ) { // This should never happen but just in case DebugLog ( ( "Error = %d, wrong vnode type.\n", ENOTSUP ) ); error = ENOTSUP; goto ERROR; } // Turn off speculative read-ahead for our vnodes. The cluster // code can't possibly do the right thing when we have possible // loss of streaming on CD media. vnode_setnoreadahead ( vNodePtr ); ERROR: DebugLog ( ( "CDDA_Open: exiting with error = %d.\n", error ) ); return ( error ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Close - This routine closes a file. Since we are a read-only // filesystem, we don't have any cleaning up to do. //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Close ( struct vnop_close_args * closeArgsPtr ) /* struct vnop_close_args { struct vnodeop_desc *a_desc; vnode_t a_vp; int a_fflag; vfs_context_t a_context; }; */ { DebugLog ( ( "CDDA_Close: Entering.\n" ) ); #if DEBUG DebugAssert ( ( closeArgsPtr != NULL ) ); #else #pragma unused ( closeArgsPtr ) #endif DebugLog ( ( "CDDA_Close: exiting...\n" ) ); return ( 0 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Read - This routine reads from a file //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Read ( struct vnop_read_args * readArgsPtr ) /* struct vnop_read_args { struct vnodeop_desc *a_desc; vnode_t a_vp; uio_t a_uio; int a_ioflag; vfs_context_t a_context; }; */ { 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 ) ); // Check to make sure we're operating on a regular file if ( ! vnode_isreg ( vNodePtr ) ) { DebugLog ( ( "CDDA_Read: not a file, exiting with error = %d.\n", EISDIR ) ); return ( EISDIR ); } // Check to make sure they asked for data if ( uio_resid ( uio ) == 0 ) { DebugLog ( ( "CDDA_Read: uio_resid = 0, no data requested" ) ); return ( 0 ); } // Can't read from a negative offset 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; // Check to make sure we don't read past EOF if ( uio_offset ( uio ) > numBytes ) { DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) ); return ( 0 ); } amountToCopy = ulmin ( uio_resid ( uio ), numBytes - offset ); uiomove ( ( caddr_t ) &cddaNodePtr->u.xmlFile.fileDataPtr[offset], amountToCopy, uio ); return ( 0 ); } else if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) { UInt32 headerSize = 0; UInt32 count = 0; UInt32 blockNumber = 0; off_t offset = 0; off_t sectorOffset = 0; buf_t bufPtr = NULL; offset = uio_offset ( uio ); // Check to make sure we don't read past EOF if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes ) { DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) ); return ( 0 ); } headerSize = sizeof ( cddaNodePtr->u.file.aiffHeader ); // Copy any part of the header that we need to copy. if ( offset < headerSize ) { UInt32 amountToCopy = 0; UInt8 * bytes = NULL; bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader; amountToCopy = ulmin ( uio_resid ( uio ), headerSize - offset ); uiomove ( ( caddr_t ) &bytes[offset], amountToCopy, uio ); offset += amountToCopy; } // Copy any part of the header pad that we need to copy. if ( ( uio_resid ( uio ) > 0 ) && ( offset < kPhysicalMediaBlockSize ) ) { UInt32 amountToCopy = 0; amountToCopy = ulmin ( uio_resid ( uio ), kPhysicalMediaBlockSize - offset ); uiomove ( ( caddr_t ) &gAIFFHeaderPadData[offset - headerSize], amountToCopy, uio ); offset += amountToCopy; } if ( ( uio_resid ( uio ) > 0 ) && ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { // Adjust offset by the header size so we have a true offset into the media. offset -= kPhysicalMediaBlockSize; sectorOffset = offset % kPhysicalMediaBlockSize; blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA; // Part 1 // We do the read in 3 parts. First is the portion which is not part of a full 2352 byte block. // In some cases, we actually are sector aligned and we skip this part. A lot of times we'll find // this sector incore as well, since it was part of third read for the previous I/O. if ( sectorOffset != 0 ) { // Clip to requested transfer count and end of file. count = ulmin ( uio_resid ( uio ), ( kPhysicalMediaBlockSize - sectorOffset ) ); count = ulmin ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); // Read the one sector error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, kPhysicalMediaBlockSize, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } // Move the data from the block into the buffer uiomove ( ( caddr_t ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ), count, uio ); // Make sure we mark this bp invalid as we don't need to keep it around anymore buf_markinvalid ( bufPtr ); // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); // Update offset blockNumber++; } // Part 2 // Now we execute the second part of the read. This will be the largest chunk of the read. // We will read multiple disc blocks up to MAXBSIZE bytes in a loop until we hit a chunk which // is less than one block size. That will be read in the third part. while ( ( uio_resid ( uio ) > kPhysicalMediaBlockSize ) && ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { UInt32 blocksToRead = 0; // Read in as close to MAXBSIZE chunks as possible if ( uio_resid ( uio ) > kMaxBytesPerRead ) { blocksToRead = kMaxBlocksPerRead; count = kMaxBytesPerRead; } else { blocksToRead = uio_resid ( uio ) / kPhysicalMediaBlockSize; count = blocksToRead * kPhysicalMediaBlockSize; } // read kMaxBlocksPerRead blocks and put them in the cache. error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, count, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } count = ulmin ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); // Move the data from the block into the buffer uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio ); // Make sure we mark any intermediate buffers as invalid as we don't need // to keep them. buf_markinvalid ( bufPtr ); // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); // Update offset blockNumber += blocksToRead; } // Part 3 // Now that we have read everything, we read the tail end which is a partial sector. // Sometimes we don't need to execute this step since there isn't a tail. if ( ( uio_resid ( uio ) > 0 ) && ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { count = ulmin ( uio_resid ( uio ), cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); // Read the one sector error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, kPhysicalMediaBlockSize, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } // Move the data from the block into the buffer uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio ); // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); } } } DebugLog ( ( "CDDA_Read: exiting.\n" ) ); return ( error ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_ReadDir - This routine reads the contents of a directory //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_ReadDir ( struct vnop_readdir_args * readDirArgsPtr ) /* struct vnop_readdir_args { struct vnodeop_desc *a_desc; vnode_t a_vp; uio_t a_uio; int a_flags; int *a_eofflag; int *a_numdirent; vfs_context_t a_context; }; */ { 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 ); // First make sure it is a directory we are dealing with 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 ); } // Make sure it's all one big buffer if ( uio_iovcnt ( uio ) > 1 ) { DebugLog ( ( "More than one buffer, exiting with error = %d.\n", EINVAL ) ); return ( EINVAL ); } // Make sure we don't return partial entries if ( ( uint32_t ) uio_resid ( uio ) < sizeof ( struct dirent ) ) { DebugLog ( ( "resid < dirent size, exiting with error = %d.\n", EINVAL ) ); return ( EINVAL ); } direntSize = sizeof ( struct dirent ); // Synthesize '.', "..", and ".TOC.plist" 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, kAppleCDDAXMLFileType, ".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 ) ) ); // OK, so much for the fakes. Now for the "real thing" // Loop over all the names in the NameArray to produce directory entries 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 ) ); // Return this entry offsetValue = AddDirectoryEntry ( nodeInfoArrayPtr->trackDescriptor.point, kAppleCDDATrackType, 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 ) ); // If we ran all the way through the list, there are no more *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 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_PageIn - This routine handles VM PageIn requests //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_PageIn ( struct vnop_pagein_args * pageInArgsPtr ) /* struct vnop_pagein_args { struct vnodeop_desc *a_desc; vnode_t a_vp; upl_t a_pl; vm_offset_t a_pl_offset; off_t a_f_offset; size_t a_size; int a_flags; vfs_context_t a_context; }; */ { 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 they didn't ask for any data, then we are done if ( pageInArgsPtr->a_size == 0 ) { if ( !nocommit ) { ubc_upl_abort_range ( pageInArgsPtr->a_pl, pageInArgsPtr->a_pl_offset, pageInArgsPtr->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY ); } return ( error ); } // Make sure we aren't reading from a negative offset if ( pageInArgsPtr->a_f_offset < 0 ) { if ( !nocommit ) { ubc_upl_abort_range ( pageInArgsPtr->a_pl, pageInArgsPtr->a_pl_offset, 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 ); } // Check to make sure we don't read past EOF if ( pageInArgsPtr->a_f_offset > numBytes ) { if ( !nocommit ) { ubc_upl_abort_range ( pageInArgsPtr->a_pl, pageInArgsPtr->a_pl_offset, pageInArgsPtr->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY ); } return ( error ); } // Workaround for faked ".TOC.plist" file if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) { kern_return_t kret = 0; vm_offset_t vmOffsetPtr = 0; off_t amountToCopy = 0; // Map the physical page into the kernel address space kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr ); // If we got an error or the vmOffsetPtr is zero, panic for now if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 ) { panic ( "CDDA_PageIn: error mapping buffer into kernel space!" ); } // Zero fill the page bzero ( ( caddr_t )( vmOffsetPtr + pageInArgsPtr->a_pl_offset ), PAGE_SIZE ); amountToCopy = ulmin ( PAGE_SIZE, numBytes - pageInArgsPtr->a_f_offset ); // Copy the file data bcopy ( &cddaNodePtr->u.xmlFile.fileDataPtr[pageInArgsPtr->a_f_offset], ( void * ) vmOffsetPtr, amountToCopy ); // Unmap the physical page from the kernel address space kret = ubc_upl_unmap ( pageInArgsPtr->a_pl ); // If we got an error, panic for now if ( kret != KERN_SUCCESS ) { panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" ); } if ( !nocommit ) { // Commit the page to the vm subsystem 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; UInt32 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; // Check to make sure we don't read past EOF if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes ) { DebugLog ( ( "CDDA_PageIn: Can't read past end of file..." ) ); return ( 0 ); } headerSize = sizeof ( cddaNodePtr->u.file.aiffHeader ); // Map the physical pages into the kernel address space kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr ); // If we got an error or the vmOffsetPtr is zero, panic for now if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 ) { panic ( "CDDA_PageIn: error mapping buffer into kernel space!" ); } // Account for the offset into the UPL. vmOffsetPtr += pageInArgsPtr->a_pl_offset; // Copy any part of the header that we need to copy. if ( offset < headerSize ) { off_t amountToCopy = 0; UInt8 * bytes = NULL; amountToCopy = ulmin ( pageInArgsPtr->a_size, headerSize - offset ); bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader; // Copy the header data bcopy ( &bytes[offset], ( void * ) vmOffsetPtr, amountToCopy ); offset += amountToCopy; residual -= amountToCopy; vmOffsetPtr += amountToCopy; } // Copy any part of the header pad that we need to copy. if ( ( residual > 0 ) && ( offset < kPhysicalMediaBlockSize ) ) { off_t amountToCopy = 0; amountToCopy = ulmin ( residual, kPhysicalMediaBlockSize - offset ); // Copy the header pad data (all zeroes). bcopy ( &gAIFFHeaderPadData[offset - headerSize], ( void * ) vmOffsetPtr, amountToCopy ); offset += amountToCopy; residual -= amountToCopy; vmOffsetPtr += amountToCopy; } if ( ( residual > 0 ) && ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { // Adjust offset by the size of header + header pad so we have a true offset into the media. offset -= kPhysicalMediaBlockSize; sectorOffset = offset % kPhysicalMediaBlockSize; blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA; // Part 1 // We do the read in 3 parts. First is the portion which is not part of a full 2352 byte block. // In some cases, we actually are sector aligned and we skip this part. A lot of times we'll find // this sector incore as well, since it was part of third read for the previous I/O. if ( sectorOffset != 0 ) { // Clip to requested transfer count and end of file. count = ulmin ( residual, ( kPhysicalMediaBlockSize - sectorOffset ) ); count = ulmin ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); // Read the one sector error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, kPhysicalMediaBlockSize, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } // Copy the data bcopy ( ( void * ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ), ( void * ) vmOffsetPtr, count ); // Increment/decrement counters offset += count; residual -= count; vmOffsetPtr += count; // Make sure we mark this bp invalid as we don't need to keep it around anymore buf_markinvalid ( bufPtr ); // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); // Update offset blockNumber++; } // Part 2 // Now we execute the second part of the read. This will be the largest chunk of the read. // We will read multiple disc blocks up to MAXBSIZE bytes in a loop until we hit a chunk which // is less than one block size. That will be read in the third part. while ( ( residual > kPhysicalMediaBlockSize ) && ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { UInt32 blocksToRead = 0; // Read in as close to MAXBSIZE chunks as possible if ( residual > kMaxBytesPerRead ) { blocksToRead = kMaxBlocksPerRead; count = kMaxBytesPerRead; } else { blocksToRead = residual / kPhysicalMediaBlockSize; count = blocksToRead * kPhysicalMediaBlockSize; } // read kMaxBlocksPerRead blocks and put them in the cache. error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, count, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } count = ulmin ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); // Copy the data bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count ); // Increment/decrement counters offset += count; residual -= count; vmOffsetPtr += count; // Make sure we mark any intermediate buffers as invalid as we don't need // to keep them. buf_markinvalid ( bufPtr ); // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); // Update offset blockNumber += blocksToRead; } // Part 3 // Now that we have read everything, we read the tail end which is a partial sector. // Sometimes we don't need to execute this step since there isn't a tail. if ( ( residual > 0 ) && ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) { count = ulmin ( residual, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); // Read the one sector error = ( int ) buf_bread ( cddaNodePtr->blockDeviceVNodePtr, blockNumber, kPhysicalMediaBlockSize, NOCRED, &bufPtr ); if ( error != 0 ) { buf_brelse ( bufPtr ); return ( error ); } // Copy the data bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count ); // Increment/decrement counters offset += count; residual -= count; vmOffsetPtr += count; // Release this buffer back into the buffer pool. buf_brelse ( bufPtr ); } } // Unmap the physical page from the kernel address space kret = ubc_upl_unmap ( pageInArgsPtr->a_pl ); // If we got an error, panic for now if ( kret != KERN_SUCCESS ) { panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" ); } if ( !nocommit ) { // Commit the page to the vm subsystem ubc_upl_commit_range ( pageInArgsPtr->a_pl, pageInArgsPtr->a_pl_offset, pageInArgsPtr->a_size, UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_CLEAR_DIRTY ); } } DebugLog ( ( "CDDA_PageIn: exiting...\n" ) ); return ( error ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_GetAttributes - This routine gets the attributes for a folder/file //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_GetAttributes ( struct vnop_getattr_args * getAttrArgsPtr ) /* struct vnop_getattr_args { struct vnodeop_desc *a_desc; vnode_t a_vp; struct vnode_attr *a_vap; vfs_context_t a_context; }; */ { 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 ) ); // Special case root since we know how to get its name if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType ) { // Set the nodeID. Force root to be 2. VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDARootFileID ); } // Special case the XMLFileNode else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) { // Set the nodeID. Force the XMLFileNode to be 3. VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDAXMLFileID ); } else { // Set the nodeID. VATTR_RETURN ( attributesPtr, va_fileid, cddaNodePtr->nodeID ); } if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType ) { // If this is the root directory and they want the parent, force it to 1 VATTR_RETURN ( attributesPtr, va_parentid, 1 ); } else { // Every other object has the root as its parent (flat filesystem) VATTR_RETURN ( attributesPtr, va_parentid, kAppleCDDARootFileID ); } VATTR_RETURN ( attributesPtr, va_type, vnode_vtype ( vNodePtr ) ); // Set the VNode type (e.g. VREG, VDIR) VATTR_RETURN ( attributesPtr, va_iosize, kPhysicalMediaBlockSize ); // Set preferred block size for I/O requests // Set all the time fields VATTR_RETURN ( attributesPtr, va_create_time, cddaMountPtr->mountTime ); // Creation time VATTR_RETURN ( attributesPtr, va_modify_time, cddaMountPtr->mountTime ); // Last modification time VATTR_RETURN ( attributesPtr, va_change_time, nullTime ); // Last change time VATTR_RETURN ( attributesPtr, va_access_time, nullTime ); // Last accessed time VATTR_RETURN ( attributesPtr, va_backup_time, nullTime ); // Backup time // These fields are the same VATTR_RETURN ( attributesPtr, va_fsid, vfs_statfs ( mountPtr )->f_fsid.val[0] ); VATTR_RETURN ( attributesPtr, va_uid, kUnknownUserID ); // "unknown" VATTR_RETURN ( attributesPtr, va_gid, kUnknownGroupID ); // "unknown" 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 ); // Set some common mode flags. // Read is ok for user, group, other. VATTR_RETURN ( attributesPtr, va_mode, S_IRUSR | S_IRGRP | S_IROTH ); // If it's the root, set some flags for it. if ( vnode_isvroot ( vNodePtr ) ) { attributesPtr->va_mode |= S_IFDIR; // It's a directory attributesPtr->va_mode |= S_IXUSR | S_IXGRP | S_IXOTH; // Execute is ok for user, group, other // Number of file refs: "." and ".." VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfRootDirReferences ); // Number of Tracks + ".", "..", and ".TOC.plist" VATTR_RETURN ( attributesPtr, va_data_size, ( cddaNodePtr->u.directory.entryCount ) * sizeof ( struct dirent ) ); } // If it isn't the root vnode, it's a file. else { // It's a file... attributesPtr->va_mode |= DEFFILEMODE; // Just the file itself VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfFileReferences ); // Is it a track? if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) { // Set file size in bytes VATTR_RETURN ( attributesPtr, va_data_size, cddaNodePtr->u.file.nodeInfoPtr->numBytes ); VATTR_RETURN ( attributesPtr, va_data_alloc, cddaNodePtr->u.file.nodeInfoPtr->numBytes ); } // Is it the ".TOC.plist" file? else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) { // Set file size in bytes. 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 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Inactive - This routine simply unlocks a vnode. //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Inactive ( struct vnop_inactive_args * inactiveArgsPtr ) /* struct vnop_inactive_args { struct vnodeop_desc *a_desc; vnode_t a_vp; vfs_context_t a_context; }; */ { DebugLog ( ( "CDDA_Inactive: Entering.\n" ) ); DebugAssert ( ( inactiveArgsPtr != NULL ) ); // We don't do anything special, so call VFS function to handle it ( void ) nop_inactive ( inactiveArgsPtr ); DebugLog ( ( "CDDA_Inactive: exiting...\n" ) ); return ( 0 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Remove - This routine removes a file from the name space. Since we // are a read-only volume, we release any locks if appropriate // and return EROFS //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Remove ( struct vnop_remove_args * removeArgsPtr ) /* struct vnop_remove_args { struct vnodeop_desc *a_desc; vnode_t a_dvp; vnode_t a_vp; struct componentname *a_cnp; int a_flags; vfs_context_t a_context; }; */ { DebugLog ( ( "CDDA_Remove: Entering.\n" ) ); DebugAssert ( ( removeArgsPtr != NULL ) ); // We don't do anything special, so call VFS function to handle it ( void ) nop_remove ( removeArgsPtr ); DebugLog ( ( "CDDA_Remove: exiting...\n" ) ); // Return the read-only filesystem error return ( EROFS ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_RmDir - This routine removes a directory from the name space. // Since we are a read-only volume, we release any locks // and return EROFS //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_RmDir ( struct vnop_rmdir_args * removeDirArgsPtr ) /* struct vnop_rmdir_args { struct vnodeop_desc *a_desc; vnode_t a_dvp; vnode_t a_vp; struct componentname *a_cnp; vfs_context_t a_context; }; */ { DebugLog ( ( "CDDA_RmDir: Entering.\n" ) ); DebugAssert ( ( removeDirArgsPtr != NULL ) ); // Call nop_rmdir to release locks ( void ) nop_rmdir ( removeDirArgsPtr ); DebugLog ( ( "CDDA_RmDir: exiting...\n" ) ); // Return the read-only filesystem error return ( EROFS ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Reclaim - This routine reclaims a vnode for use by the system. // // Remove the vnode from our node info array, drop the fs reference, // free our private data. //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Reclaim ( struct vnop_reclaim_args * reclaimArgsPtr ) /* struct vnop_reclaim_args { struct vnodeop_desc *a_desc; vnode_t a_vp; vfs_context_t a_context; }; */ { 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 ); // Release our reference on this node vnode_removefsref ( vNodePtr ); error = DisposeCDDANode ( vNodePtr ); DebugLog ( ( "CDDA_Reclaim: exiting...\n" ) ); return ( error ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_BlockToOffset - This routine converts logical block number to file // offset //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_BlockToOffset ( struct vnop_blktooff_args * blockToOffsetArgsPtr ) /* struct vnop_blktooff_args { struct vnodeop_desc *a_desc; vnode_t a_vp; daddr64_t a_lblkno; off_t *a_offset; }; */ { 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 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_OffsetToBlock - This routine converts a file offset to a logical // block number //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_OffsetToBlock ( struct vnop_offtoblk_args * offsetToBlockArgsPtr ) /* struct vnop_offtoblk_args { struct vnodeop_desc *a_desc; vnode_t a_vp; off_t a_offset; daddr64_t *a_lblkno; }; */ { 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 ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_Pathconf - Return POSIX pathconf information applicable to // special devices //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_Pathconf ( struct vnop_pathconf_args * pathConfArgsPtr ) /* struct vnop_pathconf_args { struct vnodeop_desc *a_desc; vnode_t a_vp; int a_name; register_t *a_retval; vfs_context_t a_context; }; */ { 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; default: returnValue = EINVAL; break; } DebugLog ( ( "CDDA_Pathconf: exiting with returnValue = %d.\n", returnValue ) ); return ( returnValue ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // CDDA_GetXAttr - Handles extended attribute reads. // In this case, just for FinderInfo. //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int CDDA_GetXAttr ( struct vnop_getxattr_args * getXAttrArgsPtr ) /* struct vnop_getxattr_args { struct vnodeop_desc *a_desc; vnode_t a_vp; char * a_name; uio_t a_uio; size_t *a_size; int a_options; vfs_context_t a_context; }; */ { AppleCDDANodePtr cddaNodePtr = NULL; FinderInfo * finderInfoPtr = NULL; char buf[32] = { 0 }; DebugLog ( ( "CDDA_GetXAttr: Entering.\n" ) ); DebugAssert ( ( getXAttrArgsPtr != NULL ) ); if ( strcmp ( getXAttrArgsPtr->a_name, 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" ) ); // Make the XML file invisible 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; } // Swap FinderInfo into big endian. FinderInfo must always be big endian when passed // back and forth across the kernel using getattrlist/getxattr. 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, sizeof ( buf ), getXAttrArgsPtr->a_uio ) ); } //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // Other macro'd function definitions //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ int ( **gCDDA_VNodeOp_p )( void * ); typedef int (*VNOPFUNC) ( void * ); #if 0 #pragma mark - #endif //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // VNode Operation Vector Entry Description (Dispatch Table) //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ struct vnodeopv_entry_desc gCDDA_VNodeOperationEntries[] = { { &vnop_default_desc, ( VNOPFUNC ) vn_default_error }, { &vnop_lookup_desc, ( VNOPFUNC ) CDDA_Lookup }, // lookup { &vnop_open_desc, ( VNOPFUNC ) CDDA_Open }, // open { &vnop_close_desc, ( VNOPFUNC ) CDDA_Close }, // close { &vnop_getattr_desc, ( VNOPFUNC ) CDDA_GetAttributes }, // getattr { &vnop_setattr_desc, ( VNOPFUNC ) nop_setattr }, // setattr { &vnop_read_desc, ( VNOPFUNC ) CDDA_Read }, // read { &vnop_fsync_desc, ( VNOPFUNC ) nop_fsync }, // fsync { &vnop_remove_desc, ( VNOPFUNC ) CDDA_Remove }, // remove { &vnop_rmdir_desc, ( VNOPFUNC ) CDDA_RmDir }, // rmdir { &vnop_readdir_desc, ( VNOPFUNC ) CDDA_ReadDir }, // readdir { &vnop_inactive_desc, ( VNOPFUNC ) CDDA_Inactive }, // inactive { &vnop_reclaim_desc, ( VNOPFUNC ) CDDA_Reclaim }, // reclaim { &vnop_pathconf_desc, ( VNOPFUNC ) CDDA_Pathconf }, // pathconf { &vnop_pagein_desc, ( VNOPFUNC ) CDDA_PageIn }, // pagein { &vnop_blktooff_desc, ( VNOPFUNC ) CDDA_BlockToOffset }, // blktoff { &vnop_offtoblk_desc, ( VNOPFUNC ) CDDA_OffsetToBlock }, // offtoblk { &vnop_getxattr_desc, ( VNOPFUNC ) CDDA_GetXAttr }, // getxattr { NULL, ( VNOPFUNC ) NULL } }; struct vnodeopv_desc gCDDA_VNodeOperationsDesc = { &gCDDA_VNodeOp_p, gCDDA_VNodeOperationEntries }; //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ // End Of File //ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ