1/* 2 * Copyright (c) 2000-2009 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// AppleCDDAFileSystemVNodeOps.c created by CJS on Mon 10-Apr-2000 25 26// Project Includes 27#ifndef __APPLE_CDDA_FS_VNODE_OPS_H__ 28#include "AppleCDDAFileSystemVNodeOps.h" 29#endif 30 31#ifndef __APPLE_CDDA_FS_DEBUG_H__ 32#include "AppleCDDAFileSystemDebug.h" 33#endif 34 35#ifndef __APPLE_CDDA_FS_DEFINES_H__ 36#include "AppleCDDAFileSystemDefines.h" 37#endif 38 39#ifndef __APPLE_CDDA_FS_UTILS_H__ 40#include "AppleCDDAFileSystemUtils.h" 41#endif 42 43#ifndef __APPLE_CDDA_FS_VFS_OPS_H__ 44#include "AppleCDDAFileSystemVFSOps.h" 45#endif 46 47// System Includes 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/types.h> 51#include <sys/time.h> 52#include <sys/proc.h> 53#include <sys/buf.h> 54#include <sys/vnode.h> 55#include <sys/dirent.h> 56#include <sys/stat.h> 57#include <sys/mount.h> 58#include <sys/malloc.h> 59#include <sys/paths.h> 60#include <sys/errno.h> 61#include <sys/uio.h> 62#include <sys/ubc.h> 63#include <sys/xattr.h> 64#include <vfs/vfs_support.h> 65#include <string.h> 66#include <libkern/OSByteOrder.h> 67#include <IOKit/IOLib.h> 68 69 70//----------------------------------------------------------------------------- 71// Globals 72//----------------------------------------------------------------------------- 73 74const char gAIFFHeaderPadData[kPhysicalMediaBlockSize - sizeof(CDAIFFHeader)] = { 0 }; 75 76//----------------------------------------------------------------------------- 77// Static Function Prototypes 78//----------------------------------------------------------------------------- 79 80static SInt32 81AddDirectoryEntry ( UInt32 nodeID, UInt8 type, const char * name, uio_t uio ); 82 83static inline uint64_t 84__u64min(uint64_t a, uint64_t b) 85{ 86 return (a > b ? b : a); 87} 88 89//----------------------------------------------------------------------------- 90// AddDirectoryEntry - This routine adds a directory entry to the uio buffer 91//----------------------------------------------------------------------------- 92 93static SInt32 94AddDirectoryEntry ( UInt32 nodeID, 95 UInt8 type, 96 const char * name, 97 uio_t uio ) 98{ 99 100 struct dirent directoryEntry; 101 SInt32 nameLength = 0; 102 UInt16 directoryEntryLength = 0; 103 104 DebugAssert ( ( name != NULL ) ); 105 DebugAssert ( ( uio != NULL ) ); 106 107 DebugLog ( ( "fileName = %s\n", name ) ); 108 109 nameLength = ( SInt32 ) strlen ( name ); 110 DebugAssert ( ( nameLength < MAXNAMLEN + 1 ) ); 111 112 directoryEntry.d_fileno = nodeID; 113 directoryEntry.d_reclen = sizeof ( directoryEntry ); 114 directoryEntry.d_type = type; 115 directoryEntry.d_namlen = nameLength; 116 directoryEntryLength = directoryEntry.d_reclen; 117 118 // Copy the string 119 strncpy ( directoryEntry.d_name, name, MAXNAMLEN ); 120 121 // Zero the rest of the array for safe-keeping 122 bzero ( &directoryEntry.d_name[nameLength], MAXNAMLEN + 1 - nameLength ); 123 124 if ( uio_resid ( uio ) < directoryEntry.d_reclen ) 125 { 126 127 // We can't copy because there isn't enough room in the buffer, 128 // so set the directoryEntryLength to zero so the caller knows 129 // an error occurred 130 directoryEntryLength = 0; 131 132 } 133 134 else 135 { 136 137 // Move the data 138 uiomove ( ( caddr_t ) &directoryEntry, ( int ) sizeof ( directoryEntry ), uio ); 139 140 } 141 142 return directoryEntryLength; 143 144} 145 146 147//----------------------------------------------------------------------------- 148// CDDA_Lookup - This routine performs a lookup 149//----------------------------------------------------------------------------- 150 151int 152CDDA_Lookup ( struct vnop_lookup_args * lookupArgsPtr ) 153/* 154struct vnop_lookup_args { 155 struct vnodeop_desc *a_desc; 156 vnode_t a_dvp; 157 vnode_t *a_vpp; 158 struct componentname *a_cnp; 159 vfs_context_t a_context; 160}; 161*/ 162{ 163 164 struct mount * mountPtr = NULL; 165 struct componentname * compNamePtr = NULL; 166 vnode_t * vNodeHandle = NULL; 167 vnode_t parentVNodePtr = NULLVP; 168 AppleCDDANodePtr parentCDDANodePtr = NULL; 169 AppleCDDAMountPtr cddaMountPtr = NULL; 170 int error = 0; 171 int flags = 0; 172 173 DebugLog ( ( "CDDA_Lookup: Entering.\n" ) ); 174 175 DebugAssert ( ( lookupArgsPtr != NULL ) ); 176 177 compNamePtr = lookupArgsPtr->a_cnp; 178 vNodeHandle = lookupArgsPtr->a_vpp; 179 parentVNodePtr = lookupArgsPtr->a_dvp; 180 mountPtr = vnode_mount ( parentVNodePtr ); 181 182 DebugAssert ( ( compNamePtr != NULL ) ); 183 DebugAssert ( ( vNodeHandle != NULL ) ); 184 DebugAssert ( ( parentVNodePtr != NULL ) ); 185 186 parentCDDANodePtr = VTOCDDA ( parentVNodePtr ); 187 cddaMountPtr = VFSTOCDDA ( mountPtr ); 188 189 DebugAssert ( ( parentCDDANodePtr != NULL ) ); 190 DebugAssert ( ( cddaMountPtr != NULL ) ); 191 192 *vNodeHandle = NULL; 193 flags = compNamePtr->cn_flags; 194 195 if ( compNamePtr->cn_namelen > NAME_MAX ) 196 { 197 198 error = ENAMETOOLONG; 199 goto Exit; 200 201 } 202 203 // Check if process wants to create, delete or rename anything 204 if ( compNamePtr->cn_nameiop == CREATE || 205 compNamePtr->cn_nameiop == RENAME || 206 compNamePtr->cn_nameiop == DELETE ) 207 { 208 209 DebugLog ( ( "Can't CREATE, RENAME or DELETE %s, returning EROFS\n", compNamePtr->cn_nameptr ) ); 210 error = EROFS; 211 goto Exit; 212 213 } 214 215 // Determine if we're looking for a resource fork. 216 // NB: this could cause a read off the end of the component name buffer in some rare cases. 217 if ( ( flags & ISLASTCN ) == 0 && bcmp ( &compNamePtr->cn_nameptr[compNamePtr->cn_namelen], 218 _PATH_RSRCFORKSPEC, 219 sizeof ( _PATH_RSRCFORKSPEC ) - 1 ) == 0 ) 220 { 221 222 DebugLog ( ( "No resource forks available, return ENOTDIR.\n" ) ); 223 compNamePtr->cn_consume = ( uint32_t ) sizeof ( _PATH_RSRCFORKSPEC ) - 1; 224 error = ENOTDIR; 225 goto Exit; 226 227 } 228 229 DebugLog ( ( "Looking for name = %s.\n", compNamePtr->cn_nameptr ) ); 230 231 // first check for "." and ".TOC.plist" 232 if ( compNamePtr->cn_nameptr[0] == '.' ) 233 { 234 235 if ( compNamePtr->cn_namelen == 1 ) 236 { 237 238 DebugLog ( ( ". was requested\n" ) ); 239 240 error = CDDA_VGetInternal ( mountPtr, kAppleCDDARootFileID, parentVNodePtr, compNamePtr, vNodeHandle ); 241 goto Exit; 242 243 } 244 245 else if ( ( compNamePtr->cn_namelen == 10 ) && ( !strncmp ( &compNamePtr->cn_nameptr[1], "TOC.plist", 9 ) ) ) 246 { 247 248 DebugLog ( ( ".TOC.plist was requested\n" ) ); 249 250 error = CDDA_VGetInternal ( mountPtr, kAppleCDDAXMLFileID, parentVNodePtr, compNamePtr, vNodeHandle ); 251 goto Exit; 252 253 } 254 255 else 256 { 257 258 // Not going to find anything prefixed with "." other than the above. 259 error = ENOENT; 260 goto Exit; 261 262 } 263 264 } 265 266 // At this point, we better be fetching a file which ends in ".aiff". 267 if ( strncmp ( &compNamePtr->cn_nameptr[compNamePtr->cn_namelen - 5], ".aiff", 5 ) != 0 ) 268 { 269 270 error = ENOENT; 271 goto Exit; 272 273 } 274 275 // Find out which inode they want. The first two bytes will tell us the track number which 276 // we can convert to an inode number by adding the kOffsetForFiles constant. Beware lame string 277 // parsing ahead... 278 { 279 280 ino64_t inode = 0; 281 282 if ( compNamePtr->cn_nameptr[1] == ' ' ) 283 { 284 285 // It's asking about track 1-9. 286 inode = ( ino64_t ) ( compNamePtr->cn_nameptr[0] - '0' ); 287 288 } 289 290 else if ( compNamePtr->cn_nameptr[2] == ' ' ) 291 { 292 293 // It's asking about track 10-99. 294 inode = ( ino64_t ) ( ( ( compNamePtr->cn_nameptr[0] - '0' ) * 10 ) + ( compNamePtr->cn_nameptr[1] - '0' ) ); 295 296 } 297 298 DebugLog ( ( "Track %lld was requested\n", inode ) ); 299 300 // Add the offset for a CD Track... 301 inode += kOffsetForFiles; 302 303 // Call the internal vget routine. Make sure to pass the parentVNode and compNamePtr so they 304 // can be passed to the CreateXXX routines if a vnode needs to be created. 305 error = CDDA_VGetInternal ( mountPtr, inode, parentVNodePtr, compNamePtr, vNodeHandle ); 306 goto Exit; 307 308 } 309 310 311Exit: 312 313 314 return ( error ); 315 316} 317 318 319//----------------------------------------------------------------------------- 320// CDDA_Open - This routine opens a file 321//----------------------------------------------------------------------------- 322 323int 324CDDA_Open ( struct vnop_open_args * openArgsPtr ) 325/* 326struct vnop_open_args { 327 struct vnodeop_desc *a_desc; 328 vnode_t a_vp; 329 int a_mode; 330 vfs_context_t a_context; 331}; 332*/ 333{ 334 335 vnode_t vNodePtr = NULLVP; 336 int error = 0; 337 338 DebugLog ( ( "CDDA_Open: Entering.\n" ) ); 339 340 DebugAssert ( ( openArgsPtr != NULL ) ); 341 342 vNodePtr = openArgsPtr->a_vp; 343 DebugAssert ( ( vNodePtr != NULL ) ); 344 345 // Set the vNodeOperationType to tell the user process if we are going to open a 346 // file or a directory 347 if ( ! vnode_isreg ( vNodePtr ) && ! vnode_isdir ( vNodePtr ) ) 348 { 349 350 // This should never happen but just in case 351 DebugLog ( ( "Error = %d, wrong vnode type.\n", ENOTSUP ) ); 352 error = ENOTSUP; 353 goto ERROR; 354 355 } 356 357 // Turn off speculative read-ahead for our vnodes. The cluster 358 // code can't possibly do the right thing when we have possible 359 // loss of streaming on CD media. 360 vnode_setnoreadahead ( vNodePtr ); 361 362 363ERROR: 364 365 366 DebugLog ( ( "CDDA_Open: exiting with error = %d.\n", error ) ); 367 368 return ( error ); 369 370} 371 372 373//----------------------------------------------------------------------------- 374// CDDA_Close - This routine closes a file. Since we are a read-only 375// filesystem, we don't have any cleaning up to do. 376//----------------------------------------------------------------------------- 377 378int 379CDDA_Close ( struct vnop_close_args * closeArgsPtr ) 380/* 381struct vnop_close_args { 382 struct vnodeop_desc *a_desc; 383 vnode_t a_vp; 384 int a_fflag; 385 vfs_context_t a_context; 386}; 387*/ 388{ 389#pragma unused (closeArgsPtr) 390 return ( 0 ); 391} 392 393 394//----------------------------------------------------------------------------- 395// CDDA_Read - This routine reads from a file 396//----------------------------------------------------------------------------- 397 398int 399CDDA_Read ( struct vnop_read_args * readArgsPtr ) 400/* 401struct vnop_read_args { 402 struct vnodeop_desc *a_desc; 403 vnode_t a_vp; 404 uio_t a_uio; 405 int a_ioflag; 406 vfs_context_t a_context; 407}; 408*/ 409{ 410 411 vnode_t vNodePtr = NULLVP; 412 uio_t uio = NULL; 413 AppleCDDANodePtr cddaNodePtr = NULL; 414 int error = 0; 415 416 DebugLog ( ( "CDDA_Read: Entering.\n" ) ); 417 418 DebugAssert ( ( readArgsPtr ) ); 419 420 vNodePtr = readArgsPtr->a_vp; 421 uio = readArgsPtr->a_uio; 422 423 DebugAssert ( ( vNodePtr != NULL ) ); 424 DebugAssert ( ( uio != NULL ) ); 425 426 cddaNodePtr = VTOCDDA ( vNodePtr ); 427 DebugAssert ( ( cddaNodePtr != NULL ) ); 428 429 // Check to make sure we're operating on a regular file 430 if ( ! vnode_isreg ( vNodePtr ) ) 431 { 432 433 DebugLog ( ( "CDDA_Read: not a file, exiting with error = %d.\n", EISDIR ) ); 434 return ( EISDIR ); 435 436 } 437 438 // Check to make sure they asked for data 439 if ( uio_resid ( uio ) == 0 ) 440 { 441 442 DebugLog ( ( "CDDA_Read: uio_resid = 0, no data requested" ) ); 443 return ( 0 ); 444 445 } 446 447 // Can't read from a negative offset 448 if ( uio_offset ( uio ) < 0 ) 449 { 450 451 DebugLog ( ( "CDDA_Read: Can't read from a negative offset..." ) ); 452 return ( EINVAL ); 453 454 } 455 456 if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 457 { 458 459 off_t offset = uio_offset ( uio ); 460 UInt32 amountToCopy = 0; 461 UInt32 numBytes = 0; 462 463 numBytes = cddaNodePtr->u.xmlFile.fileSize; 464 465 // Check to make sure we don't read past EOF 466 if ( uio_offset ( uio ) > numBytes ) 467 { 468 469 DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) ); 470 return ( 0 ); 471 472 } 473 474 amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), numBytes - offset ); 475 476 error = uiomove ( ( caddr_t ) &cddaNodePtr->u.xmlFile.fileDataPtr[offset], 477 amountToCopy, 478 uio ); 479 480 if ( error != 0 ) 481 { 482 483 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 484 return ( error ); 485 486 } 487 488 return ( 0 ); 489 490 } 491 492 else if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) 493 { 494 495 UInt32 headerSize = 0; 496 UInt32 count = 0; 497 UInt64 blockNumber = 0; 498 off_t offset = 0; 499 off_t sectorOffset = 0; 500 buf_t bufPtr = NULL; 501 502 offset = uio_offset ( uio ); 503 504 // Check to make sure we don't read past EOF 505 if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes ) 506 { 507 508 DebugLog ( ( "CDDA_Read: Can't read past end of file..." ) ); 509 return ( 0 ); 510 511 } 512 513 headerSize = ( UInt32 ) sizeof ( cddaNodePtr->u.file.aiffHeader ); 514 515 // Copy any part of the header that we need to copy. 516 if ( offset < headerSize ) 517 { 518 519 UInt32 amountToCopy = 0; 520 UInt8 * bytes = NULL; 521 522 bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader; 523 524 amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), headerSize - offset ); 525 526 error = uiomove ( ( caddr_t ) &bytes[offset], 527 amountToCopy, 528 uio ); 529 530 if ( error != 0 ) 531 { 532 533 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 534 return ( error ); 535 536 } 537 538 offset += amountToCopy; 539 540 } 541 542 // Copy any part of the header pad that we need to copy. 543 if ( ( uio_resid ( uio ) > 0 ) && 544 ( offset < kPhysicalMediaBlockSize ) ) 545 { 546 547 UInt32 amountToCopy = 0; 548 549 amountToCopy = ( UInt32 ) __u64min ( uio_resid ( uio ), kPhysicalMediaBlockSize - offset ); 550 551 error = uiomove ( ( caddr_t ) &gAIFFHeaderPadData[offset - headerSize], 552 amountToCopy, 553 uio ); 554 555 if ( error != 0 ) 556 { 557 558 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 559 return ( error ); 560 561 } 562 563 offset += amountToCopy; 564 565 } 566 567 if ( ( uio_resid ( uio ) > 0 ) && 568 ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 569 { 570 571 // Adjust offset by the header size so we have a true offset into the media. 572 offset -= kPhysicalMediaBlockSize; 573 sectorOffset = offset % kPhysicalMediaBlockSize; 574 blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA; 575 576 // Part 1 577 // We do the read in 3 parts. First, we read one sector (picks up any buffer cache entry from a 578 // previous Part 3 if it exists). 579 { 580 581 // Clip to requested transfer count and end of file. 582 count = ( UInt32 ) __u64min ( uio_resid ( uio ), ( kPhysicalMediaBlockSize - sectorOffset ) ); 583 count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); 584 585 // Read the one sector 586 error = ( int ) buf_meta_bread ( 587 cddaNodePtr->blockDeviceVNodePtr, 588 blockNumber, 589 kPhysicalMediaBlockSize, 590 NOCRED, 591 &bufPtr ); 592 593 if ( error != 0 ) 594 { 595 596 buf_brelse ( bufPtr ); 597 return ( error ); 598 599 } 600 601 // Move the data from the block into the buffer 602 error = uiomove ( ( caddr_t ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ), count, uio ); 603 604 // Make sure we mark this bp invalid as we don't need to keep it around anymore 605 buf_markinvalid ( bufPtr ); 606 607 // Release this buffer back into the buffer pool. 608 buf_brelse ( bufPtr ); 609 610 if ( error != 0 ) 611 { 612 613 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 614 return ( error ); 615 616 } 617 618 // Update offset 619 blockNumber++; 620 621 } 622 623 // Part 2 624 // Now we execute the second part of the read. This will be the largest chunk of the read. 625 // We will read multiple disc blocks up to MAXBSIZE bytes in a loop until we hit a chunk which 626 // is less than one block size. That will be read in the third part. 627 628 while ( ( uio_resid ( uio ) > kPhysicalMediaBlockSize ) && 629 ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 630 { 631 632 UInt64 blocksToRead = 0; 633 634 // Read in as close to MAXBSIZE chunks as possible 635 if ( uio_resid ( uio ) > kMaxBytesPerRead ) 636 { 637 blocksToRead = kMaxBlocksPerRead; 638 count = kMaxBytesPerRead; 639 } 640 641 else 642 { 643 blocksToRead = uio_resid ( uio ) / kPhysicalMediaBlockSize; 644 count = ( UInt32 ) ( blocksToRead * kPhysicalMediaBlockSize ); 645 } 646 647 // Read kMaxBlocksPerRead blocks and put them in the cache. 648 error = ( int ) buf_meta_bread ( 649 cddaNodePtr->blockDeviceVNodePtr, 650 blockNumber, 651 count, 652 NOCRED, 653 &bufPtr ); 654 655 if ( error != 0 ) 656 { 657 658 buf_brelse ( bufPtr ); 659 return ( error ); 660 661 } 662 663 count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); 664 665 // Move the data from the block into the buffer 666 error = uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio ); 667 668 // Make sure we mark any intermediate buffers as invalid as we don't need 669 // to keep them. 670 buf_markinvalid ( bufPtr ); 671 672 // Release this buffer back into the buffer pool. 673 buf_brelse ( bufPtr ); 674 675 if ( error != 0 ) 676 { 677 678 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 679 return ( error ); 680 681 } 682 683 // Update offset 684 blockNumber += blocksToRead; 685 686 } 687 688 // Part 3 689 // Now that we have read everything, we read the tail end which is a partial sector. 690 // Sometimes we don't need to execute this step since there isn't a tail. 691 if ( ( uio_resid ( uio ) > 0 ) && 692 ( uio_offset ( uio ) < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 693 { 694 695 count = ( UInt32 ) __u64min ( uio_resid ( uio ), cddaNodePtr->u.file.nodeInfoPtr->numBytes - uio_offset ( uio ) ); 696 697 // Read the one sector 698 error = ( int ) buf_meta_bread ( 699 cddaNodePtr->blockDeviceVNodePtr, 700 blockNumber, 701 kPhysicalMediaBlockSize, 702 NOCRED, 703 &bufPtr ); 704 705 if ( error != 0 ) 706 { 707 708 buf_brelse ( bufPtr ); 709 return ( error ); 710 711 } 712 713 // Move the data from the block into the buffer 714 error = uiomove ( ( caddr_t ) buf_dataptr ( bufPtr ), count, uio ); 715 716 // Make sure we mark any intermediate buffers as invalid as we don't need 717 // to keep them. 718 buf_markinvalid ( bufPtr ); 719 720 // Release this buffer back into the buffer pool. 721 buf_brelse ( bufPtr ); 722 723 if ( error != 0 ) 724 { 725 726 DebugLog ( ( "CDDA_Read: uiomove returned %d!\n", error ) ); 727 return ( error ); 728 729 } 730 731 } 732 733 } 734 735 } 736 737 DebugLog ( ( "CDDA_Read: exiting.\n" ) ); 738 739 return ( error ); 740 741} 742 743 744//----------------------------------------------------------------------------- 745// CDDA_ReadDir - This routine reads the contents of a directory 746//----------------------------------------------------------------------------- 747 748int 749CDDA_ReadDir ( struct vnop_readdir_args * readDirArgsPtr ) 750/* 751struct vnop_readdir_args { 752 struct vnodeop_desc *a_desc; 753 vnode_t a_vp; 754 uio_t a_uio; 755 int a_flags; 756 int *a_eofflag; 757 int *a_numdirent; 758 vfs_context_t a_context; 759}; 760*/ 761{ 762 763 vnode_t vNodePtr = NULLVP; 764 AppleCDDANodePtr cddaNodePtr = NULL; 765 AppleCDDAMountPtr cddaMountPtr = NULL; 766 AppleCDDANodeInfoPtr nodeInfoArrayPtr = NULL; 767 uio_t uio = NULL; 768 UInt32 index = 0; 769 int error = 0; 770 SInt32 offsetValue = 0; 771 UInt32 direntSize = 0; 772 773 DebugLog ( ( "CDDA_ReadDir: Entering.\n" ) ); 774 775 DebugAssert ( ( readDirArgsPtr != NULL ) ); 776 777 vNodePtr = readDirArgsPtr->a_vp; 778 uio = readDirArgsPtr->a_uio; 779 780 DebugAssert ( ( vNodePtr != NULL ) ); 781 DebugAssert ( ( uio != NULL ) ); 782 783 cddaNodePtr = VTOCDDA ( vNodePtr ); 784 785 DebugAssert ( ( cddaNodePtr != NULL ) ); 786 787 if ( readDirArgsPtr->a_flags & ( VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF ) ) 788 return ( EINVAL ); 789 790 // First make sure it is a directory we are dealing with 791 if ( ! vnode_isdir ( vNodePtr ) ) 792 { 793 794 DebugLog ( ( "CDDA_ReadDir: not a directory, exiting with error = %d.\n", ENOTDIR ) ); 795 return ( ENOTDIR ); 796 797 } 798 799 if ( cddaNodePtr->nodeID != kAppleCDDARootFileID ) 800 { 801 802 DebugLog ( ( "CDDA_ReadDir: not root directory, exiting with error = %d.\n", EINVAL ) ); 803 return ( EINVAL ); 804 805 } 806 807 // Make sure it's all one big buffer 808 if ( uio_iovcnt ( uio ) > 1 ) 809 { 810 811 DebugLog ( ( "More than one buffer, exiting with error = %d.\n", EINVAL ) ); 812 return ( EINVAL ); 813 814 } 815 816 // Make sure we don't return partial entries 817 if ( ( uint32_t ) uio_resid ( uio ) < sizeof ( struct dirent ) ) 818 { 819 820 DebugLog ( ( "resid < dirent size, exiting with error = %d.\n", EINVAL ) ); 821 return ( EINVAL ); 822 823 } 824 825 direntSize = ( UInt32 ) sizeof ( struct dirent ); 826 827 // Synthesize '.', "..", and ".TOC.plist" 828 if ( uio_offset ( uio ) == 0 ) 829 { 830 831 offsetValue = AddDirectoryEntry ( cddaNodePtr->nodeID, DT_DIR, ".", uio ); 832 if ( offsetValue == 0 ) 833 { 834 835 DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) ); 836 return 0; 837 838 } 839 840 } 841 842 if ( uio_offset ( uio ) == direntSize ) 843 { 844 845 offsetValue = AddDirectoryEntry ( cddaNodePtr->nodeID, DT_DIR, "..", uio ); 846 if ( offsetValue == 0 ) 847 { 848 849 DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) ); 850 return 0; 851 852 } 853 854 } 855 856 if ( uio_offset ( uio ) == direntSize * kAppleCDDARootFileID ) 857 { 858 859 offsetValue += AddDirectoryEntry ( kAppleCDDAXMLFileID, DT_REG, ".TOC.plist", uio ); 860 if ( offsetValue == 0 ) 861 { 862 863 DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) ); 864 return 0; 865 866 } 867 868 } 869 870 nodeInfoArrayPtr = VFSTONODEINFO ( vnode_mount ( vNodePtr ) ); 871 cddaMountPtr = VFSTOCDDA ( vnode_mount ( vNodePtr ) ); 872 873 DebugAssert ( ( nodeInfoArrayPtr != NULL ) ); 874 DebugAssert ( ( cddaMountPtr != NULL ) ); 875 876 DebugLog ( ( "cddaMountPtr->numTracks = %ld.\n", cddaMountPtr->numTracks ) ); 877 DebugLog ( ( "buffer size needed = %ld.\n", direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) ); 878 879 // OK, so much for the fakes. Now for the "real thing" 880 // Loop over all the names in the NameArray to produce directory entries 881 for ( index = 0; index < cddaMountPtr->numTracks; index++, nodeInfoArrayPtr++ ) 882 { 883 884 DebugLog ( ( "uio_offset ( uio ) = %ld.\n", uio_offset ( uio ) ) ); 885 DebugLog ( ( "uio_resid ( uio ) = %ld.\n", uio_resid ( uio ) ) ); 886 887 if ( uio_offset ( uio ) == direntSize * ( index + kNumberOfFakeDirEntries ) ) 888 { 889 890 DebugLog ( ( "index = %ld.\n", index ) ); 891 892 // Return this entry 893 offsetValue = AddDirectoryEntry ( nodeInfoArrayPtr->trackDescriptor.point, 894 DT_REG, 895 nodeInfoArrayPtr->name, 896 uio ); 897 898 if ( offsetValue == 0 ) 899 { 900 901 DebugLog ( ( "offsetValue is zero, exiting with error = %d.\n", 0 ) ); 902 return 0; 903 904 } 905 906 } 907 908 } 909 910 if ( readDirArgsPtr->a_eofflag ) 911 { 912 913 DebugLog ( ( "eofflag = %d.\n", ( uio_offset ( uio ) >= direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) ? 1 : 0 ) ); 914 915 // If we ran all the way through the list, there are no more 916 *readDirArgsPtr->a_eofflag = ( uio_offset ( uio ) >= direntSize * ( cddaMountPtr->numTracks + kNumberOfFakeDirEntries ) ) ? 1 : 0; 917 error = 0; 918 919 } 920 921 DebugLog ( ( "CDDA_ReadDir: exiting with error = %d.\n", error ) ); 922 923 return ( error ); 924 925} 926 927 928//----------------------------------------------------------------------------- 929// CDDA_PageIn - This routine handles VM PageIn requests 930//----------------------------------------------------------------------------- 931 932int 933CDDA_PageIn ( struct vnop_pagein_args * pageInArgsPtr ) 934/* 935struct vnop_pagein_args { 936 struct vnodeop_desc *a_desc; 937 vnode_t a_vp; 938 upl_t a_pl; 939 vm_offset_t a_pl_offset; 940 off_t a_f_offset; 941 size_t a_size; 942 int a_flags; 943 vfs_context_t a_context; 944}; 945*/ 946{ 947 948 vnode_t vNodePtr = NULLVP; 949 AppleCDDANodePtr cddaNodePtr = NULL; 950 int error = 0; 951 int nocommit = 0; 952 UInt32 numBytes = 0; 953 954 DebugLog ( ( "CDDA_PageIn: Entering.\n" ) ); 955 956 DebugAssert ( ( pageInArgsPtr != NULL ) ); 957 958 vNodePtr = pageInArgsPtr->a_vp; 959 nocommit = pageInArgsPtr->a_flags & UPL_NOCOMMIT; 960 961 DebugAssert ( ( vNodePtr != NULL ) ); 962 963 cddaNodePtr = VTOCDDA ( vNodePtr ); 964 DebugAssert ( ( cddaNodePtr != NULL ) ); 965 966 if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 967 { 968 969 numBytes = cddaNodePtr->u.xmlFile.fileSize; 970 971 } 972 973 else if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) 974 { 975 976 numBytes = cddaNodePtr->u.file.nodeInfoPtr->numBytes; 977 978 } 979 980 // If they didn't ask for any data, then we are done 981 if ( pageInArgsPtr->a_size == 0 ) 982 { 983 984 if ( !nocommit ) 985 { 986 987 ubc_upl_abort_range ( pageInArgsPtr->a_pl, 988 pageInArgsPtr->a_pl_offset, 989 ( upl_size_t ) pageInArgsPtr->a_size, 990 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY ); 991 992 } 993 994 return ( error ); 995 996 } 997 998 // Make sure we aren't reading from a negative offset 999 if ( pageInArgsPtr->a_f_offset < 0 ) 1000 { 1001 1002 if ( !nocommit ) 1003 { 1004 1005 ubc_upl_abort_range ( pageInArgsPtr->a_pl, 1006 pageInArgsPtr->a_pl_offset, 1007 ( upl_size_t ) pageInArgsPtr->a_size, 1008 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY ); 1009 1010 } 1011 1012 error = EINVAL; 1013 DebugLog ( ( "CDDA_PageIn: trying to page in from a negative offset.\n" ) ); 1014 1015 return ( error ); 1016 1017 } 1018 1019 // Check to make sure we don't read past EOF 1020 if ( pageInArgsPtr->a_f_offset > numBytes ) 1021 { 1022 1023 if ( !nocommit ) 1024 { 1025 1026 ubc_upl_abort_range ( pageInArgsPtr->a_pl, 1027 pageInArgsPtr->a_pl_offset, 1028 ( upl_size_t ) pageInArgsPtr->a_size, 1029 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY ); 1030 1031 } 1032 1033 return ( error ); 1034 1035 } 1036 1037 // Workaround for faked ".TOC.plist" file 1038 if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 1039 { 1040 1041 kern_return_t kret = 0; 1042 vm_offset_t vmOffsetPtr = 0; 1043 UInt32 amountToCopy = 0; 1044 1045 // Map the physical page into the kernel address space 1046 kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr ); 1047 1048 // If we got an error or the vmOffsetPtr is zero, panic for now 1049 if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 ) 1050 { 1051 1052 panic ( "CDDA_PageIn: error mapping buffer into kernel space!" ); 1053 1054 } 1055 1056 // Zero fill the page 1057 bzero ( ( caddr_t )( vmOffsetPtr + pageInArgsPtr->a_pl_offset ), PAGE_SIZE ); 1058 1059 amountToCopy = ( UInt32 ) __u64min ( PAGE_SIZE, numBytes - pageInArgsPtr->a_f_offset ); 1060 1061 // Copy the file data 1062 bcopy ( &cddaNodePtr->u.xmlFile.fileDataPtr[pageInArgsPtr->a_f_offset], 1063 ( void * ) vmOffsetPtr, 1064 amountToCopy ); 1065 1066 // Unmap the physical page from the kernel address space 1067 kret = ubc_upl_unmap ( pageInArgsPtr->a_pl ); 1068 1069 // If we got an error, panic for now 1070 if ( kret != KERN_SUCCESS ) 1071 { 1072 1073 panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" ); 1074 1075 } 1076 1077 if ( !nocommit ) 1078 { 1079 1080 // Commit the page to the vm subsystem 1081 ubc_upl_commit_range ( pageInArgsPtr->a_pl, 1082 pageInArgsPtr->a_pl_offset, 1083 PAGE_SIZE, 1084 UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_CLEAR_DIRTY ); 1085 1086 } 1087 1088 return 0; 1089 1090 } 1091 1092 else if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) 1093 { 1094 1095 UInt32 headerSize = 0; 1096 UInt64 blockNumber = 0; 1097 UInt32 count = 0; 1098 off_t offset = 0; 1099 off_t sectorOffset = 0; 1100 off_t residual = 0; 1101 kern_return_t kret = 0; 1102 vm_offset_t vmOffsetPtr = 0; 1103 buf_t bufPtr = NULL; 1104 1105 residual = pageInArgsPtr->a_size; 1106 offset = pageInArgsPtr->a_f_offset; 1107 1108 // Check to make sure we don't read past EOF 1109 if ( offset > cddaNodePtr->u.file.nodeInfoPtr->numBytes ) 1110 { 1111 1112 DebugLog ( ( "CDDA_PageIn: Can't read past end of file..." ) ); 1113 return ( 0 ); 1114 1115 } 1116 1117 headerSize = ( UInt32 ) sizeof ( cddaNodePtr->u.file.aiffHeader ); 1118 1119 // Map the physical pages into the kernel address space 1120 kret = ubc_upl_map ( pageInArgsPtr->a_pl, &vmOffsetPtr ); 1121 1122 // If we got an error or the vmOffsetPtr is zero, panic for now 1123 if ( kret != KERN_SUCCESS || vmOffsetPtr == 0 ) 1124 { 1125 1126 panic ( "CDDA_PageIn: error mapping buffer into kernel space!" ); 1127 1128 } 1129 1130 // Account for the offset into the UPL. 1131 vmOffsetPtr += pageInArgsPtr->a_pl_offset; 1132 1133 // Copy any part of the header that we need to copy. 1134 if ( offset < headerSize ) 1135 { 1136 1137 UInt32 amountToCopy = 0; 1138 UInt8 * bytes = NULL; 1139 1140 amountToCopy = ( UInt32 ) __u64min ( pageInArgsPtr->a_size, headerSize - offset ); 1141 1142 bytes = ( UInt8 * ) &cddaNodePtr->u.file.aiffHeader; 1143 1144 // Copy the header data 1145 bcopy ( &bytes[offset], 1146 ( void * ) vmOffsetPtr, 1147 amountToCopy ); 1148 1149 offset += amountToCopy; 1150 residual -= amountToCopy; 1151 vmOffsetPtr += amountToCopy; 1152 1153 } 1154 1155 // Copy any part of the header pad that we need to copy. 1156 if ( ( residual > 0 ) && 1157 ( offset < kPhysicalMediaBlockSize ) ) 1158 { 1159 1160 UInt32 amountToCopy = 0; 1161 1162 amountToCopy = ( UInt32 ) __u64min ( residual, kPhysicalMediaBlockSize - offset ); 1163 1164 // Copy the header pad data (all zeroes). 1165 bcopy ( &gAIFFHeaderPadData[offset - headerSize], 1166 ( void * ) vmOffsetPtr, 1167 amountToCopy ); 1168 1169 offset += amountToCopy; 1170 residual -= amountToCopy; 1171 vmOffsetPtr += amountToCopy; 1172 1173 } 1174 1175 if ( ( residual > 0 ) && 1176 ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 1177 { 1178 1179 // Adjust offset by the size of header + header pad so we have a true offset into the media. 1180 offset -= kPhysicalMediaBlockSize; 1181 sectorOffset = offset % kPhysicalMediaBlockSize; 1182 blockNumber = ( offset / kPhysicalMediaBlockSize ) + cddaNodePtr->u.file.nodeInfoPtr->LBA; 1183 1184 // Part 1 1185 // We do the read in 3 parts. First, we read one sector (picks up any buffer cache entry from a 1186 // previous Part 3 if it exists). 1187 { 1188 1189 // Clip to requested transfer count and end of file. 1190 count = ( UInt32 ) __u64min ( residual, ( kPhysicalMediaBlockSize - sectorOffset ) ); 1191 count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); 1192 1193 // Read the one sector 1194 error = ( int ) buf_meta_bread ( 1195 cddaNodePtr->blockDeviceVNodePtr, 1196 blockNumber, 1197 kPhysicalMediaBlockSize, 1198 NOCRED, 1199 &bufPtr ); 1200 1201 if ( error != 0 ) 1202 { 1203 1204 buf_brelse ( bufPtr ); 1205 return ( error ); 1206 1207 } 1208 1209 // Copy the data 1210 bcopy ( ( void * ) ( ( char * ) buf_dataptr ( bufPtr ) + sectorOffset ), 1211 ( void * ) vmOffsetPtr, 1212 count ); 1213 1214 // Increment/decrement counters 1215 offset += count; 1216 residual -= count; 1217 vmOffsetPtr += count; 1218 1219 // Make sure we mark this bp invalid as we don't need to keep it around anymore 1220 buf_markinvalid ( bufPtr ); 1221 1222 // Release this buffer back into the buffer pool. 1223 buf_brelse ( bufPtr ); 1224 1225 // Update offset 1226 blockNumber++; 1227 1228 } 1229 1230 // Part 2 1231 // Now we execute the second part of the read. This will be the largest chunk of the read. 1232 // We will read multiple disc blocks up to MAXBSIZE bytes in a loop until we hit a chunk which 1233 // is less than one block size. That will be read in the third part. 1234 1235 while ( ( residual > kPhysicalMediaBlockSize ) && 1236 ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 1237 { 1238 1239 UInt64 blocksToRead = 0; 1240 1241 // Read in as close to MAXBSIZE chunks as possible 1242 if ( residual > kMaxBytesPerRead ) 1243 { 1244 blocksToRead = kMaxBlocksPerRead; 1245 count = kMaxBytesPerRead; 1246 } 1247 1248 else 1249 { 1250 blocksToRead = residual / kPhysicalMediaBlockSize; 1251 count = ( UInt32 ) ( blocksToRead * kPhysicalMediaBlockSize ); 1252 } 1253 1254 // read kMaxBlocksPerRead blocks and put them in the cache. 1255 error = ( int ) buf_meta_bread ( 1256 cddaNodePtr->blockDeviceVNodePtr, 1257 blockNumber, 1258 count, 1259 NOCRED, 1260 &bufPtr ); 1261 1262 if ( error != 0 ) 1263 { 1264 1265 buf_brelse ( bufPtr ); 1266 return ( error ); 1267 1268 } 1269 1270 count = ( UInt32 ) __u64min ( count, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); 1271 1272 // Copy the data 1273 bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count ); 1274 1275 // Increment/decrement counters 1276 offset += count; 1277 residual -= count; 1278 vmOffsetPtr += count; 1279 1280 // Make sure we mark any intermediate buffers as invalid as we don't need 1281 // to keep them. 1282 buf_markinvalid ( bufPtr ); 1283 1284 // Release this buffer back into the buffer pool. 1285 buf_brelse ( bufPtr ); 1286 1287 // Update offset 1288 blockNumber += blocksToRead; 1289 1290 } 1291 1292 // Part 3 1293 // Now that we have read everything, we read the tail end which is a partial sector. 1294 // Sometimes we don't need to execute this step since there isn't a tail. 1295 if ( ( residual > 0 ) && 1296 ( offset < cddaNodePtr->u.file.nodeInfoPtr->numBytes ) ) 1297 { 1298 1299 count = ( UInt32 ) __u64min ( residual, cddaNodePtr->u.file.nodeInfoPtr->numBytes - offset ); 1300 1301 // Read the one sector 1302 error = ( int ) buf_meta_bread ( 1303 cddaNodePtr->blockDeviceVNodePtr, 1304 blockNumber, 1305 kPhysicalMediaBlockSize, 1306 NOCRED, 1307 &bufPtr ); 1308 1309 if ( error != 0 ) 1310 { 1311 1312 buf_brelse ( bufPtr ); 1313 return ( error ); 1314 1315 } 1316 1317 // Copy the data 1318 bcopy ( ( void * ) buf_dataptr ( bufPtr ), ( void * ) vmOffsetPtr, count ); 1319 1320 // Increment/decrement counters 1321 offset += count; 1322 residual -= count; 1323 vmOffsetPtr += count; 1324 1325 // Make sure we mark any intermediate buffers as invalid as we don't need 1326 // to keep them. 1327 buf_markinvalid ( bufPtr ); 1328 1329 // Release this buffer back into the buffer pool. 1330 buf_brelse ( bufPtr ); 1331 1332 } 1333 1334 } 1335 1336 // Unmap the physical page from the kernel address space 1337 kret = ubc_upl_unmap ( pageInArgsPtr->a_pl ); 1338 1339 // If we got an error, panic for now 1340 if ( kret != KERN_SUCCESS ) 1341 { 1342 1343 panic ( "CDDA_PageIn: error unmapping buffer from kernel space!" ); 1344 1345 } 1346 1347 if ( !nocommit ) 1348 { 1349 1350 // Commit the page to the vm subsystem 1351 ubc_upl_commit_range ( pageInArgsPtr->a_pl, 1352 pageInArgsPtr->a_pl_offset, 1353 ( upl_size_t ) pageInArgsPtr->a_size, 1354 UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_CLEAR_DIRTY ); 1355 1356 } 1357 1358 } 1359 1360 DebugLog ( ( "CDDA_PageIn: exiting...\n" ) ); 1361 1362 return ( error ); 1363 1364} 1365 1366 1367//----------------------------------------------------------------------------- 1368// CDDA_GetAttributes - This routine gets the attributes for a folder/file 1369//----------------------------------------------------------------------------- 1370 1371int 1372CDDA_GetAttributes ( struct vnop_getattr_args * getAttrArgsPtr ) 1373/* 1374struct vnop_getattr_args { 1375 struct vnodeop_desc *a_desc; 1376 vnode_t a_vp; 1377 struct vnode_attr *a_vap; 1378 vfs_context_t a_context; 1379}; 1380*/ 1381{ 1382 1383 vnode_t vNodePtr = NULLVP; 1384 mount_t mountPtr = NULL; 1385 struct vnode_attr * attributesPtr = NULL; 1386 AppleCDDANodePtr cddaNodePtr = NULL; 1387 AppleCDDAMountPtr cddaMountPtr = NULL; 1388 struct timespec nullTime = { 0, 0 }; 1389 1390 DebugLog ( ( "CDDA_GetAttributes: Entering.\n" ) ); 1391 1392 DebugAssert ( ( getAttrArgsPtr != NULL ) ); 1393 1394 vNodePtr = getAttrArgsPtr->a_vp; 1395 mountPtr = vnode_mount ( vNodePtr ); 1396 attributesPtr = getAttrArgsPtr->a_vap; 1397 1398 DebugAssert ( ( vNodePtr != NULL ) ); 1399 DebugAssert ( ( attributesPtr != NULL ) ); 1400 1401 cddaMountPtr = VFSTOCDDA ( mountPtr ); 1402 cddaNodePtr = VTOCDDA ( vNodePtr ); 1403 1404 DebugAssert ( ( cddaNodePtr != NULL ) ); 1405 DebugAssert ( ( cddaMountPtr != NULL ) ); 1406 1407 DebugLog ( ( "nodeID = %ld.\n", cddaNodePtr->nodeID ) ); 1408 1409 // Special case root since we know how to get its name 1410 if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType ) 1411 { 1412 1413 // Set the nodeID. Force root to be 2. 1414 VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDARootFileID ); 1415 1416 } 1417 1418 // Special case the XMLFileNode 1419 else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 1420 { 1421 1422 // Set the nodeID. Force the XMLFileNode to be 3. 1423 VATTR_RETURN ( attributesPtr, va_fileid, kAppleCDDAXMLFileID ); 1424 1425 } 1426 1427 else 1428 { 1429 1430 // Set the nodeID. 1431 VATTR_RETURN ( attributesPtr, va_fileid, cddaNodePtr->nodeID ); 1432 1433 } 1434 1435 if ( cddaNodePtr->nodeType == kAppleCDDADirectoryType ) 1436 { 1437 1438 // If this is the root directory and they want the parent, force it to 1 1439 VATTR_RETURN ( attributesPtr, va_parentid, 1 ); 1440 1441 } 1442 1443 else 1444 { 1445 1446 // Every other object has the root as its parent (flat filesystem) 1447 VATTR_RETURN ( attributesPtr, va_parentid, kAppleCDDARootFileID ); 1448 1449 } 1450 1451 VATTR_RETURN ( attributesPtr, va_type, vnode_vtype ( vNodePtr ) ); // Set the VNode type (e.g. VREG, VDIR) 1452 VATTR_RETURN ( attributesPtr, va_iosize, kPhysicalMediaBlockSize ); // Set preferred block size for I/O requests 1453 1454 // Set all the time fields 1455 VATTR_RETURN ( attributesPtr, va_create_time, cddaMountPtr->mountTime ); // Creation time 1456 VATTR_RETURN ( attributesPtr, va_modify_time, cddaMountPtr->mountTime ); // Last modification time 1457 VATTR_RETURN ( attributesPtr, va_change_time, nullTime ); // Last change time 1458 VATTR_RETURN ( attributesPtr, va_access_time, nullTime ); // Last accessed time 1459 VATTR_RETURN ( attributesPtr, va_backup_time, nullTime ); // Backup time 1460 1461 // These fields are the same 1462 VATTR_RETURN ( attributesPtr, va_fsid, vfs_statfs ( mountPtr )->f_fsid.val[0] ); 1463 VATTR_RETURN ( attributesPtr, va_uid, kUnknownUserID ); // "unknown" 1464 VATTR_RETURN ( attributesPtr, va_gid, kUnknownGroupID ); // "unknown" 1465 VATTR_RETURN ( attributesPtr, va_filerev, 0 ); 1466 VATTR_RETURN ( attributesPtr, va_gen, 0 ); 1467 VATTR_RETURN ( attributesPtr, va_flags, 0 ); 1468 VATTR_RETURN ( attributesPtr, va_rdev, 0 ); 1469 VATTR_RETURN ( attributesPtr, va_encoding, 0 ); 1470 1471 // Set some common mode flags. 1472 // Read is ok for user, group, other. 1473 VATTR_RETURN ( attributesPtr, va_mode, S_IRUSR | S_IRGRP | S_IROTH ); 1474 1475 // If it's the root, set some flags for it. 1476 if ( vnode_isvroot ( vNodePtr ) ) 1477 { 1478 1479 attributesPtr->va_mode |= S_IFDIR; // It's a directory 1480 attributesPtr->va_mode |= S_IXUSR | S_IXGRP | S_IXOTH; // Execute is ok for user, group, other 1481 1482 // Number of file refs: "." and ".." 1483 VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfRootDirReferences ); 1484 VATTR_RETURN ( attributesPtr, va_nchildren, cddaNodePtr->u.directory.entryCount - kAppleCDDANumberOfRootDirReferences ); 1485 1486 // Number of Tracks + ".", "..", and ".TOC.plist" 1487 VATTR_RETURN ( attributesPtr, va_data_size, ( cddaNodePtr->u.directory.entryCount ) * sizeof ( struct dirent ) ); 1488 1489 } 1490 1491 // If it isn't the root vnode, it's a file. 1492 else 1493 { 1494 1495 // It's a file... 1496 attributesPtr->va_mode |= DEFFILEMODE; 1497 1498 // Just the file itself 1499 VATTR_RETURN ( attributesPtr, va_nlink, kAppleCDDANumberOfFileReferences ); 1500 1501 // Is it a track? 1502 if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) 1503 { 1504 1505 // Set file size in bytes 1506 VATTR_RETURN ( attributesPtr, va_data_size, cddaNodePtr->u.file.nodeInfoPtr->numBytes ); 1507 VATTR_RETURN ( attributesPtr, va_data_alloc, cddaNodePtr->u.file.nodeInfoPtr->numBytes ); 1508 1509 } 1510 1511 // Is it the ".TOC.plist" file? 1512 else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 1513 { 1514 1515 // Set file size in bytes. 1516 VATTR_RETURN ( attributesPtr, va_data_size, cddaNodePtr->u.xmlFile.fileSize ); 1517 VATTR_RETURN ( attributesPtr, va_data_alloc, cddaNodePtr->u.xmlFile.fileSize ); 1518 1519 } 1520 1521 } 1522 1523 DebugLog ( ( "CDDA_GetAttributes: exiting...\n" ) ); 1524 1525 return ( 0 ); 1526 1527} 1528 1529 1530//----------------------------------------------------------------------------- 1531// CDDA_Inactive - This routine simply unlocks a vnode. 1532//----------------------------------------------------------------------------- 1533 1534int 1535CDDA_Inactive ( struct vnop_inactive_args * inactiveArgsPtr ) 1536/* 1537struct vnop_inactive_args { 1538 struct vnodeop_desc *a_desc; 1539 vnode_t a_vp; 1540 vfs_context_t a_context; 1541}; 1542*/ 1543{ 1544 1545 DebugLog ( ( "CDDA_Inactive: Entering.\n" ) ); 1546 1547 DebugAssert ( ( inactiveArgsPtr != NULL ) ); 1548 1549 // We don't do anything special, so call VFS function to handle it 1550 ( void ) nop_inactive ( inactiveArgsPtr ); 1551 1552 DebugLog ( ( "CDDA_Inactive: exiting...\n" ) ); 1553 1554 return ( 0 ); 1555 1556} 1557 1558 1559//----------------------------------------------------------------------------- 1560// CDDA_Remove - This routine removes a file from the name space. Since we 1561// are a read-only volume, we release any locks if appropriate 1562// and return EROFS 1563//----------------------------------------------------------------------------- 1564 1565int 1566CDDA_Remove ( struct vnop_remove_args * removeArgsPtr ) 1567/* 1568struct vnop_remove_args { 1569 struct vnodeop_desc *a_desc; 1570 vnode_t a_dvp; 1571 vnode_t a_vp; 1572 struct componentname *a_cnp; 1573 int a_flags; 1574 vfs_context_t a_context; 1575}; 1576*/ 1577{ 1578 1579 DebugLog ( ( "CDDA_Remove: Entering.\n" ) ); 1580 1581 DebugAssert ( ( removeArgsPtr != NULL ) ); 1582 1583 // We don't do anything special, so call VFS function to handle it 1584 ( void ) nop_remove ( removeArgsPtr ); 1585 1586 DebugLog ( ( "CDDA_Remove: exiting...\n" ) ); 1587 1588 // Return the read-only filesystem error 1589 return ( EROFS ); 1590 1591} 1592 1593 1594//----------------------------------------------------------------------------- 1595// CDDA_RmDir - This routine removes a directory from the name space. 1596// Since we are a read-only volume, we release any locks 1597// and return EROFS 1598//----------------------------------------------------------------------------- 1599 1600int 1601CDDA_RmDir ( struct vnop_rmdir_args * removeDirArgsPtr ) 1602/* 1603struct vnop_rmdir_args { 1604 struct vnodeop_desc *a_desc; 1605 vnode_t a_dvp; 1606 vnode_t a_vp; 1607 struct componentname *a_cnp; 1608 vfs_context_t a_context; 1609}; 1610*/ 1611{ 1612 1613 DebugLog ( ( "CDDA_RmDir: Entering.\n" ) ); 1614 1615 DebugAssert ( ( removeDirArgsPtr != NULL ) ); 1616 1617 // Call nop_rmdir to release locks 1618 ( void ) nop_rmdir ( removeDirArgsPtr ); 1619 1620 DebugLog ( ( "CDDA_RmDir: exiting...\n" ) ); 1621 1622 // Return the read-only filesystem error 1623 return ( EROFS ); 1624 1625} 1626 1627 1628//----------------------------------------------------------------------------- 1629// CDDA_Reclaim - This routine reclaims a vnode for use by the system. 1630// 1631// Remove the vnode from our node info array, drop the fs reference, 1632// free our private data. 1633//----------------------------------------------------------------------------- 1634 1635int 1636CDDA_Reclaim ( struct vnop_reclaim_args * reclaimArgsPtr ) 1637/* 1638struct vnop_reclaim_args { 1639 struct vnodeop_desc *a_desc; 1640 vnode_t a_vp; 1641 vfs_context_t a_context; 1642}; 1643*/ 1644{ 1645 1646 vnode_t vNodePtr = NULLVP; 1647 AppleCDDANodePtr cddaNodePtr = NULL; 1648 AppleCDDAMountPtr cddaMountPtr = NULL; 1649 AppleCDDANodeInfoPtr nodeInfoPtr = NULL; 1650 int error = 0; 1651 1652 DebugLog ( ( "CDDA_Reclaim: Entering.\n" ) ); 1653 1654 DebugAssert ( ( reclaimArgsPtr != NULL ) ); 1655 1656 vNodePtr = reclaimArgsPtr->a_vp; 1657 1658 DebugAssert ( ( vNodePtr != NULL ) ); 1659 1660 cddaNodePtr = VTOCDDA ( vNodePtr ); 1661 1662 DebugAssert ( ( cddaNodePtr != NULL ) ); 1663 1664 cddaMountPtr = VFSTOCDDA ( vnode_mount ( vNodePtr ) ); 1665 1666 lck_mtx_lock ( cddaMountPtr->cddaMountLock ); 1667 1668 if ( cddaNodePtr->nodeType == kAppleCDDATrackType ) 1669 { 1670 1671 nodeInfoPtr = CDDATONODEINFO ( cddaNodePtr ); 1672 nodeInfoPtr->vNodePtr = NULL; 1673 1674 } 1675 1676 else if ( cddaNodePtr->nodeType == kAppleCDDAXMLFileType ) 1677 { 1678 1679 cddaMountPtr->xmlFileVNodePtr = NULL; 1680 1681 } 1682 1683 lck_mtx_unlock ( cddaMountPtr->cddaMountLock ); 1684 1685 // Release our reference on this node 1686 vnode_removefsref ( vNodePtr ); 1687 1688 error = DisposeCDDANode ( vNodePtr ); 1689 1690 DebugLog ( ( "CDDA_Reclaim: exiting...\n" ) ); 1691 1692 return ( error ); 1693 1694} 1695 1696 1697 1698//----------------------------------------------------------------------------- 1699// CDDA_BlockToOffset - This routine converts logical block number to file 1700// offset 1701//----------------------------------------------------------------------------- 1702 1703int 1704CDDA_BlockToOffset ( struct vnop_blktooff_args * blockToOffsetArgsPtr ) 1705/* 1706struct vnop_blktooff_args { 1707 struct vnodeop_desc *a_desc; 1708 vnode_t a_vp; 1709 daddr64_t a_lblkno; 1710 off_t *a_offset; 1711}; 1712*/ 1713{ 1714 1715 DebugLog ( ( "CDDA_BlockToOffset: Entering.\n" ) ); 1716 1717 DebugAssert ( ( blockToOffsetArgsPtr != NULL ) ); 1718 1719 if ( blockToOffsetArgsPtr->a_vp == NULL ) 1720 { 1721 1722 DebugLog ( ( "CDDA_BlockToOffset: incoming vnode is NULL.\n" ) ); 1723 return ( EINVAL ); 1724 1725 } 1726 1727 *( blockToOffsetArgsPtr->a_offset ) = 1728 ( off_t ) ( blockToOffsetArgsPtr->a_lblkno * PAGE_SIZE ); 1729 1730 DebugLog ( ( "CDDA_BlockToOffset: exiting...\n" ) ); 1731 1732 return ( 0 ); 1733 1734} 1735 1736 1737//----------------------------------------------------------------------------- 1738// CDDA_OffsetToBlock - This routine converts a file offset to a logical 1739// block number 1740//----------------------------------------------------------------------------- 1741 1742int 1743CDDA_OffsetToBlock ( struct vnop_offtoblk_args * offsetToBlockArgsPtr ) 1744/* 1745struct vnop_offtoblk_args { 1746 struct vnodeop_desc *a_desc; 1747 vnode_t a_vp; 1748 off_t a_offset; 1749 daddr64_t *a_lblkno; 1750}; 1751*/ 1752{ 1753 1754 DebugLog ( ( "CDDA_OffsetToBlock: Entering.\n" ) ); 1755 1756 DebugAssert ( ( offsetToBlockArgsPtr != NULL ) ); 1757 1758 if ( offsetToBlockArgsPtr->a_vp == NULL ) 1759 { 1760 1761 DebugLog ( ( "CDDA_OffsetToBlock: incoming vnode is NULL.\n" ) ); 1762 return ( EINVAL ); 1763 1764 } 1765 1766 *( offsetToBlockArgsPtr->a_lblkno ) = ( offsetToBlockArgsPtr->a_offset / PAGE_SIZE ); 1767 1768 DebugLog ( ( "CDDA_OffsetToBlock: exiting...\n" ) ); 1769 1770 return ( 0 ); 1771 1772} 1773 1774 1775//----------------------------------------------------------------------------- 1776// CDDA_Pathconf - Return POSIX pathconf information applicable to 1777// special devices 1778//----------------------------------------------------------------------------- 1779 1780int 1781CDDA_Pathconf ( struct vnop_pathconf_args * pathConfArgsPtr ) 1782/* 1783struct vnop_pathconf_args { 1784 struct vnodeop_desc *a_desc; 1785 vnode_t a_vp; 1786 int a_name; 1787 register_t *a_retval; 1788 vfs_context_t a_context; 1789}; 1790*/ 1791{ 1792 1793 int returnValue = 0; 1794 1795 DebugLog ( ( "CDDA_Pathconf: Entering.\n" ) ); 1796 1797 DebugAssert ( ( pathConfArgsPtr != NULL ) ); 1798 1799 switch ( pathConfArgsPtr->a_name ) 1800 { 1801 1802 case _PC_LINK_MAX: 1803 *pathConfArgsPtr->a_retval = 1; 1804 break; 1805 1806 case _PC_NAME_MAX: 1807 *pathConfArgsPtr->a_retval = NAME_MAX; 1808 break; 1809 1810 case _PC_PATH_MAX: 1811 *pathConfArgsPtr->a_retval = PATH_MAX; 1812 break; 1813 1814 case _PC_CHOWN_RESTRICTED: 1815 *pathConfArgsPtr->a_retval = 1; 1816 break; 1817 1818 case _PC_NO_TRUNC: 1819 *pathConfArgsPtr->a_retval = 0; 1820 break; 1821 1822 case _PC_XATTR_SIZE_BITS: 1823 *pathConfArgsPtr->a_retval = 0; 1824 break; 1825 1826 default: 1827 returnValue = EINVAL; 1828 break; 1829 1830 } 1831 1832 DebugLog ( ( "CDDA_Pathconf: exiting with returnValue = %d.\n", returnValue ) ); 1833 1834 return ( returnValue ); 1835 1836} 1837 1838//----------------------------------------------------------------------------- 1839// CDDA_GetXAttr - Handles extended attribute reads. 1840// In this case, just for FinderInfo. 1841//----------------------------------------------------------------------------- 1842 1843int 1844CDDA_GetXAttr ( struct vnop_getxattr_args * getXAttrArgsPtr ) 1845/* 1846struct vnop_getxattr_args { 1847 struct vnodeop_desc *a_desc; 1848 vnode_t a_vp; 1849 char * a_name; 1850 uio_t a_uio; 1851 size_t 1852 *a_size; 1853 int a_options; 1854 vfs_context_t a_context; 1855}; 1856*/ 1857{ 1858 1859 AppleCDDANodePtr cddaNodePtr = NULL; 1860 FinderInfo * finderInfoPtr = NULL; 1861 char buf[32] = { 0 }; 1862 1863 DebugLog ( ( "CDDA_GetXAttr: Entering.\n" ) ); 1864 DebugAssert ( ( getXAttrArgsPtr != NULL ) ); 1865 1866 if ( strncmp ( getXAttrArgsPtr->a_name, XATTR_FINDERINFO_NAME, sizeof ( XATTR_FINDERINFO_NAME ) ) != 0 ) 1867 { 1868 return ( ENOATTR ); 1869 } 1870 1871 cddaNodePtr = VTOCDDA ( getXAttrArgsPtr->a_vp ); 1872 finderInfoPtr = ( FinderInfo * ) buf; 1873 1874 if ( !vnode_isvroot ( getXAttrArgsPtr->a_vp ) ) 1875 { 1876 1877 if ( cddaNodePtr->nodeID == kAppleCDDAXMLFileID ) 1878 { 1879 1880 DebugLog ( ( "kFinderInfoInvisibleMask\n" ) ); 1881 // Make the XML file invisible 1882 finderInfoPtr->finderFlags = kFinderInfoInvisibleMask; 1883 1884 } 1885 1886 else 1887 { 1888 finderInfoPtr->finderFlags = kFinderInfoNoFileExtensionMask; 1889 } 1890 1891 finderInfoPtr->location.v = -1; 1892 finderInfoPtr->location.h = -1; 1893 1894 if ( vnode_isreg ( getXAttrArgsPtr->a_vp ) && ( cddaNodePtr->nodeID != kAppleCDDAXMLFileID ) ) 1895 { 1896 1897 DebugLog ( ( "fileType, creator\n" ) ); 1898 finderInfoPtr->fileType = VFSTOCDDA ( vnode_mount ( cddaNodePtr->vNodePtr ) )->fileType; 1899 finderInfoPtr->fileCreator = VFSTOCDDA ( vnode_mount ( cddaNodePtr->vNodePtr ) )->fileCreator; 1900 1901 } 1902 1903 // Swap FinderInfo into big endian. FinderInfo must always be big endian when passed 1904 // back and forth across the kernel using getattrlist/getxattr. 1905 finderInfoPtr->fileType = OSSwapHostToBigInt32 ( finderInfoPtr->fileType ); 1906 finderInfoPtr->fileCreator = OSSwapHostToBigInt32 ( finderInfoPtr->fileCreator ); 1907 finderInfoPtr->finderFlags = OSSwapHostToBigInt16 ( finderInfoPtr->finderFlags ); 1908 finderInfoPtr->location.v = OSSwapHostToBigInt16 ( finderInfoPtr->location.v ); 1909 finderInfoPtr->location.h = OSSwapHostToBigInt16 ( finderInfoPtr->location.h ); 1910 1911 } 1912 1913 return ( uiomove ( ( caddr_t ) buf, ( int ) sizeof ( buf ), getXAttrArgsPtr->a_uio ) ); 1914 1915} 1916 1917 1918//----------------------------------------------------------------------------- 1919// Other macro'd function definitions 1920//----------------------------------------------------------------------------- 1921 1922int ( **gCDDA_VNodeOp_p )( void * ); 1923typedef int (*VNOPFUNC) ( void * ); 1924 1925 1926#if 0 1927#pragma mark - 1928#endif 1929 1930 1931//----------------------------------------------------------------------------- 1932// VNode Operation Vector Entry Description (Dispatch Table) 1933//----------------------------------------------------------------------------- 1934 1935struct vnodeopv_entry_desc gCDDA_VNodeOperationEntries[] = 1936{ 1937 { &vnop_default_desc, ( VNOPFUNC ) vn_default_error }, 1938 { &vnop_lookup_desc, ( VNOPFUNC ) CDDA_Lookup }, // lookup 1939 { &vnop_open_desc, ( VNOPFUNC ) CDDA_Open }, // open 1940 { &vnop_close_desc, ( VNOPFUNC ) CDDA_Close }, // close 1941 { &vnop_getattr_desc, ( VNOPFUNC ) CDDA_GetAttributes }, // getattr 1942 { &vnop_setattr_desc, ( VNOPFUNC ) nop_setattr }, // setattr 1943 { &vnop_read_desc, ( VNOPFUNC ) CDDA_Read }, // read 1944 { &vnop_fsync_desc, ( VNOPFUNC ) nop_fsync }, // fsync 1945 { &vnop_remove_desc, ( VNOPFUNC ) CDDA_Remove }, // remove 1946 { &vnop_rmdir_desc, ( VNOPFUNC ) CDDA_RmDir }, // rmdir 1947 { &vnop_readdir_desc, ( VNOPFUNC ) CDDA_ReadDir }, // readdir 1948 { &vnop_inactive_desc, ( VNOPFUNC ) CDDA_Inactive }, // inactive 1949 { &vnop_reclaim_desc, ( VNOPFUNC ) CDDA_Reclaim }, // reclaim 1950 { &vnop_pathconf_desc, ( VNOPFUNC ) CDDA_Pathconf }, // pathconf 1951 { &vnop_pagein_desc, ( VNOPFUNC ) CDDA_PageIn }, // pagein 1952 { &vnop_blktooff_desc, ( VNOPFUNC ) CDDA_BlockToOffset }, // blktoff 1953 { &vnop_offtoblk_desc, ( VNOPFUNC ) CDDA_OffsetToBlock }, // offtoblk 1954 { &vnop_getxattr_desc, ( VNOPFUNC ) CDDA_GetXAttr }, // getxattr 1955 { NULL, ( VNOPFUNC ) NULL } 1956}; 1957 1958 1959struct vnodeopv_desc gCDDA_VNodeOperationsDesc = 1960{ 1961 &gCDDA_VNodeOp_p, 1962 gCDDA_VNodeOperationEntries 1963}; 1964 1965 1966//----------------------------------------------------------------------------- 1967// End Of File 1968//----------------------------------------------------------------------------- 1969