1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// AppleCDDAFileSystemVFSOps.c created by CJS on Mon 10-Apr-2000 26 27 28// System Includes 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/proc.h> 32#include <sys/vnode.h> 33#include <sys/mount.h> 34#include <sys/buf.h> 35#include <sys/malloc.h> 36#include <sys/ubc.h> 37#include <mach/kmod.h> 38#include <libkern/OSKextLib.h> 39 40// Project Includes 41#ifndef __APPLE_CDDA_FS_VFS_OPS_H__ 42#include "AppleCDDAFileSystemVFSOps.h" 43#endif 44 45#ifndef __APPLE_CDDA_FS_VNODE_OPS_H__ 46#include "AppleCDDAFileSystemVNodeOps.h" 47#endif 48 49#ifndef __APPLE_CDDA_FS_DEBUG_H__ 50#include "AppleCDDAFileSystemDebug.h" 51#endif 52 53#ifndef __APPLE_CDDA_FS_DEFINES_H__ 54#include "AppleCDDAFileSystemDefines.h" 55#endif 56 57#ifndef __APPLE_CDDA_FS_UTILS_H__ 58#include "AppleCDDAFileSystemUtils.h" 59#endif 60 61#ifndef __AIFF_SUPPORT_H__ 62#include "AIFFSupport.h" 63#endif 64 65 66//----------------------------------------------------------------------------- 67// Globals 68//----------------------------------------------------------------------------- 69 70 71// Global variables defined in other modules 72extern struct vnodeopv_desc gCDDA_VNodeOperationsDesc; 73 74// CDDA File System globals 75static char gAppleCDDAName[MFSNAMELEN] = "cddafs"; 76 77static vfstable_t gCDDA_VFSTableEntry; 78static struct vnodeopv_desc * gCDDA_VNodeOperationsDescList[1] = 79{ 80 &gCDDA_VNodeOperationsDesc 81}; 82 83// vfsops 84struct vfsops gCDDA_VFSOps = 85{ 86 CDDA_Mount, 87 0, // start 88 CDDA_Unmount, 89 CDDA_Root, 90 0, // quotactl 91 CDDA_VFSGetAttributes, 92 0, // synchronize 93 CDDA_VGet, 94 0, // fhtovp 95 0, // vptofh 96 0, // init 97 0, // sysctl 98 0, // setattr 99 { 0 } // reserved 100}; 101 102static void 103FindVolumeName ( const char * mn, const char ** np, ssize_t * nl ); 104 105 106//----------------------------------------------------------------------------- 107// CDDA_Mount - This routine is responsible for mounting the filesystem 108// in the desired path 109//----------------------------------------------------------------------------- 110 111int 112CDDA_Mount ( mount_t mountPtr, 113 vnode_t blockDeviceVNodePtr, 114 user_addr_t data, 115 vfs_context_t context ) 116{ 117 118#pragma unused ( context ) 119 120 AppleCDDAMountPtr cddaMountPtr = NULL; 121 AppleCDDANodePtr cddaNodePtr = NULL; 122 void * xmlData = NULL; 123 int error = 0; 124 AppleCDDAArguments cddaArgs; 125 struct timeval now; 126 struct timespec timespec; 127 128 OSKextRetainKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) ); 129 130 bzero ( &cddaArgs, sizeof ( cddaArgs ) ); 131 bzero ( &now, sizeof ( now ) ); 132 bzero ( ×pec, sizeof ( timespec ) ); 133 134 DebugLog ( ( "CDDA_Mount: Entering.\n" ) ); 135 136 DebugAssert ( ( mountPtr != NULL ) ); 137 DebugAssert ( ( context != NULL ) ); 138 139 error = copyin ( data, ( caddr_t ) &cddaArgs, sizeof ( cddaArgs ) ); 140 if ( error != 0 ) 141 { 142 143 DebugLog ( ( "CDDA_Mount: copyin error = %d\n", error ) ); 144 goto ERROR; 145 146 } 147 148 if ( ( vfs_isrdwr ( mountPtr ) ) != 0 ) 149 { 150 151 DebugLog ( ( "Returning EROFS...\n" ) ); 152 error = EROFS; 153 goto ERROR; 154 155 } 156 157 // Update is a no-op 158 if ( vfs_isupdate ( mountPtr ) ) 159 { 160 161 DebugLog ( ( "Returning ENOTSUP...\n" ) ); 162 error = ENOTSUP; 163 goto ERROR; 164 165 } 166 167 if ( ( cddaArgs.nameData == USER_ADDR_NULL ) || ( cddaArgs.xmlData == USER_ADDR_NULL ) ) 168 { 169 170 DebugLog ( ( "cddaArgs.nameData = 0x%qX, cddaArgs.xmlData = 0x%qX, Returning EINVAL...\n", cddaArgs.nameData, cddaArgs.xmlData ) ); 171 error = EINVAL; 172 goto ERROR; 173 174 } 175 176 if ( ( cddaArgs.nameDataSize == 0 ) || ( cddaArgs.nameDataSize > kMaxNameDataSize ) ) 177 { 178 179 DebugLog ( ( "cddaArgs.nameDataSize = %u, invalid, Returning EINVAL...\n", cddaArgs.nameDataSize ) ); 180 error = EINVAL; 181 goto ERROR; 182 183 } 184 185 if ( ( cddaArgs.xmlFileSize == 0 ) || ( cddaArgs.xmlFileSize > kMaxXMLDataSize ) ) 186 { 187 188 DebugLog ( ( "cddaArgs.xmlFileSize = %u, invalid, Returning EINVAL...\n", cddaArgs.xmlFileSize ) ); 189 error = EINVAL; 190 goto ERROR; 191 192 } 193 194 // Allocate memory for private mount data 195 MALLOC ( cddaMountPtr, AppleCDDAMountPtr, sizeof ( AppleCDDAMount ), M_TEMP, M_WAITOK ); 196 197 // Zero the structure 198 bzero ( cddaMountPtr, sizeof ( AppleCDDAMount ) ); 199 200 // Initialize the lock 201 cddaMountPtr->cddaMountLockGroupAttr = lck_grp_attr_alloc_init ( ); 202 cddaMountPtr->cddaMountLockGroup = lck_grp_alloc_init ( "cddafs mount structure", cddaMountPtr->cddaMountLockGroupAttr ); 203 cddaMountPtr->cddaMountLockAttr = lck_attr_alloc_init ( ); 204 cddaMountPtr->cddaMountLock = lck_mtx_alloc_init ( cddaMountPtr->cddaMountLockGroup, cddaMountPtr->cddaMountLockAttr ); 205 206 // Save the number of audio tracks 207 cddaMountPtr->numTracks = cddaArgs.numTracks; 208 209 // Save file TYPE/CREATOR 210 cddaMountPtr->fileType = cddaArgs.fileType; 211 cddaMountPtr->fileCreator = cddaArgs.fileCreator; 212 213 // Allocate memory for NodeInfo array 214 MALLOC ( cddaMountPtr->nodeInfoArrayPtr, AppleCDDANodeInfoPtr, 215 sizeof ( AppleCDDANodeInfo ) * cddaMountPtr->numTracks, M_TEMP, M_WAITOK ); 216 217 // Zero the array 218 bzero ( cddaMountPtr->nodeInfoArrayPtr, sizeof ( AppleCDDANodeInfo ) * cddaMountPtr->numTracks ); 219 220 // Fill in the mount time 221 microtime ( &now ); 222 TIMEVAL_TO_TIMESPEC ( &now, ×pec ); 223 cddaMountPtr->mountTime = timespec; 224 225 // Allocate memory for CD Track Names data 226 MALLOC ( cddaMountPtr->nameData, UInt8 *, cddaArgs.nameDataSize, M_TEMP, M_WAITOK ); 227 cddaMountPtr->nameDataSize = cddaArgs.nameDataSize; 228 229 DebugLog ( ( "cddaMountPtr->nameData = %p, cddaMountPtr->nameDataSize = %d\n", cddaMountPtr->nameData, cddaMountPtr->nameDataSize ) ); 230 231 error = copyin ( cddaArgs.nameData, ( caddr_t ) cddaMountPtr->nameData, cddaMountPtr->nameDataSize ); 232 if ( error != 0 ) 233 { 234 235 DebugLog ( ( "CDDA_Mount: copyin failed with error = %d.\n", error ) ); 236 goto FREE_NODE_INFO_ERROR; 237 238 } 239 240 error = CreateNewCDDADirectory ( mountPtr, 241 kAppleCDDARootFileID, 242 &cddaMountPtr->root ); 243 244 if ( error != 0 ) 245 { 246 247 // XXX fix error to return a valid error number here 248 DebugLog ( ( "Returning error = %d after CreateNewCDDADirectory.\n", error ) ); 249 goto FREE_TRACK_NAMES; 250 251 } 252 253 // Cache the vid for the root vnode. 254 cddaMountPtr->rootVID = vnode_vid ( cddaMountPtr->root ); 255 256 // Set the root vnode's blockDeviceVNodePtr 257 cddaNodePtr = VTOCDDA ( cddaMountPtr->root ); 258 cddaNodePtr->blockDeviceVNodePtr = blockDeviceVNodePtr; 259 260 vfs_setflags ( mountPtr, ( MNT_LOCAL | MNT_RDONLY | MNT_DOVOLFS ) ); // Local Read-Only FileSystem 261 vfs_setfsprivate ( mountPtr, ( void * ) cddaMountPtr ); // Hang our data off the MountPoint 262 263 // Get a filesystem ID for us 264 vfs_getnewfsid ( mountPtr ); 265 266 // Allocate memory for xml data 267 MALLOC ( xmlData, void *, cddaArgs.xmlFileSize, M_TEMP, M_WAITOK ); 268 269 error = copyin ( cddaArgs.xmlData, ( caddr_t ) xmlData, cddaArgs.xmlFileSize ); 270 if ( error != 0 ) 271 { 272 273 DebugLog ( ( "CDDA_Mount: copyin 2 failed with error = %d.\n", error ) ); 274 goto FREE_ROOT_DIRECTORY; 275 276 } 277 278 cddaMountPtr->xmlData = xmlData; 279 cddaMountPtr->xmlDataSize = cddaArgs.xmlFileSize; 280 281 // Parse the TOC of the CD and build the tracks 282 error = ParseTOC ( mountPtr, cddaMountPtr->numTracks ); 283 if ( error != 0 ) 284 { 285 286 DebugLog ( ( "CDDA_Mount: Error = %d returned from ParseTOC.\n", error ) ); 287 goto FREE_ROOT_DIRECTORY; 288 289 } 290 291 // Keep a reference on the root directory, and unlock it 292 vnode_ref ( cddaMountPtr->root ); 293 vnode_put ( cddaMountPtr->root ); 294 295 DebugLog ( ( "CDDA_Mount: Exiting CDDA_Mount.\n" ) ); 296 297 return ( 0 ); 298 299 300FREE_ROOT_DIRECTORY: 301 302 303 if ( cddaMountPtr->root != NULL ) 304 { 305 306 // Release the root directory vnode we got above 307 vnode_put ( cddaMountPtr->root ); 308 309 } 310 311 312FREE_TRACK_NAMES: 313 314 315 if ( cddaMountPtr->nameData != NULL ) 316 { 317 318 FREE ( ( caddr_t ) cddaMountPtr->nameData, M_TEMP ); 319 cddaMountPtr->nameData = NULL; 320 cddaMountPtr->nameDataSize = 0; 321 322 } 323 324 325FREE_NODE_INFO_ERROR: 326 327 328 if ( cddaMountPtr->nodeInfoArrayPtr != NULL ) 329 { 330 331 // Free memory allocated for NodeInfo array 332 FREE ( ( caddr_t ) cddaMountPtr->nodeInfoArrayPtr, M_TEMP ); 333 cddaMountPtr->nodeInfoArrayPtr = NULL; 334 335 } 336 337 338 if ( cddaMountPtr != NULL ) 339 { 340 341 // Free memory allocated for mount structure 342 FREE ( ( caddr_t ) cddaMountPtr, M_TEMP ); 343 cddaMountPtr = NULL; 344 345 } 346 347 348ERROR: 349 350 351 OSKextReleaseKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) ); 352 353 return error; 354 355} 356 357 358//----------------------------------------------------------------------------- 359// CDDA_Unmount - This routine is called to unmount the disc at the 360// specified mount point 361//----------------------------------------------------------------------------- 362 363int 364CDDA_Unmount ( mount_t mountPtr, 365 int theFlags, 366 unused vfs_context_t context ) 367{ 368 369 vnode_t rootVNodePtr = NULLVP; 370 AppleCDDAMountPtr cddaMountPtr = NULL; 371 AppleCDDANodePtr cddaNodePtr = NULL; 372 AppleCDDANodeInfoPtr nodeInfoArrayPtr = NULL; 373 UInt8 * nameData = NULL; 374 UInt8 * xmlData = NULL; 375 int error = 0; 376 int flags = 0; 377 378 DebugLog ( ( "CDDA_Unmount: Entering.\n" ) ); 379 380 DebugAssert ( ( mountPtr != NULL ) ); 381 DebugAssert ( ( context != NULL ) ); 382 383 cddaMountPtr = VFSTOCDDA ( mountPtr ); 384 DebugAssert ( ( cddaMountPtr != NULL ) ); 385 386 rootVNodePtr = cddaMountPtr->root; 387 DebugAssert ( ( rootVNodePtr != NULL ) ); 388 389 cddaNodePtr = VTOCDDA ( rootVNodePtr ); 390 DebugAssert ( ( cddaNodePtr != NULL ) ); 391 392 if ( theFlags & MNT_FORCE ) 393 { 394 395 DebugLog ( ( "CDDA_Unmount: Setting forceclose.\n" ) ); 396 flags |= FORCECLOSE; 397 398 } 399 400 DebugAssert ( ( rootVNodePtr != NULL ) ); 401 402 // Check for open files 403 error = vflush ( mountPtr, rootVNodePtr, flags ); 404 if ( error != 0 ) 405 { 406 407 DebugLog ( ( "CDDA_Unmount: Returning error = %d after vflush.\n", error ) ); 408 return ( error ); 409 410 } 411 412 // Release the underlying root vnode 413 vnode_rele ( rootVNodePtr ); 414 415 error = vflush ( mountPtr, NULLVP, FORCECLOSE ); 416 if ( error != 0 ) 417 { 418 419 DebugLog ( ( "CDDA_Unmount: Returning error = %d after vflush.\n", error ) ); 420 return ( error ); 421 422 } 423 424 DebugLog ( ( "CDDA_Unmount: released the root vnode.\n" ) ); 425 DebugLog ( ( "CDDA_Unmount: All vnodes killed!\n" ) ); 426 427 // Get a pointer to the name data 428 nameData = VFSTONAMEINFO ( mountPtr ); 429 430 // Get a pointer to the XML data 431 xmlData = VFSTOXMLDATA ( mountPtr ); 432 433 DebugLog ( ( "CDDA_Unmount: Free the name data.\n" ) ); 434 435 // Free the name data 436 FREE ( ( caddr_t ) nameData, M_TEMP ); 437 438 DebugLog ( ( "CDDA_Unmount: Free the XML data.\n" ) ); 439 440 // Free the XML data 441 FREE ( ( caddr_t ) xmlData, M_TEMP ); 442 443 // Get a pointer to the NodeInfo Array 444 nodeInfoArrayPtr = VFSTONODEINFO ( mountPtr ); 445 446 DebugLog ( ( "CDDA_Unmount: Free the nodeinfo array.\n" ) ); 447 448 // Free the NodeInfo Array we allocated at mount time 449 FREE ( nodeInfoArrayPtr, M_TEMP ); 450 451 DebugLog ( ( "CDDA_Unmount: Free the nodeinfo lock.\n" ) ); 452 453 lck_mtx_free ( cddaMountPtr->cddaMountLock, cddaMountPtr->cddaMountLockGroup ); 454 lck_attr_free ( cddaMountPtr->cddaMountLockAttr ); 455 lck_grp_free ( cddaMountPtr->cddaMountLockGroup ); 456 lck_grp_attr_free ( cddaMountPtr->cddaMountLockGroupAttr ); 457 458 DebugLog ( ( "CDDA_Unmount: Free the mount point data.\n" ) ); 459 460 // Finally, free the mount-specific data we allocated at mount time 461 FREE ( vfs_fsprivate ( mountPtr ), M_TEMP ); 462 463 // Point the pointer to nothing 464 vfs_setfsprivate ( mountPtr, NULL ); 465 466 DebugLog ( ( "CDDA_Unmount: Exiting, returning error = %d.\n", error ) ); 467 468 OSKextReleaseKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) ); 469 470 return 0; 471 472} 473 474 475//----------------------------------------------------------------------------- 476// CDDA_Root - This routine is called to get a vnode pointer to the root 477// vnode of the filesystem 478//----------------------------------------------------------------------------- 479 480int 481CDDA_Root ( mount_t mountPtr, 482 vnode_t * vNodeHandle, 483 vfs_context_t context ) 484{ 485 486 int error = 0; 487 ino64_t inode = kAppleCDDARootFileID; 488 489 DebugLog ( ( "CDDA_Root: Entering.\n" ) ); 490 491 DebugAssert ( ( mountPtr != NULL ) ); 492 DebugAssert ( ( vNodeHandle != NULL ) ); 493 DebugAssert ( ( context != NULL ) ); 494 495 error = CDDA_VGet ( mountPtr, inode, vNodeHandle, context ); 496 497 DebugLog ( ( "CDDA_Root: exiting...\n" ) ); 498 499 return ( error ); 500 501} 502 503 504//----------------------------------------------------------------------------- 505// CDDA_VFSGetAttributes - This routine is called to get filesystem attributes. 506//----------------------------------------------------------------------------- 507 508int 509CDDA_VFSGetAttributes ( mount_t mountPtr, 510 struct vfs_attr * attrPtr, 511 unused vfs_context_t context ) 512{ 513 514 AppleCDDAMountPtr cddaMountPtr = NULL; 515 AppleCDDANodePtr rootCDDANodePtr = NULL; 516 vol_capabilities_attr_t * capabilities = NULL; 517 vol_attributes_attr_t * attributes = NULL; 518 519 DebugLog ( ( "CDDA_VFSGetAttributes: Entering.\n" ) ); 520 521 DebugAssert ( ( mountPtr != NULL ) ); 522 DebugAssert ( ( attrPtr != NULL ) ); 523 524 capabilities = &attrPtr->f_capabilities; 525 attributes = &attrPtr->f_attributes; 526 527 cddaMountPtr = VFSTOCDDA ( mountPtr ); 528 DebugAssert ( ( cddaMountPtr != NULL ) ); 529 530 rootCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); 531 DebugAssert ( ( rootCDDANodePtr != NULL ) ); 532 533 DebugAssert ( ( rootCDDANodePtr->nodeType == kAppleCDDADirectoryType ) ); 534 535 // 536 // The +1's below are to account for the ".TOC.plist" file 537 // 538 VFSATTR_RETURN ( attrPtr, f_objcount, cddaMountPtr->numTracks + 1 ); 539 VFSATTR_RETURN ( attrPtr, f_filecount, cddaMountPtr->numTracks + 1 ); 540 VFSATTR_RETURN ( attrPtr, f_dircount, 0 ); 541 VFSATTR_RETURN ( attrPtr, f_maxobjcount, cddaMountPtr->numTracks + 1 ); 542 VFSATTR_RETURN ( attrPtr, f_iosize, kMaxBytesPerRead * 2 ); 543 VFSATTR_RETURN ( attrPtr, f_blocks, rootCDDANodePtr->u.directory.directorySize / kPhysicalMediaBlockSize ); 544 VFSATTR_RETURN ( attrPtr, f_bfree, 0 ); 545 VFSATTR_RETURN ( attrPtr, f_bavail, 0 ); 546 VFSATTR_RETURN ( attrPtr, f_bused, attrPtr->f_blocks ); 547 VFSATTR_RETURN ( attrPtr, f_files, rootCDDANodePtr->u.directory.entryCount ); 548 VFSATTR_RETURN ( attrPtr, f_ffree, 0 ); 549 VFSATTR_RETURN ( attrPtr, f_bsize, kPhysicalMediaBlockSize ); 550 551 VFSATTR_RETURN ( attrPtr, f_create_time, cddaMountPtr->mountTime ); 552 VFSATTR_RETURN ( attrPtr, f_modify_time, cddaMountPtr->mountTime ); 553 554 if ( VFSATTR_IS_ACTIVE ( attrPtr, f_backup_time ) ) 555 { 556 557 attrPtr->f_backup_time.tv_sec = 0; 558 attrPtr->f_backup_time.tv_nsec = 0; 559 VFSATTR_SET_SUPPORTED ( attrPtr, f_backup_time ); 560 561 } 562 563 if ( VFSATTR_IS_ACTIVE ( attrPtr, f_vol_name ) ) 564 { 565 566 const char * vname = NULL; 567 ssize_t length = 0; 568 569 FindVolumeName ( vfs_statfs ( mountPtr )->f_mntonname, &vname, &length ); 570 571 if ( vname != NULL ) 572 { 573 574 strlcpy ( attrPtr->f_vol_name, vname, MAXPATHLEN ); 575 VFSATTR_SET_SUPPORTED ( attrPtr, f_vol_name ); 576 577 } 578 579 } 580 581 // XXX these will go away soon 582 VFSATTR_RETURN ( attrPtr, f_fsid, vfs_statfs ( mountPtr )->f_fsid ); 583 584 // Set the signature to 'BD'. 585 VFSATTR_RETURN ( attrPtr, f_signature, kAppleCDDAFileSystemVolumeSignature ); 586 587 // Set the carbon FSID to 'JH'. 588 VFSATTR_RETURN ( attrPtr, f_carbon_fsid, kAppleCDDAFileSystemVCBFSID ); 589 590 // We understand the following. 591 capabilities->valid[VOL_CAPABILITIES_FORMAT] = 592 VOL_CAP_FMT_PERSISTENTOBJECTIDS | 593 VOL_CAP_FMT_SYMBOLICLINKS | 594 VOL_CAP_FMT_HARDLINKS | 595 VOL_CAP_FMT_JOURNAL | 596 VOL_CAP_FMT_JOURNAL_ACTIVE | 597 VOL_CAP_FMT_NO_ROOT_TIMES | 598 VOL_CAP_FMT_SPARSE_FILES | 599 VOL_CAP_FMT_ZERO_RUNS | 600 VOL_CAP_FMT_CASE_SENSITIVE | 601 VOL_CAP_FMT_CASE_PRESERVING | 602 VOL_CAP_FMT_FAST_STATFS | 603 VOL_CAP_FMT_PATH_FROM_ID; 604 605 // We understand the following interfaces. 606 capabilities->valid[VOL_CAPABILITIES_INTERFACES] = 607 VOL_CAP_INT_SEARCHFS | 608 VOL_CAP_INT_ATTRLIST | 609 VOL_CAP_INT_NFSEXPORT | 610 VOL_CAP_INT_READDIRATTR | 611 VOL_CAP_INT_EXCHANGEDATA | 612 VOL_CAP_INT_COPYFILE | 613 VOL_CAP_INT_ALLOCATE | 614 VOL_CAP_INT_VOL_RENAME | 615 VOL_CAP_INT_ADVLOCK | 616 VOL_CAP_INT_FLOCK | 617 VOL_CAP_INT_EXTENDED_ATTR; 618 619 // We only support these bits of the above recognized things. 620 capabilities->capabilities[VOL_CAPABILITIES_FORMAT] = 621 VOL_CAP_FMT_PATH_FROM_ID | 622 VOL_CAP_FMT_PERSISTENTOBJECTIDS | 623 VOL_CAP_FMT_FAST_STATFS | 624 VOL_CAP_FMT_NO_ROOT_TIMES; 625 626 // We only support these things of the above recognized ones. 627 capabilities->capabilities[VOL_CAPABILITIES_INTERFACES] = 628 VOL_CAP_INT_ATTRLIST | 629 VOL_CAP_INT_EXTENDED_ATTR; 630 631 // Reserved. Zero them. 632 capabilities->capabilities[VOL_CAPABILITIES_RESERVED1] = 0; 633 capabilities->capabilities[VOL_CAPABILITIES_RESERVED2] = 0; 634 capabilities->valid[VOL_CAPABILITIES_RESERVED1] = 0; 635 capabilities->valid[VOL_CAPABILITIES_RESERVED2] = 0; 636 637 // Set the attributes. 638 VFSATTR_SET_SUPPORTED ( attrPtr, f_capabilities ); 639 640 attributes->validattr.commonattr = kAppleCDDACommonAttributesValidMask; 641 attributes->validattr.volattr = kAppleCDDAVolumeAttributesValidMask; 642 attributes->validattr.dirattr = kAppleCDDADirectoryAttributesValidMask; 643 attributes->validattr.fileattr = kAppleCDDAFileAttributesValidMask; 644 attributes->validattr.forkattr = kAppleCDDAForkAttributesValidMask; 645 646 attributes->nativeattr.commonattr = kAppleCDDACommonAttributesValidMask; 647 attributes->nativeattr.volattr = kAppleCDDAVolumeAttributesValidMask; 648 attributes->nativeattr.dirattr = kAppleCDDADirectoryAttributesValidMask; 649 attributes->nativeattr.fileattr = kAppleCDDAFileAttributesValidMask; 650 attributes->nativeattr.forkattr = kAppleCDDAForkAttributesValidMask; 651 652 // Set the attributes. 653 VFSATTR_SET_SUPPORTED ( attrPtr, f_attributes ); 654 655 return ( 0 ); 656 657} 658 659 660//----------------------------------------------------------------------------- 661// CDDA_VGet - This routine is responsible for getting the desired vnode. 662//----------------------------------------------------------------------------- 663 664int 665CDDA_VGet ( mount_t mountPtr, 666 ino64_t ino, 667 vnode_t * vNodeHandle, 668 unused vfs_context_t context ) 669{ 670 671 DebugLog ( ( "CDDA_VGet: Entering.\n" ) ); 672 673 DebugAssert ( ( mountPtr != NULL ) ); 674 DebugAssert ( ( vNodeHandle != NULL ) ); 675 DebugAssert ( ( context != NULL ) ); 676 677 return CDDA_VGetInternal ( mountPtr, ino, NULL, NULL, vNodeHandle ); 678 679} 680 681 682//----------------------------------------------------------------------------- 683// CDDA_VGetInternal - This routine is responsible for getting the 684// desired vnode. 685//----------------------------------------------------------------------------- 686 687int 688CDDA_VGetInternal ( mount_t mountPtr, 689 ino64_t ino, 690 vnode_t parentVNodePtr, 691 struct componentname * compNamePtr, 692 vnode_t * vNodeHandle ) 693{ 694 695 AppleCDDAMountPtr cddaMountPtr = NULL; 696 AppleCDDANodePtr parentCDDANodePtr = NULL; 697 AppleCDDANodeInfoPtr nodeInfoArrayPtr = NULL; 698 vnode_t vNodePtr = NULLVP; 699 int error = 0; 700 uint32_t index = 0; 701 uint32_t vid = 0; 702 703 cddaMountPtr = VFSTOCDDA ( mountPtr ); 704 705 DebugAssert ( ( cddaMountPtr != NULL ) ); 706 707 if ( ino == kAppleCDDARootFileID ) 708 { 709 710 DebugLog ( ( "Root vnode asked for!\n" ) ); 711 712 // Get the root vnode. 713 error = vnode_getwithvid ( cddaMountPtr->root, cddaMountPtr->rootVID ); 714 if ( error == 0 ) 715 { 716 717 // Return the root vnode to the caller since we have an iocount 718 // on it now. 719 *vNodeHandle = cddaMountPtr->root; 720 721 } 722 723 goto Exit; 724 725 } 726 727 else if ( ino == kAppleCDDAXMLFileID ) 728 { 729 730 DebugLog ( ( "XML vnode asked for!\n" ) ); 731 732 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 733 734 while ( cddaMountPtr->xmlFileFlags & kAppleCDDANodeBusyMask ) 735 { 736 737 cddaMountPtr->xmlFileFlags |= kAppleCDDANodeWantedMask; 738 ( void ) msleep ( &cddaMountPtr->xmlFileFlags, 739 cddaMountPtr->cddaMountLock, 740 PINOD, 741 "CDDA_VGetInternal(XML)", 742 0 ); 743 744 } 745 746 cddaMountPtr->xmlFileFlags |= kAppleCDDANodeBusyMask; 747 vNodePtr = cddaMountPtr->xmlFileVNodePtr; 748 749 if ( vNodePtr != NULL ) 750 { 751 752 // Get an io_count on the vnode 753 vid = vnode_vid ( vNodePtr ); 754 755 // Release the lock on our nodeInfo structure first 756 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 757 758 error = vnode_getwithvid ( vNodePtr, vid ); 759 760 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 761 762 if ( error == 0 ) 763 { 764 765 // Return the vnode to the caller since we have an iocount 766 // on it now. 767 *vNodeHandle = vNodePtr; 768 769 } 770 771 } 772 773 else 774 { 775 776 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 777 778 error = CreateNewXMLFile ( mountPtr, 779 cddaMountPtr->xmlDataSize, 780 cddaMountPtr->xmlData, 781 parentVNodePtr, 782 compNamePtr, 783 &vNodePtr ); 784 785 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 786 787 if ( error == 0 ) 788 { 789 790 cddaMountPtr->xmlFileVNodePtr = vNodePtr; 791 *vNodeHandle = vNodePtr; 792 793 } 794 795 } 796 797 cddaMountPtr->xmlFileFlags &= ~kAppleCDDANodeBusyMask; 798 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 799 800 if ( cddaMountPtr->xmlFileFlags & kAppleCDDANodeWantedMask ) 801 { 802 803 cddaMountPtr->xmlFileFlags &= ~kAppleCDDANodeWantedMask; 804 wakeup ( &cddaMountPtr->xmlFileFlags ); 805 806 } 807 808 goto Exit; 809 810 } 811 812 else if ( ( ino > 100 ) && ( ino < 200 ) ) 813 { 814 815 parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root ); 816 817 // subtract our file offset to get to the real nodeID 818 ino -= kOffsetForFiles; 819 820 // Look in our NodeInfo array to see if a vnode has been created for this 821 // track yet. 822 823 nodeInfoArrayPtr = VFSTONODEINFO ( mountPtr ); 824 DebugAssert ( ( nodeInfoArrayPtr != NULL ) ); 825 826 DebugLog ( ( "Locking cddaMountLock.\n" ) ); 827 DebugLog ( ( "Looking for nodeID = %lld.\n", ino ) ); 828 829 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 830 831 index = 0; 832 833 while ( index < ( parentCDDANodePtr->u.directory.entryCount - kNumberOfFakeDirEntries ) ) 834 { 835 836 if ( nodeInfoArrayPtr->trackDescriptor.point == ( UInt8 ) ino ) 837 { 838 839 while ( nodeInfoArrayPtr->flags & kAppleCDDANodeBusyMask ) 840 { 841 842 nodeInfoArrayPtr->flags |= kAppleCDDANodeWantedMask; 843 ( void ) msleep ( &nodeInfoArrayPtr->flags, 844 cddaMountPtr->cddaMountLock, 845 PINOD, 846 "CDDA_VGetInternal(Track)", 847 0 ); 848 849 } 850 851 nodeInfoArrayPtr->flags |= kAppleCDDANodeBusyMask; 852 vNodePtr = nodeInfoArrayPtr->vNodePtr; 853 854 // See if the vNodePtr was attached (vNodePtr is only non-NULL if the node has been created) 855 if ( vNodePtr != NULL ) 856 { 857 858 // Get the vid, so we can get an io_count on the vnode. 859 vid = vnode_vid ( vNodePtr ); 860 861 DebugLog ( ( "Releasing cddaMountLock.\n" ) ); 862 863 // Release the lock on our nodeInfo structure first. 864 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 865 866 // Get the iocount. 867 error = vnode_getwithvid ( vNodePtr, vid ); 868 869 // Grab our lock again. 870 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 871 872 if ( error == 0 ) 873 { 874 875 // The specified vNode was found and we got 876 // an iocount on it. Return this vnode. 877 *vNodeHandle = vNodePtr; 878 879 } 880 881 } 882 883 else 884 { 885 886 DebugLog ( ( "Couldn't find the vnode...Calling CreateNewCDDAFile\n" ) ); 887 888 // Release the lock. Creating a vnode could cause another one to be reclaimed. 889 // We don't want to deadlock in reclaim because we forgot to drop the lock here! 890 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 891 892 // If we get here, it doesn't exist yet, so create it 893 error = CreateNewCDDAFile ( mountPtr, 894 nodeInfoArrayPtr->trackDescriptor.point + kOffsetForFiles, 895 nodeInfoArrayPtr, 896 parentVNodePtr, 897 compNamePtr, 898 &vNodePtr ); 899 900 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 901 902 if ( error == 0 ) 903 { 904 905 // Make sure we mark this vnode as being in the array now. 906 *vNodeHandle = vNodePtr; 907 nodeInfoArrayPtr->vNodePtr = vNodePtr; 908 909 } 910 911 } 912 913 nodeInfoArrayPtr->flags &= ~kAppleCDDANodeBusyMask; 914 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 915 916 if ( nodeInfoArrayPtr->flags & kAppleCDDANodeWantedMask ) 917 { 918 919 nodeInfoArrayPtr->flags &= ~kAppleCDDANodeWantedMask; 920 wakeup ( &nodeInfoArrayPtr->flags ); 921 922 } 923 924 goto Exit; 925 926 } 927 928 index++; 929 nodeInfoArrayPtr++; 930 931 } 932 933 DebugLog ( ( "Releasing cddaMountLock...About to return ENOENT.\n" ) ); 934 935 // Now we can release our lock because we're getting out 936 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 937 938 // If we get here, we couldn't find anything with that name. Return ENOENT. 939 error = ENOENT; 940 941 } 942 943 else 944 { 945 946 error = ENOENT; 947 948 } 949 950 951Exit: 952 953 DebugLog ( ( "CDDA_VGetInternal: exiting...\n" ) ); 954 955 return ( error ); 956 957} 958 959 960//----------------------------------------------------------------------------- 961// FindVolumeName - Cribbed from vfs_attrlist.c. Gets volume name. 962//----------------------------------------------------------------------------- 963 964static void 965FindVolumeName ( const char * mn, const char ** np, ssize_t * nl ) 966{ 967 968 int counting = 0; 969 const char * cp = NULL; 970 971 // We're looking for the last sequence of non-'/' characters, but 972 // not including any trailing '/' characters. 973 *np = NULL; 974 *nl = 0; 975 976 for ( cp = mn; *cp != 0; cp++ ) 977 { 978 979 if ( !counting ) 980 { 981 982 // start of run of chars 983 if ( *cp != '/' ) 984 { 985 986 *np = cp; 987 counting = 1; 988 989 } 990 991 } 992 993 else 994 { 995 996 // end of run of chars 997 if ( *cp == '/' ) 998 { 999 1000 *nl = cp - *np; 1001 counting = 0; 1002 1003 } 1004 1005 } 1006 1007 } 1008 1009 // Need to close run? 1010 if ( counting ) 1011 *nl = cp - *np; 1012 1013} 1014 1015 1016//----------------------------------------------------------------------------- 1017// Apple_CDDA_FS_Module_Start - This routine is responsible for 1018// all the initialization that would 1019// ordinarily be done as part of the 1020// system startup 1021//----------------------------------------------------------------------------- 1022 1023int 1024Apple_CDDA_FS_Module_Start ( unused kmod_info_t * moduleInfo, 1025 unused void * loadArgument ) 1026{ 1027 1028 errno_t error = KERN_FAILURE; 1029 struct vfs_fsentry vfsEntry; 1030 1031 bzero ( &vfsEntry, sizeof ( vfsEntry ) ); 1032 1033 vfsEntry.vfe_vfsops = &gCDDA_VFSOps; 1034 vfsEntry.vfe_vopcnt = 1; // Just one vnode operation table 1035 vfsEntry.vfe_opvdescs = gCDDA_VNodeOperationsDescList; 1036 vfsEntry.vfe_flags = VFS_TBLNOTYPENUM | VFS_TBLLOCALVOL | VFS_TBL64BITREADY | VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK; 1037 1038 strlcpy ( vfsEntry.vfe_fsname, gAppleCDDAName, sizeof ( gAppleCDDAName ) ); 1039 1040 error = vfs_fsadd ( &vfsEntry, &gCDDA_VFSTableEntry ); 1041 1042 return error ? KERN_FAILURE : KERN_SUCCESS; 1043 1044} 1045 1046 1047//----------------------------------------------------------------------------- 1048// Apple_CDDA_FS_Module_Stop - This routine is responsible for stopping 1049// filesystem services 1050//----------------------------------------------------------------------------- 1051 1052int 1053Apple_CDDA_FS_Module_Stop ( unused kmod_info_t * moduleInfo, 1054 unused void * unloadArgument ) 1055{ 1056 1057 errno_t error = KERN_SUCCESS; 1058 1059 error = vfs_fsremove ( gCDDA_VFSTableEntry ); 1060 1061 return error ? KERN_FAILURE : KERN_SUCCESS; 1062 1063} 1064 1065 1066//----------------------------------------------------------------------------- 1067// End Of File 1068//----------------------------------------------------------------------------- 1069