|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* @(#)hfs_vfsutils.c 4.0 ! 26: * ! 27: * (c) 1997-1999 Apple Computer, Inc. All Rights Reserved ! 28: * ! 29: * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS. ! 30: * ! 31: * Change History (most recent first): ! 32: * ! 33: * 1-Mar-1999 Scott Roberts Dont double MALLOC on long names. ! 34: * 23-Feb-1999 Pat Dirks Change incrementing of meta refcount to be done BEFORE lock is acquired. ! 35: * 2-Feb-1999 Pat Dirks For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0. ! 36: * 18-Jan-1999 Pat Dirks Changed CopyCatalogToHFSNode to start with ACCESSPERMS instead of adding ! 37: * write access only for unlocked files (now handled via IMMUTABLE setting) ! 38: * 7-Dec-1998 Pat Dirks Changed PackCatalogInfoFileAttributeBlock to return proper I/O block size. ! 39: * 7-Dec-1998 Don Brady Pack the real text encoding instead of zero. ! 40: * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist. ! 41: * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist. ! 42: * 2-Dec-1998 Scott Roberts Copy the mdbVN correctly into the vcb. ! 43: * 3-Dec-1998 Pat Dirks Added support for ATTR_VOL_MOUNTFLAGS. ! 44: * 20-Nov-1998 Don Brady Add support for UTF-8 names. ! 45: * 18-Nov-1998 Pat Dirks Changed UnpackCommonAttributeBlock to call wait for hfs_chflags to update catalog entry when changing flags ! 46: * 13-Nov-1998 Pat Dirks Changed BestBlockSizeFit to try PAGE_SIZE only and skip check for MAXBSIZE. ! 47: * 10-Nov-1998 Pat Dirks Changed CopyCatalogToHFSNode to ensure consistency between lock flag and IMMUTABLE bits. ! 48: * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines. ! 49: * 18-Nov-1998 Pat Dirks Changed PackVolAttributeBlock to return proper logical block size ! 50: * for ATTR_VOL_IOBLOCKSIZE attribute. ! 51: * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec" ! 52: * change in the kernel. ! 53: * 23-Sep-1998 Don Brady In UnpackCommonAttributeBlock simplified setting of gid, uid and mode. ! 54: * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines. ! 55: * 17-Sep-1998 Pat Dirks Changed BestBlockSizeFit to try MAXBSIZE and PAGE_SIZE first. ! 56: * 8-Sep-1998 Don Brady Fix CopyVNodeToCatalogNode to use h_mtime for contentModDate (instead of h_ctime). ! 57: * 4-Sep-1998 Pat Dirks Added BestBlockSizeFit routine. ! 58: * 18-Aug-1998 Don Brady Change DEBUG_BREAK_MSG to a DBG_UTILS in MacToVFSError (radar #2262802). ! 59: * 30-Jun-1998 Don Brady Add calls to MacToVFSError to hfs/hfsplus mount routines (for radar #2249539). ! 60: * 22-Jun-1998 Don Brady Add more error cases to MacToVFSError; all HFS Common errors are negative. ! 61: * Changed hfsDelete to call DeleteFile for files. ! 62: * 4-Jun-1998 Pat Dirks Changed incorrect references to 'vcbAlBlkSize' to 'blockSize'; ! 63: * Added hfsCreateFileID. ! 64: * 4-Jun-1998 Don Brady Add hfsMoveRename to replace hfsMove and hfsRename. Use VPUT/VRELE macros ! 65: * instead of vput/vrele to catch bad ref counts. ! 66: * 28-May-1998 Pat Dirks Adjusted for change in definition of ATTR_CMN_NAME and removed ATTR_CMN_RAWDEVICE. ! 67: * 7-May-1998 Don Brady Added check for NULL vp to hfs_metafilelocking (radar #2233832). ! 68: * 24-Apr-1998 Pat Dirks Fixed AttributeBlockSize to return only length of variable attribute block. ! 69: * 4/21/1998 Don Brady Add SUPPORTS_MAC_ALIASES conditional (for radar #2225419). ! 70: * 4/21/1998 Don Brady Map cmNotEmpty errors to ENOTEMPTY (radar #2229259). ! 71: * 4/21/1998 Don Brady Fix up time/date conversions. ! 72: * 4/20/1998 Don Brady Remove course-grained hfs metadata locking. ! 73: * 4/18/1998 Don Brady Add VCB locking. ! 74: * 4/17/1998 Pat Dirks Fixed PackFileAttributeBlock to return more up-to-date EOF/PEOF info from vnode. ! 75: * 4/15/1998 Don Brady Add hasOverflowExtents and hfs_metafilelocking. Use ExtendBTreeFile instead ! 76: * of SetEndOfForkProc. Set forktype for system files. ! 77: * 4/14/1998 Deric Horn PackCatalogInfoAttributeBlock(), and related packing routines to ! 78: * pack attribute data given hfsCatalogInfo, without the objects vnode; ! 79: * 4/14/1998 Scott Roberts Add execute priviledges to all hfs objects. ! 80: * 4/9/1998 Don Brady Add MDB/VolumeHeader flushing to hfsUnmount; ! 81: * 4/8/1998 Don Brady Make sure vcbVRefNum field gets initialized (use MAKE_VREFNUM). ! 82: * 4/6/1998 Don Brady Removed calls to CreateVolumeCatalogCache (obsolete). ! 83: * 4/06/1998 Scott Roberts Added complex file support. ! 84: * 4/02/1998 Don Brady UpdateCatalogNode now takes parID and name as input. ! 85: * 3/31/1998 Don Brady Sync up with final HFSVolumes.h header file. ! 86: * 3/31/1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater ! 87: * than 31 characters. ! 88: * 3/30/1998 Don Brady In InitMetaFileVNode set VSYSTEM bit in vnode's v_flag. ! 89: * 3/26/1998 Don Brady Cleaned up hfs_MountXXX routines. Removed CloseBtreeFile and OpenBTreeFile. ! 90: * Simplified hfsUnmount (removed MacOS specific code). ! 91: * 3/17/1998 Don Brady AttributeBlockSize calculation did not account for the size field (4bytes). ! 92: * PackVolCommonAttributes and PackCommonAttributeBlock for ATTR_CMN_NAME ! 93: * were not setting up the name correctly. ! 94: * 3/17/1998 Don Brady Changed CreateCatalogNode interface to take kCatalogFolderNode and ! 95: * kCatalogFileNode as type input. Also, force MountCheck to always run. ! 96: * 12-nov-1997 Scott Roberts Initially created file. ! 97: * 17-Mar-98 ser Broke out and created CopyCatalogToHFSNode() ! 98: * ! 99: */ ! 100: #include <sys/param.h> ! 101: #include <sys/systm.h> ! 102: #include <sys/kernel.h> ! 103: #include <sys/malloc.h> ! 104: #include <sys/fcntl.h> ! 105: #include <sys/uio.h> ! 106: #include <sys/stat.h> ! 107: #include <sys/attr.h> ! 108: #include <sys/mount.h> ! 109: #include <libkern/libkern.h> ! 110: #include <mach/machine/simple_lock.h> ! 111: #include <mach/vm_param.h> ! 112: #include <kern/mapfs.h> ! 113: ! 114: #include "hfs.h" ! 115: #include "hfs_dbg.h" ! 116: ! 117: #include "hfscommon/headers/system/MacOSTypes.h" ! 118: #include "hfscommon/headers/system/MacOSStubs.h" ! 119: #include "hfscommon/headers/FileMgrInternal.h" ! 120: #include "hfscommon/headers/BTreesPrivate.h" ! 121: #include "hfscommon/headers/system/HFSUnicodeWrappers.h" ! 122: ! 123: #define SUPPORTS_MAC_ALIASES 0 ! 124: #define kMaxSecsForFsync 5 ! 125: ! 126: #define BYPASSBLOCKINGOPTIMIZATION 0 ! 127: ! 128: extern int (**hfs_vnodeop_p)(); ! 129: extern int count_lock_queue __P((void)); ! 130: ! 131: ! 132: OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb ); ! 133: Boolean IsARamDiskDriver( void ); ! 134: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize ); ! 135: ! 136: extern struct tm *localtime __P((const time_t *)); ! 137: extern time_t mktime __P((struct tm *)); ! 138: ! 139: int memcmp __P((const void *,const void *, size_t)); ! 140: ! 141: extern UInt16 CountRootFiles(ExtendedVCB *vcb); ! 142: extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb); ! 143: ! 144: static int InitMetaFileVNode(struct vnode *vp, u_long eof, u_long clumpSize, void *extents, ! 145: HFSCatalogNodeID fileID, void * keyCompareProc); ! 146: ! 147: static void ReleaseMetaFileVNode(struct vnode *vp); ! 148: ! 149: ! 150: //******************************************************************************* ! 151: // Routine: hfs_MountHFSVolume ! 152: // ! 153: // ! 154: //******************************************************************************* ! 155: ! 156: OSErr hfs_MountHFSVolume( register struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, struct proc *p) ! 157: { ! 158: ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 159: struct vnode *tmpvnode; ! 160: OSErr err; ! 161: DBG_FUNC_NAME("hfs_MountHFSVolume"); ! 162: DBG_PRINT_FUNC_NAME(); ! 163: ! 164: if (hfsmp == nil || mdb == nil) /* exit if bad paramater */ ! 165: return (EINVAL); ! 166: ! 167: err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */ ! 168: if (err) ! 169: return MacToVFSError(err); ! 170: ! 171: /* ! 172: * The MDB seems OK: transfer info from it into VCB ! 173: * Note - the VCB starts out clear (all zeros) ! 174: * ! 175: * vcbSigWord is the start of duplicate mdb/vcb info. ! 176: * copy all fields in mdb till the drVN field ! 177: */ ! 178: ! 179: DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0); ! 180: vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev); ! 181: bcopy( mdb, &(vcb->vcbSigWord), (Size)(&(mdb->drVN)) - (Size)mdb ); ! 182: ! 183: /* ! 184: * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring ! 185: */ ! 186: ! 187: bcopy( &mdb->drVN[1], vcb->vcbVN, mdb->drVN[0]); ! 188: vcb->vcbVN[mdb->drVN[0]] = '\0'; ! 189: ! 190: ! 191: // Initialize our dirID/nodePtr cache associated with this volume. ! 192: err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) ); ! 193: ReturnIfError( err ); ! 194: ! 195: /* ! 196: * Some fields like vcbNmAlBlks, vcbAlBlkSiz, and vcbFreeBks are just ! 197: * around for API compatability and the HFS/HFS Plus code uses new ! 198: * ExtendedVCB fields. ! 199: * note: vcbNmAlBlks * vcbAlBlkSiz still gives correct volume size ! 200: */ ! 201: vcb->totalBlocks = vcb->vcbNmAlBlks; ! 202: vcb->freeBlocks = vcb->vcbFreeBks; ! 203: vcb->blockSize = vcb->vcbAlBlkSiz; ! 204: ! 205: hfsmp->hfs_log_block_size = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); ! 206: ! 207: // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately ! 208: if ( IsARamDiskDriver() ) ! 209: { ! 210: vcb->vcbAtrb |= kHFSVolumeNoCacheRequiredMask; // yes:�mark VCB as a RAM Disk ! 211: } ! 212: ! 213: //-- copy all fields in mdb between drXTFlSize & drVolBkUp ! 214: bcopy( &(mdb->drVolBkUp), &(vcb->vcbVolBkUp), (Size)&(mdb->drXTFlSize) - (Size)&(mdb->drVolBkUp) ); // 66 bytes ! 215: ! 216: vcb->vcbXTAlBlks = DivUp( mdb->drXTFlSize, vcb->blockSize ); // Pick up PEOF of extent B*-Tree ! 217: vcb->vcbCTAlBlks = DivUp( mdb->drCTFlSize, vcb->blockSize ); // Pick up PEOF of catalog B*-Tree ! 218: vcb->nextAllocation = mdb->drAllocPtr; ! 219: vcb->vcbAllocPtr = 0; // Restart the roving allocation ptr ! 220: vcb->vcbWrCnt++; // Compensate for write of MDB on last flush ! 221: ! 222: VCB_LOCK_INIT(vcb); ! 223: ! 224: /* ! 225: * Set up Extents B-tree vnode... ! 226: */ ! 227: err = GetInitializedVNode(hfsmp, &tmpvnode); ! 228: if (err) goto MtVolErr; ! 229: err = InitMetaFileVNode(tmpvnode, mdb->drXTFlSize, vcb->vcbXTClpSiz, &mdb->drXTExtRec, ! 230: kHFSExtentsFileID, CompareExtentKeys); ! 231: if (err) goto MtVolErr; ! 232: ! 233: /* ! 234: * Set up Catalog B-tree vnode... ! 235: */ ! 236: err = GetInitializedVNode(hfsmp, &tmpvnode); ! 237: if (err) goto MtVolErr; ! 238: err = InitMetaFileVNode(tmpvnode, mdb->drCTFlSize, vcb->vcbCTClpSiz, &mdb->drCTExtRec, ! 239: kHFSCatalogFileID, CompareCatalogKeys); ! 240: if (err) goto MtVolErr; ! 241: ! 242: if ( !(vcb->vcbAtrb & (short)kHFSVolumeUnmountedMask) ) ! 243: { ! 244: UInt32 consistencyStatus; ! 245: ! 246: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit) ! 247: DBG_VFS(("hfs_MountHFSVolume: calling MountCheck...\n")); ! 248: err = MountCheck(vcb, &consistencyStatus); ! 249: DBG_VFS(("hfs_MountHFSVolume: MountCheck returned %d and %08lx\n",err, consistencyStatus)); ! 250: if ( err ) goto MtChkErr; ! 251: } ! 252: else ! 253: { ! 254: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit) ! 255: } ! 256: ! 257: /* ! 258: * all done with b-trees so we can unlock now... ! 259: */ ! 260: VOP_UNLOCK(vcb->catalogRefNum, 0, p); ! 261: VOP_UNLOCK(vcb->extentsRefNum, 0, p); ! 262: ! 263: err = noErr; ! 264: ! 265: if ( err == noErr ) ! 266: { ! 267: if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected ! 268: { ! 269: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written ! 270: } ! 271: } ! 272: goto CmdDone; ! 273: ! 274: ! 275: MtChkErr:; ! 276: InvalidateCatalogCache( vcb ); ! 277: ! 278: err = EBADF; ! 279: ! 280: //-- Release any resources allocated so far before exiting with an error: ! 281: MtVolErr:; ! 282: ReleaseMetaFileVNode(vcb->catalogRefNum); ! 283: ReleaseMetaFileVNode(vcb->extentsRefNum); ! 284: ! 285: CmdDone:; ! 286: return( err ); ! 287: ! 288: } ! 289: ! 290: //******************************************************************************* ! 291: // Routine: hfs_MountHFSPlusVolume ! 292: // ! 293: // ! 294: //******************************************************************************* ! 295: ! 296: OSErr hfs_MountHFSPlusVolume( register struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, u_long embBlkOffset, struct proc *p) ! 297: { ! 298: register ExtendedVCB *vcb; ! 299: HFSPlusForkData *fdp; ! 300: struct vnode *tmpvnode; ! 301: OSErr retval; ! 302: ! 303: if (hfsmp == nil || vhp == nil) /* exit if bad paramater */ ! 304: return (EINVAL); ! 305: ! 306: DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n", vhp->signature, vhp->version, vhp->blockSize)); ! 307: ! 308: retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */ ! 309: if (retval) ! 310: return MacToVFSError(retval); ! 311: ! 312: /* ! 313: * The VolumeHeader seems OK: transfer info from it into VCB ! 314: * Note - the VCB starts out clear (all zeros) ! 315: */ ! 316: vcb = HFSTOVCB(hfsmp); ! 317: ! 318: DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0); ! 319: vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev); ! 320: vcb->vcbSigWord = vhp->signature; ! 321: vcb->vcbCrDate = vhp->createDate; // NOTE: local time, not GMT! ! 322: vcb->vcbLsMod = UTCToLocal(vhp->modifyDate); ! 323: vcb->vcbAtrb = (UInt16) vhp->attributes; // VCB only uses lower 16 bits ! 324: vcb->vcbClpSiz = vhp->rsrcClumpSize; ! 325: vcb->vcbNxtCNID = vhp->nextCatalogID; ! 326: vcb->vcbVolBkUp = UTCToLocal(vhp->backupDate); ! 327: vcb->vcbWrCnt = vhp->writeCount; ! 328: vcb->vcbXTClpSiz = vhp->extentsFile.clumpSize; ! 329: vcb->vcbCTClpSiz = vhp->catalogFile.clumpSize; ! 330: vcb->vcbFilCnt = vhp->fileCount; ! 331: vcb->vcbDirCnt = vhp->folderCount; ! 332: ! 333: /* copy 32 bytes of Finder info */ ! 334: bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); ! 335: ! 336: /* ! 337: * vcbFreeBks is the number of free bytes divided by the (HFS compatible) allocation block size. Since the ! 338: * number of free bytes could overflow a UInt32, we actually divide both free bytes and allocation block size by ! 339: * 512 before doing the division. This prevents intermediate values from overflowing until the volume size is ! 340: * 2 TB. It's OK to divide by 512 since HFS Plus requires allocation blocks to be a multiple of 512. ! 341: */ ! 342: HFSBlocksFromTotalSectors( (vhp->blockSize / 512) * vhp->totalBlocks, &vcb->vcbAlBlkSiz, &vcb->vcbNmAlBlks ); ! 343: ! 344: vcb->vcbFreeBks = (vhp->freeBlocks * (vhp->blockSize / 512)) / (vcb->vcbAlBlkSiz / 512); ! 345: vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */ ! 346: vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */ ! 347: ! 348: VCB_LOCK_INIT(vcb); ! 349: ! 350: /* Now fill in the Extended VCB info */ ! 351: vcb->nextAllocation = vhp->nextAllocation; ! 352: vcb->totalBlocks = vhp->totalBlocks; ! 353: vcb->freeBlocks = vhp->freeBlocks; ! 354: vcb->blockSize = vhp->blockSize; ! 355: vcb->allocationsClumpSize = vhp->allocationFile.clumpSize; ! 356: vcb->attributesClumpSize = vhp->attributesFile.clumpSize; ! 357: vcb->checkedDate = vhp->checkedDate; ! 358: vcb->encodingsBitmap = vhp->encodingsBitmap; ! 359: ! 360: vcb->vcbAlBlSt = embBlkOffset; ! 361: vcb->hfsPlusIOPosOffset = embBlkOffset * 512; ! 362: ! 363: /* Update the logical block size in the mount struct (currently set up from the wrapper MDB) ! 364: using the new blocksize value: */ ! 365: hfsmp->hfs_log_block_size = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); ! 366: ! 367: // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately ! 368: // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!! ! 369: ! 370: if ( IsARamDiskDriver() ) ! 371: vcb->vcbAtrb |= kHFSVolumeNoCacheRequiredMask; // yes:�mark VCB as a RAM Disk ! 372: ! 373: // Initialize our dirID/nodePtr cache associated with this volume. ! 374: retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) ); ! 375: if (retval != noErr) goto ErrorExit; ! 376: ! 377: /* ! 378: * Set up Extents B-tree vnode... ! 379: */ ! 380: retval = GetInitializedVNode(hfsmp, &tmpvnode); ! 381: if (retval) goto ErrorExit; ! 382: fdp = &vhp->extentsFile; ! 383: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents, ! 384: kHFSExtentsFileID, CompareExtentKeysPlus); ! 385: if (retval) goto ErrorExit; ! 386: ! 387: /* ! 388: * Set up Catalog B-tree vnode... ! 389: */ ! 390: retval = GetInitializedVNode(hfsmp, &tmpvnode); ! 391: if (retval) goto ErrorExit; ! 392: fdp = &vhp->catalogFile; ! 393: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents, ! 394: kHFSCatalogFileID, CompareExtendedCatalogKeys); ! 395: if (retval) goto ErrorExit; ! 396: ! 397: /* ! 398: * Set up Allocation file vnode... ! 399: */ ! 400: retval = GetInitializedVNode(hfsmp, &tmpvnode); ! 401: if (retval) goto ErrorExit; ! 402: VTOH(tmpvnode)->h_meta->h_logBlockSize = kHFSBlockSize; /* XXX does Allocation use GetBlock? */ ! 403: VTOH(tmpvnode)->h_meta->h_physBlkPerLogBlk = 1; ! 404: fdp = &vhp->allocationFile; ! 405: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents, ! 406: kHFSAllocationFileID, NULL); ! 407: if (retval) goto ErrorExit; ! 408: ! 409: /* ! 410: * Set up Attribute B-tree vnode (optional)... ! 411: */ ! 412: if (vhp->attributesFile.logicalSize.lo > 0) { ! 413: retval = GetInitializedVNode(hfsmp, &tmpvnode); ! 414: if (retval) goto ErrorExit; ! 415: fdp = &vhp->attributesFile; ! 416: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents, ! 417: kHFSAttributesFileID, CompareAttributeKeys); ! 418: if (retval) goto ErrorExit; ! 419: } ! 420: ! 421: /* ! 422: * Now that Catalog file is open... ! 423: * get the root file count ! 424: * get the volume name from the catalog ! 425: */ ! 426: vcb->vcbNmFls = CountRootFiles(vcb); /* set up root file count */ ! 427: DBG_VFS(("hfs_MountHFSPlusVolume: root file count was %d\n", vcb->vcbNmFls)); ! 428: ! 429: retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) ); ! 430: if (retval != noErr) goto ErrorExit; ! 431: ! 432: /* ! 433: * if volume was not cleanly unmounted then do a consistency check ! 434: */ ! 435: if ( !(vcb->vcbAtrb & (short)kHFSVolumeUnmountedMask) ) ! 436: { ! 437: UInt32 consistencyStatus; ! 438: ! 439: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit) ! 440: DBG_VFS(("hfs_MountHFSPlusVolume: calling MountCheck...\n")); ! 441: retval = MacToVFSError( MountCheck(vcb, &consistencyStatus) ); ! 442: DBG_VFS(("hfs_MountHFSPlusVolume: MountCheck returned %d and %08lx\n",retval, consistencyStatus)); ! 443: if (retval) goto ErrorExit; ! 444: } ! 445: else ! 446: { ! 447: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit) ! 448: } ! 449: ! 450: /* ! 451: * all done with metadata files so we can unlock now... ! 452: */ ! 453: if (vcb->attributesRefNum != NULL) ! 454: VOP_UNLOCK(vcb->attributesRefNum, 0, p); ! 455: VOP_UNLOCK(vcb->allocationsRefNum, 0, p); ! 456: VOP_UNLOCK(vcb->catalogRefNum, 0, p); ! 457: VOP_UNLOCK(vcb->extentsRefNum, 0, p); ! 458: ! 459: if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected ! 460: { ! 461: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written ! 462: } ! 463: ! 464: DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval)); ! 465: ! 466: return (0); ! 467: ! 468: ! 469: ErrorExit: ! 470: /* ! 471: * A fatal error occured and the volume cannot be mounted ! 472: * release any resources that we aquired... ! 473: */ ! 474: ! 475: DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval)); ! 476: ! 477: InvalidateCatalogCache(vcb); ! 478: ! 479: ReleaseMetaFileVNode(vcb->allocationsRefNum); ! 480: ReleaseMetaFileVNode(vcb->attributesRefNum); ! 481: ReleaseMetaFileVNode(vcb->catalogRefNum); ! 482: ReleaseMetaFileVNode(vcb->extentsRefNum); ! 483: ! 484: return (retval); ! 485: } ! 486: ! 487: ! 488: /* ! 489: * ReleaseMetaFileVNode ! 490: * ! 491: * vp L - - ! 492: */ ! 493: static void ReleaseMetaFileVNode(struct vnode *vp) ! 494: { ! 495: if (vp) ! 496: { ! 497: FCB *fcb = VTOFCB(vp); ! 498: ! 499: if (fcb->fcbBTCBPtr != NULL) ! 500: (void) BTClosePath(fcb); /* ignore errors since there is only one path open */ ! 501: ! 502: /* release the node even if BTClosePath fails */ ! 503: if (VOP_ISLOCKED(vp)) ! 504: VPUT(vp); ! 505: else ! 506: VRELE(vp); ! 507: } ! 508: } ! 509: ! 510: ! 511: /* ! 512: * InitMetaFileVNode ! 513: * ! 514: * vp U L L ! 515: */ ! 516: static int InitMetaFileVNode(struct vnode *vp, u_long eof, u_long clumpSize, void *extents, ! 517: HFSCatalogNodeID fileID, void * keyCompareProc) ! 518: { ! 519: FCB *fcb; ! 520: ExtendedVCB *vcb; ! 521: int result = 0; ! 522: ! 523: DBG_ASSERT(vp != NULL); ! 524: DBG_ASSERT(vp->v_data != NULL); ! 525: DBG_ASSERT(VTOH(vp)->h_xfcb->fcb_vp == vp); ! 526: ! 527: vcb = VTOVCB(vp); ! 528: fcb = VTOFCB(vp); ! 529: ! 530: switch (fileID) ! 531: { ! 532: case kHFSExtentsFileID: ! 533: vcb->extentsRefNum = vp; ! 534: break; ! 535: ! 536: case kHFSCatalogFileID: ! 537: vcb->catalogRefNum = vp; ! 538: break; ! 539: ! 540: case kHFSAttributesFileID: ! 541: vcb->attributesRefNum = vp; ! 542: break; ! 543: ! 544: case kHFSAllocationFileID: ! 545: vcb->allocationsRefNum = vp; ! 546: VTOH(vp)->h_meta->h_logBlockSize = kHFSBlockSize; ! 547: VTOH(vp)->h_meta->h_physBlkPerLogBlk = 1; ! 548: break; ! 549: ! 550: default: ! 551: panic("InitMetaFileVNode: invalid fileID!"); ! 552: } ! 553: ! 554: fcb->fcbVPtr = vcb; ! 555: fcb->fcbEOF = eof; ! 556: fcb->fcbPLen = eof; ! 557: fcb->fcbClmpSize = clumpSize; ! 558: fcb->fcbFlNm = fileID; ! 559: H_FILEID(VTOH(vp)) = fileID; ! 560: H_FORKTYPE(VTOH(vp)) = kSysFile; ! 561: ! 562: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 563: ExtendedFCB *xfcb; ! 564: ! 565: xfcb = &(((struct vfsFCB *)(fcb))->fcb_extFCB); //XXX use a macro instead?! ! 566: bcopy(extents, xfcb->extents, sizeof(HFSPlusExtentRecord)); ! 567: } ! 568: else { ! 569: bcopy(extents, fcb->fcbExtRec, sizeof(HFSExtentRecord)); ! 570: } ! 571: ! 572: /* ! 573: * Lock the hfsnode and insert the hfsnode into the hash queue: ! 574: */ ! 575: hfs_vhashins(VTOH(vp)); ! 576: vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */ ! 577: ! 578: if (keyCompareProc != NULL) { ! 579: result = BTOpenPath(fcb, ! 580: (KeyCompareProcPtr) keyCompareProc, ! 581: GetBTreeBlock, ! 582: ReleaseBTreeBlock, ! 583: ExtendBTreeFile, ! 584: SetBTreeBlockSize); ! 585: result = MacToVFSError(result); ! 586: } ! 587: ! 588: return (result); ! 589: } ! 590: ! 591: ! 592: /************************************************************* ! 593: * ! 594: * Unmounts a hfs volume. ! 595: * At this point vflush() has been called (to dump all non-metadata files) ! 596: * ! 597: *************************************************************/ ! 598: ! 599: short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) ! 600: { ! 601: ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 602: int retval = E_NONE; ! 603: ! 604: (void) DisposeMRUCache(vcb->hintCachePtr); ! 605: InvalidateCatalogCache( vcb ); ! 606: // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )? ! 607: ! 608: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 609: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); ! 610: ! 611: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 612: (void) hfs_metafilelocking(hfsmp, kHFSAttributesFileID, LK_EXCLUSIVE, p); ! 613: ! 614: ReleaseMetaFileVNode(vcb->allocationsRefNum); ! 615: ReleaseMetaFileVNode(vcb->attributesRefNum); ! 616: } ! 617: ! 618: ReleaseMetaFileVNode(vcb->catalogRefNum); ! 619: ReleaseMetaFileVNode(vcb->extentsRefNum); ! 620: ! 621: return (retval); ! 622: } ! 623: ! 624: ! 625: /* ! 626: * Performs a lookup on the given dirID, name. Returns the catalog info ! 627: */ ! 628: /* XXX SER catInfo points to a hint, why do we need to pass one in ? */ ! 629: ! 630: short hfsLookup (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, UInt32 hint, hfsCatalogInfo *catInfo) ! 631: { ! 632: char tmpname[NAME_MAX + 1]; /* UUU */ ! 633: OSErr result; ! 634: ! 635: if (len != -1 ) { ! 636: bcopy(name, tmpname, len); ! 637: tmpname[len] = '\0'; ! 638: result = GetCatalogNode(vcb, parentDirID, tmpname, hint, &catInfo->spec, &catInfo->nodeData, &catInfo->hint); ! 639: } else ! 640: result = GetCatalogNode(vcb, parentDirID, name, hint, &catInfo->spec, &catInfo->nodeData, &catInfo->hint); ! 641: ! 642: if (result) ! 643: DBG_ERR(("on Lookup, GetCatalogNode returned: %d: dirid: %ld name: %s\n", result, parentDirID, name)); ! 644: ! 645: return MacToVFSError(result); ! 646: } ! 647: ! 648: ! 649: ! 650: short hfsDelete (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, short isfile, UInt32 catalogHint) ! 651: { ! 652: OSErr result = noErr; ! 653: ! 654: /* XXX have all the file's blocks been flushed/trashed? */ ! 655: ! 656: /* ! 657: * DeleteFile will delete the catalog node and then ! 658: * free up any disk space used by the file. ! 659: */ ! 660: if (isfile) ! 661: result = DeleteFile(vcb, parentDirID, name, catalogHint); ! 662: else /* is a directory */ ! 663: result = DeleteCatalogNode(vcb, parentDirID, name, catalogHint); ! 664: ! 665: if (result) ! 666: DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name)); ! 667: ! 668: return MacToVFSError(result); ! 669: } ! 670: ! 671: ! 672: short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint) ! 673: { ! 674: OSErr result = noErr; ! 675: ! 676: result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint); ! 677: ! 678: if (result) ! 679: DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName)); ! 680: ! 681: ! 682: return MacToVFSError(result); ! 683: } ! 684: ! 685: /* XXX SER pass back the hint so other people can use it */ ! 686: ! 687: ! 688: short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode) ! 689: { ! 690: OSErr result = noErr; ! 691: HFSCatalogNodeID catalogNodeID; ! 692: UInt32 catalogHint; ! 693: UInt32 type; ! 694: ! 695: /* just test for directories, the default is to create a file (like symlinks) */ ! 696: if ((mode & IFMT) == IFDIR) ! 697: type = kCatalogFolderNode; ! 698: else ! 699: type = kCatalogFileNode; ! 700: ! 701: result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint); ! 702: ! 703: return MacToVFSError(result); ! 704: } ! 705: ! 706: ! 707: short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr) ! 708: { ! 709: return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr)); ! 710: } ! 711: ! 712: ! 713: /************************************************************************/ ! 714: /* hfsGet - Returns a vnode derived from hfs */ ! 715: /* */ ! 716: /************************************************************************/ ! 717: ! 718: short hfsGet( ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode *dvp, struct vnode **vpp) ! 719: { ! 720: struct hfsnode *hp; ! 721: struct vnode *vp; ! 722: struct vnode *cp; ! 723: struct hfsmount *hfsmp; ! 724: struct hfsfilemeta *fm; ! 725: struct mount *mp; ! 726: struct vfsFCB *xfcb; ! 727: dev_t dev; ! 728: int retval; ! 729: ! 730: DBG_ASSERT(vcb != NULL); ! 731: DBG_ASSERT(catInfo != NULL); ! 732: DBG_ASSERT(vpp != NULL); ! 733: ! 734: hfsmp = VCBTOHFS(vcb); ! 735: mp = HFSTOVFS(hfsmp); ! 736: dev = hfsmp->hfs_raw_dev; ! 737: ! 738: DBG_UTILS(("\thfsGet: On '%s' with forktype of %d, nodeType of 0x%08lX\n", catInfo->spec.name, forkType, (unsigned long)catInfo->nodeData.nodeType)); ! 739: ! 740: /* Must malloc() here, since getnewvnode() can sleep */ ! 741: MALLOC(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK); ! 742: bzero((caddr_t)hp, sizeof(struct hfsnode)); ! 743: lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0); ! 744: ! 745: /* getnewvnode() does a VREF() on the vnode */ ! 746: /* Allocate a new vnode. */ ! 747: if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) { ! 748: *vpp = NULL; ! 749: goto Err_Exit; ! 750: } ! 751: ! 752: hp->h_vp = vp; /* Make HFSTOV work */ ! 753: hp->h_dev = hfsmp->hfs_raw_dev; ! 754: vp->v_data = hp; /* Make VTOH work */ ! 755: H_FILEID(hp) = catInfo->nodeData.nodeID; ! 756: H_FORKTYPE(hp) = forkType; ! 757: ! 758: /* ! 759: * Lock the hfsnode and insert the hfsnode into the hash queue: ! 760: * NOTE: THIS IS DANGEROUS IN CASES WHERE WE NEED TO BACK OUT OF THE CREATION? ! 761: */ ! 762: hfs_vhashins(hp); ! 763: hp->h_valid = HFS_VNODE_MAGIC; ! 764: ! 765: /* ! 766: * Allocate and init the right data structs: ! 767: */ ! 768: xfcb = NULL; ! 769: if (catInfo->nodeData.nodeType == kCatalogFolderNode) ! 770: { ! 771: /* Just allocate the data */ ! 772: MALLOC(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSNODE, M_WAITOK); ! 773: bzero(fm, sizeof(struct hfsfilemeta)); ! 774: MALLOC(xfcb, struct vfsFCB *, sizeof(struct vfsFCB), M_HFSNODE, M_WAITOK); ! 775: bzero(xfcb, sizeof(struct vfsFCB)); ! 776: fm->h_logBlockSize = hfsmp->hfs_log_block_size; ! 777: fm->h_physBlkPerLogBlk = fm->h_logBlockSize/kHFSBlockSize; ! 778: } ! 779: else ! 780: { ! 781: if (forkType==kDirCmplx) ! 782: { ! 783: /* Just allocate the meta part */ ! 784: MALLOC(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSNODE, M_WAITOK); ! 785: bzero(fm, sizeof(struct hfsfilemeta)); ! 786: lockinit(&fm->h_fmetalock, PINOD, "hfsfilemeta", 0, 0); ! 787: fm->h_logBlockSize = hfsmp->hfs_log_block_size; ! 788: fm->h_physBlkPerLogBlk = fm->h_logBlockSize/kHFSBlockSize; ! 789: } ! 790: else ! 791: { ! 792: Boolean unlockPar = false; ! 793: ! 794: /* Get the complex vnode, creating it if none existed */ ! 795: if (dvp->v_type == VCPLX) { ! 796: cp = dvp; ! 797: } ! 798: else { ! 799: cp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDirCmplx); ! 800: unlockPar = TRUE; ! 801: } ! 802: ! 803: if (cp == NULL) ! 804: { ! 805: if ((retval = hfsGet(vcb, catInfo, kDirCmplx, NULL, &cp))) ! 806: { ! 807: /* Couldn't get a complex node: back out of this vnode's creation ! 808: since an hfs vnode can't stand alone: */ ! 809: vp->v_flag |= VSYSTEM; /* Prevent hfs_lock et al. from going for meta lock... */ ! 810: VPUT(vp); ! 811: goto Err_Exit; ! 812: }; ! 813: unlockPar = TRUE; ! 814: } ! 815: ! 816: fm = VTOH(cp)->h_meta; ! 817: DBG_ASSERT(fm); ! 818: /* Increment the usecount, to make sure it doesnt go away on us */ ! 819: fm->h_usecount++; ! 820: lockmgr(&fm->h_fmetalock, LK_EXCLUSIVE, (struct slock *)0, CURRENT_PROC); ! 821: hp->h_relative = cp; ! 822: if (forkType == kDataFork) /* Init downlink */ ! 823: VTOH(cp)->h_relative = vp; ! 824: if (fm->h_fork == NULL) ! 825: fm->h_fork = vp; ! 826: else { ! 827: hp->h_sibling = fm->h_fork; ! 828: VTOH(fm->h_fork)->h_sibling = vp; ! 829: } ! 830: /* Increment the complex usecount, to make sure it doesnt go inactive on us */ ! 831: VREF(cp); ! 832: if (unlockPar) ! 833: VPUT(cp); ! 834: } ! 835: MALLOC(xfcb, struct vfsFCB *, sizeof(struct vfsFCB), M_HFSNODE, M_WAITOK); ! 836: bzero(xfcb, sizeof(struct vfsFCB)); ! 837: } ! 838: ! 839: hp->h_xfcb = xfcb; ! 840: hp->h_meta = fm; ! 841: ! 842: /* ! 843: * Finish filling in the record ! 844: */ ! 845: if (xfcb) { ! 846: xfcb->fcb_vp = vp; /* Make FCBTOV work */ ! 847: } ! 848: ! 849: /* ! 850: * Copy the Catalog info to the new macnode ! 851: */ ! 852: CopyCatalogToHFSNode(catInfo, hp); ! 853: ! 854: ! 855: /* Lets do some testing here */ ! 856: DBG_ASSERT(hp->h_meta); ! 857: DBG_ASSERT(VTOH(vp)==hp); ! 858: DBG_ASSERT(HTOV(hp)==vp); ! 859: if (hp->h_xfcb) { ! 860: DBG_ASSERT(VTOH(vp)->h_xfcb->fcb_vp == vp); ! 861: DBG_ASSERT(FCBTOV(&hp->h_xfcb->fcb_fcb) == vp); ! 862: DBG_ASSERT(FCBTOH(&hp->h_xfcb->fcb_fcb) == hp); ! 863: DBG_ASSERT(&hp->h_xfcb->fcb_fcb == VTOFCB(vp)); ! 864: DBG_ASSERT(&hp->h_xfcb->fcb_fcb == HTOFCB(hp)); ! 865: DBG_ASSERT(VTOVCB(vp) == FCBTOVCB(&hp->h_xfcb->fcb_fcb)); ! 866: } ! 867: if (hp->h_sibling) { ! 868: DBG_ASSERT(VTOH(hp->h_sibling)->h_sibling == vp); ! 869: DBG_ASSERT(VTOH(hp->h_sibling)->h_relative == hp->h_relative); ! 870: DBG_ASSERT(VTOH(hp->h_sibling)->h_meta == hp->h_meta); ! 871: } ! 872: if (H_FORKTYPE(hp) == kDirCmplx) { ! 873: DBG_ASSERT(hp->h_meta->h_usecount==0); ! 874: } ! 875: else { ! 876: DBG_ASSERT(hp->h_meta->h_usecount>0 && hp->h_meta->h_usecount<=2); ! 877: } ! 878: ! 879: /* ! 880: * Finish inode initialization now that aliasing has been resolved. ! 881: */ ! 882: hp->h_devvp = hfsmp->hfs_devvp; ! 883: VREF(hp->h_devvp); ! 884: *vpp = vp; ! 885: return 0; ! 886: ! 887: Err_Exit:; ! 888: FREE (hp, M_HFSNODE); ! 889: *vpp = NULL; ! 890: return (retval); ! 891: } ! 892: ! 893: ! 894: int hasOverflowExtents(struct hfsnode *hp) ! 895: { ! 896: ExtendedVCB *vcb = HTOVCB(hp); ! 897: FCB *fcb = HTOFCB(hp); ! 898: u_long blocks; ! 899: ! 900: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 901: { ! 902: ExtendedFCB *xfcb; ! 903: ! 904: xfcb = GetParallelFCB(HTOV(hp)); ! 905: if (xfcb->extents[7].blockCount == 0) ! 906: return false; ! 907: ! 908: blocks = xfcb->extents[0].blockCount + ! 909: xfcb->extents[1].blockCount + ! 910: xfcb->extents[2].blockCount + ! 911: xfcb->extents[3].blockCount + ! 912: xfcb->extents[4].blockCount + ! 913: xfcb->extents[5].blockCount + ! 914: xfcb->extents[6].blockCount + ! 915: xfcb->extents[7].blockCount; ! 916: } ! 917: else ! 918: { ! 919: if (fcb->fcbExtRec[2].blockCount == 0) ! 920: return false; ! 921: ! 922: blocks = fcb->fcbExtRec[0].blockCount + ! 923: fcb->fcbExtRec[1].blockCount + ! 924: fcb->fcbExtRec[2].blockCount; ! 925: } ! 926: ! 927: return ((fcb->fcbPLen / vcb->blockSize) > blocks); ! 928: } ! 929: ! 930: ! 931: int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p) ! 932: { ! 933: ExtendedVCB *vcb; ! 934: struct vnode *vp = NULL; ! 935: struct timeval tv; ! 936: int numOfLockedBuffs; ! 937: int retval = 0; ! 938: ! 939: vcb = HFSTOVCB(hfsmp); ! 940: ! 941: DBG_VFS((" hfs_metafilelocking: vol: %d, file: %ld %s%s%s\n", vcb->vcbVRefNum, fileID, ! 942: ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""), ! 943: ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""), ! 944: ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") )); ! 945: ! 946: /*kprintf("file: %ld flags: 0x%x %s%s%s\n",fileID, flags, ! 947: ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""), ! 948: ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""), ! 949: ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") ); ! 950: */ ! 951: ! 952: switch (fileID) ! 953: { ! 954: case kHFSExtentsFileID: ! 955: vp = vcb->extentsRefNum; ! 956: break; ! 957: ! 958: case kHFSCatalogFileID: ! 959: vp = vcb->catalogRefNum; ! 960: break; ! 961: ! 962: case kHFSAttributesFileID: ! 963: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 964: vp = vcb->attributesRefNum; ! 965: break; ! 966: } ! 967: // fall through for hfs... ! 968: ! 969: case kHFSAllocationFileID: ! 970: // bitmap is covered by Extents B-tree locking ! 971: default: ! 972: panic("hfs_lockmetafile: invalid fileID"); ! 973: } ! 974: /*kprintf("\tBefore: %d\n", lockstatus(&VTOH(vp)->h_lock)); ! 975: */ ! 976: if (vp != NULL) { ! 977: ! 978: /* Release, if necesary any locked buffer caches */ ! 979: if (flags & LK_RELEASE) { ! 980: numOfLockedBuffs = count_lock_queue(); ! 981: tv = time; ! 982: if ((numOfLockedBuffs > 32) || ((numOfLockedBuffs>1) && ((tv.tv_sec - VTOH(vp)->h_lastfsync) > kMaxSecsForFsync))) { ! 983: // kprintf("Synching meta deta...locked buffers = %d, fsync gap = %ld\n", numOfLockedBuffs, (tv.tv_sec - VTOH(vp)->h_lastfsync)); ! 984: VOP_FSYNC(vp, NOCRED, MNT_NOWAIT, p); ! 985: }; ! 986: }; ! 987: ! 988: retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p); ! 989: }; ! 990: ! 991: return retval; ! 992: } ! 993: ! 994: ! 995: void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData) ! 996: { ! 997: ExtendedVCB *vcb; ! 998: FCB *fcb; ! 999: struct hfsnode *hp; ! 1000: Boolean isHFSPlus, isResource; ! 1001: HFSPlusExtentDescriptor *extents, *parellextents; ! 1002: ExtendedFCB *extendedFCB; ! 1003: ! 1004: hp = VTOH(vp); ! 1005: vcb = HTOVCB(hp); ! 1006: fcb = HTOFCB(hp); ! 1007: isResource = (H_FORKTYPE(hp) == kRsrcFork); ! 1008: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); ! 1009: ! 1010: nodeData->contentModDate = to_hfs_time(hp->h_meta->h_mtime); /* date and time of last fork modification */ ! 1011: ! 1012: DBG_ASSERT(fcb->fcbFlNm == H_FILEID(hp)); ! 1013: ! 1014: if (isHFSPlus) { ! 1015: nodeData->attributeModDate = to_hfs_time(hp->h_meta->h_ctime); /* date and time of last modification (any kind) */ ! 1016: nodeData->accessDate = to_hfs_time(hp->h_meta->h_atime); /* date and time of last access (Rhapsody only) */ ! 1017: if (! (hp->h_meta->h_nodeflags & IN_UNSETACCESS)) { ! 1018: /* This is a tricky stuff-job: the pflags longword has two bytes of significance and they're ! 1019: combined with the mode field to yield a 32-bit permissions field as follows: ! 1020: ! 1021: +------------------------------------+ ! 1022: hp->h_meta->h_pflags: |XXXXXXXX| A |XXXXXXXX| B | ! 1023: +------------------------------------+ ! 1024: ! 1025: | ! 1026: V ! 1027: ! 1028: +------------------------------------+ ! 1029: permissions: | A | B | mode | ! 1030: +------------------------------------+ ! 1031: */ ! 1032: nodeData->permissions.permissions = (((hp->h_meta->h_pflags << 8) & 0xFF000000) | /* A */ ! 1033: ((hp->h_meta->h_pflags << 16) & 0x00FF0000) | /* B */ ! 1034: (hp->h_meta->h_mode & 0x0000FFFF)); ! 1035: nodeData->permissions.ownerID = hp->h_meta->h_uid; ! 1036: nodeData->permissions.groupID = hp->h_meta->h_gid; ! 1037: nodeData->permissions.specialDevice = hp->h_meta->h_rdev; ! 1038: }; ! 1039: }; ! 1040: ! 1041: /* the rest only applies to files */ ! 1042: if (nodeData->nodeType == kCatalogFileNode) { ! 1043: if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) { ! 1044: /* The file is locked: set the locked bit in the catalog. */ ! 1045: nodeData->nodeFlags |= kHFSFileLockedMask; ! 1046: } else { ! 1047: /* The file is unlocked: make sure the locked bit in the catalog is clear. */ ! 1048: nodeData->nodeFlags &= ~kHFSFileLockedMask; ! 1049: }; ! 1050: if (isResource) { ! 1051: extents = nodeData->rsrcExtents; ! 1052: nodeData->rsrcLogicalSize = fcb->fcbEOF; ! 1053: nodeData->rsrcPhysicalSize = fcb->fcbPLen; ! 1054: } else { ! 1055: extents = nodeData->dataExtents; ! 1056: nodeData->dataLogicalSize = fcb->fcbEOF; ! 1057: nodeData->dataPhysicalSize = fcb->fcbPLen; ! 1058: }; ! 1059: ! 1060: /* Copy the extents from their correct location */ ! 1061: if ( ! isHFSPlus) { ! 1062: /* HFS, Copy the extents from the FCB part */ ! 1063: int i; ! 1064: for (i = 0; i < kHFSExtentDensity; ++i) { ! 1065: extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock); ! 1066: extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount); ! 1067: } ! 1068: } else { ! 1069: /* HFSPlus, Copy the extents from the parallel extents */ ! 1070: extendedFCB = GetParallelFCB (HTOV(hp)); ! 1071: parellextents = extendedFCB->extents; ! 1072: bcopy ( parellextents, extents, sizeof(HFSPlusExtentRecord)); ! 1073: }; ! 1074: ! 1075: if (vp->v_type == VLNK) { ! 1076: ((struct FInfo *)(&nodeData->finderInfo))->fdType = kSymLinkFileType; ! 1077: ((struct FInfo *)(&nodeData->finderInfo))->fdCreator = kSymLinkCreator; ! 1078: ! 1079: /* Set this up as an alias */ ! 1080: #if SUPPORTS_MAC_ALIASES ! 1081: ((struct FInfo *)(&nodeData->finderInfo))->fdFlags |= kIsAlias; ! 1082: #endif ! 1083: } ! 1084: } ! 1085: } ! 1086: ! 1087: ! 1088: ! 1089: void MapFileOffset(struct hfsnode *hp, ! 1090: off_t filePosition, ! 1091: daddr_t *logBlockNumber, ! 1092: long *blockSize, ! 1093: long *blockOffset) { ! 1094: off_t extentOffset = filePosition; ! 1095: daddr_t precedingBlockCount; ! 1096: unsigned long logicalBlockSize = 0; ! 1097: unsigned long spaceRemaining; ! 1098: ! 1099: DBG_IO(("MapFileOffset: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp))); ! 1100: // DBG_IO(("\tfilePosition 0x%08lX", (u_long)filePosition)); ! 1101: ! 1102: if (filePosition < hp->h_optimizedblocksizelimit) { ! 1103: int extent; ! 1104: ! 1105: precedingBlockCount = 0; ! 1106: for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) { ! 1107: if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) && ! 1108: (extentOffset < hp->h_logicalblocktable[extent].extentLength)) { ! 1109: logicalBlockSize = MAXLOGBLOCKSIZE; ! 1110: spaceRemaining = hp->h_logicalblocktable[extent].extentLength - ((extentOffset / logicalBlockSize) * logicalBlockSize); ! 1111: *blockSize = MIN(logicalBlockSize, spaceRemaining); ! 1112: // DBG_IO(("\tUsing entry #%d: preceding blocks = 0x%X, position = 0x%8lX:\n", ! 1113: // extent, precedingBlockCount, (u_long)extentOffset)); ! 1114: break; ! 1115: }; ! 1116: precedingBlockCount += hp->h_logicalblocktable[extent].logicalBlockCount; ! 1117: extentOffset -= hp->h_logicalblocktable[extent].extentLength; ! 1118: }; ! 1119: DBG_ASSERT(logicalBlockSize > 0); ! 1120: } else { ! 1121: // DBG_IO(("\tUsing h_uniformblocksizestart = 0x%X and h_optimizedblocksizelimit = 0x%lX:\n", ! 1122: // hp->h_uniformblocksizestart, (u_long)hp->h_optimizedblocksizelimit)); ! 1123: precedingBlockCount = hp->h_uniformblocksizestart; ! 1124: extentOffset -= hp->h_optimizedblocksizelimit; ! 1125: logicalBlockSize = hp->h_meta->h_logBlockSize; ! 1126: *blockSize = logicalBlockSize; ! 1127: }; ! 1128: ! 1129: *logBlockNumber = precedingBlockCount + (extentOffset / logicalBlockSize); ! 1130: *blockOffset = extentOffset % logicalBlockSize; ! 1131: DBG_IO(("\tfilePosition 0x%08lX -> logBlockNo = 0x%X, blockSize = 0x%lX, blockOffset = 0x%lX.\n", ! 1132: (u_long)filePosition, ! 1133: *logBlockNumber, ! 1134: *blockSize, ! 1135: *blockOffset)); ! 1136: } ! 1137: ! 1138: ! 1139: long LogicalBlockSize(struct hfsnode *hp, daddr_t logicalBlockNumber) { ! 1140: if (logicalBlockNumber < hp->h_uniformblocksizestart) { ! 1141: off_t fragmentOffset = 0; ! 1142: int extent; ! 1143: ! 1144: for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) { ! 1145: if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) && ! 1146: (logicalBlockNumber < hp->h_logicalblocktable[extent].logicalBlockCount)) { ! 1147: // *filePosition = fragmentOffset + (logicalBlockNumber * MAXLOGBLOCKSIZE); ! 1148: return MIN(MAXLOGBLOCKSIZE, hp->h_logicalblocktable[extent].extentLength - (logicalBlockNumber * MAXLOGBLOCKSIZE)); ! 1149: }; ! 1150: logicalBlockNumber -= hp->h_logicalblocktable[extent].logicalBlockCount; ! 1151: fragmentOffset += hp->h_logicalblocktable[extent].extentLength; ! 1152: }; ! 1153: } else { ! 1154: // *filePosition = hp->h_optimizedblocksizelimit + ((logicalBlockNumber - hp->h_uniformblocksizestart) * hp->h_meta->h_logBlockSize); ! 1155: return hp->h_meta->h_logBlockSize; ! 1156: }; ! 1157: ! 1158: DBG_ASSERT(0 /* cannot be reached */); ! 1159: return 0; ! 1160: }; ! 1161: ! 1162: ! 1163: void UpdateBlockMappingTableEntry(struct hfsnode *hp, int index, daddr_t firstFragmentBlockNumber, long newFragmentLength) { ! 1164: // off_t currentFragmentLength; ! 1165: ! 1166: /* Compute the number of logical blocks, rounding up to include any small trailing fragments: */ ! 1167: hp->h_logicalblocktable[index].logicalBlockCount = (newFragmentLength + MAXLOGBLOCKSIZE - 1) / MAXLOGBLOCKSIZE; ! 1168: ! 1169: DBG_IO(("\tblocktable[%d]: length = 0x%lX, # blocks = 0x%lX.\n", ! 1170: index, ! 1171: newFragmentLength, ! 1172: (u_long)hp->h_logicalblocktable[index].logicalBlockCount)); ! 1173: ! 1174: #if 0 ! 1175: currentFragmentLength = hp->h_logicalblocktable[index].extentLength; ! 1176: if ((newFragmentLength > currentFragmentLength) && (currentFragmentLength > 0)) { ! 1177: daddr_t currentLastBlockNumber; ! 1178: long currentLastBlockSize; ! 1179: long newLastBlockSize; ! 1180: struct buf *bp; ! 1181: int retval; ! 1182: ! 1183: currentLastBlockNumber = firstFragmentBlockNumber + (currentFragmentLength / MAXLOGBLOCKSIZE); ! 1184: currentLastBlockSize = currentFragmentLength % MAXLOGBLOCKSIZE; ! 1185: if (currentLastBlockSize > 0) { ! 1186: newLastBlockSize = MIN(MAXLOGBLOCKSIZE, ! 1187: newFragmentLength - ! 1188: ((currentLastBlockNumber - firstFragmentBlockNumber) * MAXLOGBLOCKSIZE)); ! 1189: if (newLastBlockSize != currentLastBlockSize) { ! 1190: DBG_IO(("\t\t(Adjusting block 0x%lX from 0x%lX to 0x%lX...)\n", ! 1191: (unsigned long)currentLastBlockNumber, ! 1192: currentLastBlockSize, ! 1193: newLastBlockSize)); ! 1194: retval = bread(HTOV(hp), currentLastBlockNumber, currentLastBlockSize, NOCRED, &bp); ! 1195: if (retval == 0) { ! 1196: bexpand(bp, newLastBlockSize, NULL, RELEASE_BUFFER); ! 1197: } else { ! 1198: DBG_IO(("\t\terror (%d.) acquiring block 0x%lX; bp = 0x%08lX\n", ! 1199: retval, ! 1200: (unsigned long)currentLastBlockNumber, ! 1201: (unsigned long)bp)); ! 1202: if (bp) brelse(bp); ! 1203: }; ! 1204: }; ! 1205: }; ! 1206: }; ! 1207: #endif ! 1208: hp->h_logicalblocktable[index].extentLength = newFragmentLength; ! 1209: } ! 1210: ! 1211: ! 1212: void UpdateBlockMappingTable(struct hfsnode *hp) ! 1213: { ! 1214: ExtendedVCB *vcb = HTOVCB(hp); ! 1215: FCB *fcb = HTOFCB(hp); ! 1216: ExtendedFCB *extendedFCB; ! 1217: Boolean isHFSPlus; ! 1218: HFSPlusExtentDescriptor *parellextents; ! 1219: off_t rangeMappedSoFar; ! 1220: u_long logicalBlocksMappedSoFar; ! 1221: int i; ! 1222: off_t newFragmentLength; ! 1223: ! 1224: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); ! 1225: DBG_IO(("UpdateBlockMappingTable: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp))); ! 1226: if (H_FORKTYPE(hp) != kDirCmplx) { ! 1227: rangeMappedSoFar = 0; ! 1228: logicalBlocksMappedSoFar = 0; ! 1229: ! 1230: if ( ! isHFSPlus) { ! 1231: DBG_ASSERT(kHFSExtentDensity <= LOGBLOCKMAPENTRIES); ! 1232: for (i = 0; i < kHFSExtentDensity; ++i) { ! 1233: newFragmentLength = fcb->fcbExtRec[i].blockCount * vcb->blockSize; ! 1234: UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength); ! 1235: rangeMappedSoFar += newFragmentLength; ! 1236: logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount; ! 1237: } ! 1238: /* Zero out any remaining entries: */ ! 1239: for (i = kHFSExtentDensity; i < LOGBLOCKMAPENTRIES; ++i) { ! 1240: hp->h_logicalblocktable[i].extentLength = 0; ! 1241: }; ! 1242: #if DIAGNOSTIC ! 1243: if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSExtentDensity-1].extentLength > 0); ! 1244: #endif ! 1245: } else { ! 1246: extendedFCB = GetParallelFCB (FCBTOV(fcb)); ! 1247: parellextents = extendedFCB->extents; ! 1248: for (i = 0; i < kHFSPlusExtentDensity; ++i) { ! 1249: newFragmentLength = parellextents[i].blockCount * vcb->blockSize; ! 1250: UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength); ! 1251: rangeMappedSoFar += newFragmentLength; ! 1252: logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount; ! 1253: } ! 1254: /* No need to zero out the remaining entries [there are none]: */ ! 1255: DBG_ASSERT(LOGBLOCKMAPENTRIES <= kHFSPlusExtentDensity); ! 1256: #if DIAGNOSTIC ! 1257: if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSPlusExtentDensity-1].extentLength > 0); ! 1258: #endif ! 1259: }; ! 1260: ! 1261: hp->h_optimizedblocksizelimit = rangeMappedSoFar; ! 1262: hp->h_uniformblocksizestart = logicalBlocksMappedSoFar; ! 1263: DBG_IO(("\th_optimizedblocksizelimit = 0x%lX, h_uniformblocksizestart = 0x%lX.\n", ! 1264: (u_long)hp->h_optimizedblocksizelimit, (u_long)hp->h_uniformblocksizestart)); ! 1265: ! 1266: #if BYPASSBLOCKINGOPTIMIZATION ! 1267: hp->h_optimizedblocksizelimit = 0; ! 1268: hp->h_uniformblocksizestart = 0; ! 1269: #endif ! 1270: }; ! 1271: } ! 1272: ! 1273: void CopyCatalogToHFSNode(struct hfsCatalogInfo *catalogInfo, struct hfsnode *hp) ! 1274: { ! 1275: FCB *fcb; ! 1276: ExtendedVCB *vcb = HTOVCB(hp); ! 1277: Boolean isHFSPlus, isDirectory, isResource; ! 1278: HFSPlusExtentDescriptor *extents, *parellextents; ! 1279: ExtendedFCB *extendedFCB; ! 1280: ushort finderFlags; ! 1281: UInt8 forkType; ! 1282: ! 1283: DBG_ASSERT (hp != NULL); ! 1284: DBG_ASSERT (hp->h_valid == HFS_VNODE_MAGIC); ! 1285: DBG_ASSERT (hp->h_meta != NULL); ! 1286: ! 1287: DBG_UTILS(("\tCopying to vnode Ox%08lX: name:%s, type:%d, nodeid:%ld\n", (unsigned long)HTOV(hp), catalogInfo->spec.name, H_FORKTYPE(hp), catalogInfo->nodeData.nodeID)); ! 1288: forkType = H_FORKTYPE(hp); ! 1289: isResource = (forkType == kRsrcFork); ! 1290: isDirectory = (catalogInfo->nodeData.nodeType == kCatalogFolderNode); ! 1291: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); ! 1292: finderFlags = ((struct FInfo *)(&catalogInfo->nodeData.finderInfo))->fdFlags; ! 1293: DBG_UTILS(("\t\t forkType:%d, isResource:%d, isDirectory:%d, isHFSPlus:%d\n", forkType, isResource, isDirectory, isHFSPlus)); ! 1294: ! 1295: /* Copy over the name if NOT set yet */ ! 1296: if (H_NAME(hp) == NULL) { ! 1297: hp->h_meta->h_namelen = strlen(catalogInfo->spec.name); ! 1298: if (hp->h_meta->h_namelen <= MAXHFSVNODELEN) { ! 1299: H_NAME(hp) = hp->h_meta->h_fileName; ! 1300: } ! 1301: else { ! 1302: MALLOC(H_NAME(hp), char *, hp->h_meta->h_namelen+1, M_HFSNODE, M_WAITOK); ! 1303: hp->h_meta->h_nodeflags |= IN_LONGNAME; ! 1304: }; ! 1305: bcopy(catalogInfo->spec.name, H_NAME(hp), hp->h_meta->h_namelen+1); ! 1306: } ! 1307: else { ! 1308: DBG_ASSERT (hp->h_meta->h_namelen == strlen(catalogInfo->spec.name)); ! 1309: DBG_ASSERT (strcmp(H_NAME(hp), catalogInfo->spec.name) == 0); ! 1310: }; ! 1311: ! 1312: /* Copy over the dirid, and hint */ ! 1313: H_FILEID(hp) = catalogInfo->nodeData.nodeID; ! 1314: H_DIRID(hp) = catalogInfo->spec.parID; ! 1315: H_HINT(hp) = catalogInfo->hint; ! 1316: ! 1317: if (hp->h_xfcb != NULL) { ! 1318: ! 1319: /* Init the fcb */ ! 1320: fcb = HTOFCB(hp); ! 1321: fcb->fcbVPtr = vcb; ! 1322: fcb->fcbFlNm = catalogInfo->nodeData.nodeID; ! 1323: fcb->fcbFlags = catalogInfo->nodeData.nodeFlags; ! 1324: ! 1325: if (forkType != kDirCmplx) { ! 1326: fcb->fcbFlags &= kHFSFileLockedMask; /* Clear resource, dirty bits */ ! 1327: if (fcb->fcbFlags != 0) /* if clear, its not locked, then.. */ ! 1328: fcb->fcbFlags = fcbFileLockedMask; /* duplicate the bit for later use */ ! 1329: ! 1330: fcb->fcbClmpSize = vcb->vcbClpSiz; /*XXX why not use the one in catalogInfo? */ ! 1331: ! 1332: if (isResource) ! 1333: extents = catalogInfo->nodeData.rsrcExtents; ! 1334: else ! 1335: extents = catalogInfo->nodeData.dataExtents; ! 1336: ! 1337: /* Copy the extents to their correct location: */ ! 1338: if ( ! isHFSPlus) { ! 1339: int i; ! 1340: for (i = 0; i < kHFSExtentDensity; ++i) { ! 1341: fcb->fcbExtRec[i].startBlock = (UInt32) (extents[i].startBlock); ! 1342: fcb->fcbExtRec[i].blockCount = (UInt32) (extents[i].blockCount); ! 1343: } ! 1344: } else { ! 1345: /* HFSPlus, Copy the extents to the parallel extents */ ! 1346: extendedFCB = GetParallelFCB (FCBTOV(fcb)); ! 1347: parellextents = extendedFCB->extents; ! 1348: bcopy (extents, parellextents, sizeof(HFSPlusExtentRecord)); ! 1349: }; ! 1350: UpdateBlockMappingTable(hp); ! 1351: ! 1352: /* the valence field is overloaded to flag files over 2 gig */ ! 1353: /* since we are working with a single fork, isolate it flags <why?> */ ! 1354: /* secondFlags = catalogInfo->nodeData.valence; */ ! 1355: ! 1356: if (isResource) { ! 1357: fcb->fcbEOF = catalogInfo->nodeData.rsrcLogicalSize; ! 1358: fcb->fcbPLen = catalogInfo->nodeData.rsrcPhysicalSize; ! 1359: fcb->fcbFlags |= fcbResourceMask; ! 1360: } else { ! 1361: fcb->fcbEOF = catalogInfo->nodeData.dataLogicalSize; ! 1362: fcb->fcbPLen = catalogInfo->nodeData.dataPhysicalSize; ! 1363: }; ! 1364: }; ! 1365: }; ! 1366: ! 1367: hp->h_meta->h_mtime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format mod date in seconds */ ! 1368: hp->h_meta->h_crtime = to_bsd_time(catalogInfo->nodeData.createDate); /* UNIX-format creation date in secs. */ ! 1369: hp->h_meta->h_butime = to_bsd_time(catalogInfo->nodeData.backupDate); /* UNIX-format backup date in secs. */ ! 1370: if (isHFSPlus) { ! 1371: hp->h_meta->h_atime = to_bsd_time(catalogInfo->nodeData.accessDate); /* UNIX-format mod date in seconds */ ! 1372: hp->h_meta->h_ctime = to_bsd_time(catalogInfo->nodeData.attributeModDate); /* UNIX-format status change date */ ! 1373: } ! 1374: else { ! 1375: hp->h_meta->h_atime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format mod date in seconds */ ! 1376: hp->h_meta->h_ctime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format status change date */ ! 1377: } ! 1378: ! 1379: /* Now the rest */ ! 1380: if (isHFSPlus && (catalogInfo->nodeData.permissions.permissions & IFMT)) { ! 1381: hp->h_meta->h_uid = catalogInfo->nodeData.permissions.ownerID; ! 1382: hp->h_meta->h_gid = catalogInfo->nodeData.permissions.groupID; ! 1383: /* The 32-bit permissions field is unpacked to yield the two significant bytes of flags and the ! 1384: mode as follows: ! 1385: +------------------------------------+ ! 1386: permissions: | A | B | mode | ! 1387: +------------------------------------+ ! 1388: ! 1389: | ! 1390: V ! 1391: ! 1392: +------------------------------------+ ! 1393: hp->h_meta->h_pflags: |XXXXXXXX| A |XXXXXXXX| B | ! 1394: +------------------------------------+ ! 1395: ! 1396: */ ! 1397: hp->h_meta->h_pflags = (((catalogInfo->nodeData.permissions.permissions & 0xFF000000) >> 8) | /* A */ ! 1398: ((catalogInfo->nodeData.permissions.permissions & 0x00FF0000) >> 16)); /* B */ ! 1399: hp->h_meta->h_mode = (mode_t)(catalogInfo->nodeData.permissions.permissions & 0x0000FFFF); ! 1400: hp->h_meta->h_rdev = catalogInfo->nodeData.permissions.specialDevice; ! 1401: } else { ! 1402: /* ! 1403: * Set the permissions as determined by the mount auguments ! 1404: * but keep in account if the file or folder is hfs locked ! 1405: */ ! 1406: hp->h_meta->h_nodeflags |= IN_UNSETACCESS; ! 1407: hp->h_meta->h_uid = HTOHFS(hp)->hfs_uid; ! 1408: hp->h_meta->h_gid = HTOHFS(hp)->hfs_gid; ! 1409: /* Default access is full read/write/execute: */ ! 1410: hp->h_meta->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */ ! 1411: ! 1412: /* ... but no more than that permitted by the mount point's: */ ! 1413: if (isDirectory) { ! 1414: hp->h_meta->h_mode &= HTOHFS(hp)->hfs_dir_mask; ! 1415: } ! 1416: else { ! 1417: hp->h_meta->h_mode &= HTOHFS(hp)->hfs_file_mask; ! 1418: } ! 1419: ! 1420: if(isDirectory) ! 1421: hp->h_meta->h_mode |= IFDIR; ! 1422: else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */ ! 1423: hp->h_meta->h_mode |= IFLNK; ! 1424: else ! 1425: hp->h_meta->h_mode |= IFREG; ! 1426: ! 1427: }; ! 1428: ! 1429: /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */ ! 1430: if (!isDirectory) { ! 1431: if (catalogInfo->nodeData.nodeFlags & kHFSFileLockedMask) { ! 1432: /* The file's supposed to be locked: ! 1433: Make sure at least one of the IMMUTABLE bits is set: */ ! 1434: if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) { ! 1435: hp->h_meta->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */ ! 1436: }; ! 1437: } else { ! 1438: /* The file's supposed to be unlocked: */ ! 1439: hp->h_meta->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE); ! 1440: }; ! 1441: }; ! 1442: ! 1443: if (isDirectory) ! 1444: hp->h_size = sizeof (hfsdirentry) * (catalogInfo->nodeData.valence + 2); ! 1445: else ! 1446: hp->h_size = catalogInfo->nodeData.rsrcPhysicalSize + catalogInfo->nodeData.dataPhysicalSize; ! 1447: ! 1448: /* finish up some vnode stuff */ ! 1449: /* Set the root flag if necesary */ ! 1450: switch (hp->h_meta->h_mode & IFMT) { ! 1451: case IFDIR: ! 1452: HTOV(hp)->v_type = VDIR; ! 1453: if (H_FILEID(hp) == kRootDirID) ! 1454: HTOV(hp)->v_flag |= VROOT; ! 1455: break; ! 1456: case IFREG: ! 1457: if (forkType == kDirCmplx) ! 1458: HTOV(hp)->v_type = VCPLX; ! 1459: else ! 1460: HTOV(hp)->v_type = VREG; ! 1461: break; ! 1462: case IFLNK: ! 1463: if (forkType == kDirCmplx) ! 1464: HTOV(hp)->v_type = VCPLX; ! 1465: else ! 1466: HTOV(hp)->v_type = VLNK; ! 1467: break; ! 1468: default: ! 1469: DBG_ASSERT(false); ! 1470: HTOV(hp)->v_type = VBAD; ! 1471: }; ! 1472: } ! 1473: ! 1474: int AttributeBlockSize(struct attrlist *attrlist) { ! 1475: int size; ! 1476: attrgroup_t a; ! 1477: ! 1478: #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \ ! 1479: ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \ ! 1480: ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \ ! 1481: ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \ ! 1482: ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \ ! 1483: ATTR_CMN_FLAGS) != ATTR_CMN_VALIDMASK) ! 1484: #error AttributeBlockSize: Missing bits in common mask computation! ! 1485: #endif ! 1486: DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0); ! 1487: ! 1488: #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \ ! 1489: ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \ ! 1490: ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \ ! 1491: ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO) != ATTR_VOL_VALIDMASK) ! 1492: #error AttributeBlockSize: Missing bits in volume mask computation! ! 1493: #endif ! 1494: DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0); ! 1495: ! 1496: #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT) != ATTR_DIR_VALIDMASK) ! 1497: #error AttributeBlockSize: Missing bits in directory mask computation! ! 1498: #endif ! 1499: DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0); ! 1500: #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \ ! 1501: ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \ ! 1502: ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \ ! 1503: ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK) ! 1504: #error AttributeBlockSize: Missing bits in file mask computation! ! 1505: #endif ! 1506: DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0); ! 1507: ! 1508: #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK) ! 1509: #error AttributeBlockSize: Missing bits in fork mask computation! ! 1510: #endif ! 1511: DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0); ! 1512: ! 1513: size = 0; ! 1514: ! 1515: if ((a = attrlist->commonattr) != 0) { ! 1516: if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference); ! 1517: if (a & ATTR_CMN_DEVID) size += sizeof(dev_t); ! 1518: if (a & ATTR_CMN_FSID) size += sizeof(fsid_t); ! 1519: if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t); ! 1520: if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t); ! 1521: if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t); ! 1522: if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t); ! 1523: if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t); ! 1524: if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t); ! 1525: if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec); ! 1526: if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec); ! 1527: if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec); ! 1528: if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec); ! 1529: if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec); ! 1530: if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(UInt8); ! 1531: if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t); ! 1532: if (a & ATTR_CMN_GRPID) size += sizeof(gid_t); ! 1533: if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long); ! 1534: if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long); ! 1535: if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference); ! 1536: if (a & ATTR_CMN_FLAGS) size += sizeof(u_long); ! 1537: }; ! 1538: if ((a = attrlist->volattr) != 0) { ! 1539: if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long); ! 1540: if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long); ! 1541: if (a & ATTR_VOL_SIZE) size += sizeof(off_t); ! 1542: if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t); ! 1543: if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t); ! 1544: if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t); ! 1545: if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t); ! 1546: if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long); ! 1547: if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long); ! 1548: if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long); ! 1549: if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long); ! 1550: if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long); ! 1551: if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference); ! 1552: if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference); ! 1553: if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long); ! 1554: }; ! 1555: if ((a = attrlist->dirattr) != 0) { ! 1556: if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long); ! 1557: if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long); ! 1558: }; ! 1559: if ((a = attrlist->fileattr) != 0) { ! 1560: if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long); ! 1561: if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t); ! 1562: if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t); ! 1563: if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t); ! 1564: if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t); ! 1565: if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long); ! 1566: if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long); ! 1567: if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long); ! 1568: if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference); ! 1569: if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t); ! 1570: if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t); ! 1571: if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord); ! 1572: if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t); ! 1573: if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t); ! 1574: if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord); ! 1575: }; ! 1576: if ((a = attrlist->forkattr) != 0) { ! 1577: if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t); ! 1578: if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t); ! 1579: }; ! 1580: ! 1581: return size; ! 1582: } ! 1583: ! 1584: ! 1585: ! 1586: void PackVolCommonAttributes(struct attrlist *alist, ! 1587: struct vnode *root_vp, ! 1588: struct hfsCatalogInfo *root_catInfo, ! 1589: void **attrbufptrptr, ! 1590: void **varbufptrptr) { ! 1591: void *attrbufptr; ! 1592: void *varbufptr; ! 1593: attrgroup_t a; ! 1594: struct hfsnode *root_hp = VTOH(root_vp); ! 1595: struct mount *mp = VTOVFS(root_vp); ! 1596: struct hfsmount *hfsmp = VTOHFS(root_vp); ! 1597: struct ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 1598: u_long attrlength; ! 1599: ! 1600: attrbufptr = *attrbufptrptr; ! 1601: varbufptr = *varbufptrptr; ! 1602: ! 1603: if ((a = alist->commonattr) != 0) { ! 1604: if (a & ATTR_CMN_NAME) { ! 1605: attrlength = root_hp->h_meta->h_namelen+1; ! 1606: ((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr; ! 1607: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1608: (void) strncpy((unsigned char *)varbufptr, H_NAME(root_hp), attrlength); ! 1609: ! 1610: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1611: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1612: ++((struct attrreference *)attrbufptr); ! 1613: }; ! 1614: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev; ! 1615: if (a & ATTR_CMN_FSID) *((fsid_t *)attrbufptr)++ = mp->mnt_stat.f_fsid; ! 1616: if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = 0; ! 1617: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = VT_HFS; ! 1618: if (a & ATTR_CMN_OBJID) { ! 1619: ((fsobj_id_t *)attrbufptr)->fid_objno = 0; ! 1620: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1621: ++((fsobj_id_t *)attrbufptr); ! 1622: }; ! 1623: if (a & ATTR_CMN_OBJPERMANENTID) { ! 1624: ((fsobj_id_t *)attrbufptr)->fid_objno = 0; ! 1625: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1626: ++((fsobj_id_t *)attrbufptr); ! 1627: }; ! 1628: if (a & ATTR_CMN_PAROBJID) { ! 1629: ((fsobj_id_t *)attrbufptr)->fid_objno = 0; ! 1630: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1631: ++((fsobj_id_t *)attrbufptr); ! 1632: }; ! 1633: VCB_LOCK(vcb); ! 1634: if (a & ATTR_CMN_SCRIPT) *((text_encoding_t *)attrbufptr)++ = vcb->volumeNameEncodingHint; ! 1635: /* NOTE: all VCB dates are in local Mac OS time */ ! 1636: if (a & ATTR_CMN_CRTIME) { ! 1637: /* ! 1638: * HFS Plus stores the volume create date in *local* ! 1639: * time in the volume header. So don't use the create ! 1640: * date from the vcb. Use the root's crtime instead. ! 1641: */ ! 1642: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 1643: ((struct timespec *)attrbufptr)->tv_sec = root_hp->h_meta->h_crtime; ! 1644: } else { ! 1645: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbCrDate); ! 1646: } ! 1647: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1648: ++((struct timespec *)attrbufptr); ! 1649: }; ! 1650: if (a & ATTR_CMN_MODTIME) { ! 1651: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); ! 1652: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1653: ++((struct timespec *)attrbufptr); ! 1654: }; ! 1655: if (a & ATTR_CMN_CHGTIME) { ! 1656: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); ! 1657: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1658: ++((struct timespec *)attrbufptr); ! 1659: }; ! 1660: if (a & ATTR_CMN_ACCTIME) { ! 1661: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); ! 1662: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1663: ++((struct timespec *)attrbufptr); ! 1664: }; ! 1665: if (a & ATTR_CMN_BKUPTIME) { ! 1666: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbVolBkUp); ! 1667: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1668: ++((struct timespec *)attrbufptr); ! 1669: }; ! 1670: if (a & ATTR_CMN_FNDRINFO) { ! 1671: bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo)); ! 1672: attrbufptr += sizeof(vcb->vcbFndrInfo); ! 1673: }; ! 1674: VCB_UNLOCK(vcb); ! 1675: if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = root_hp->h_meta->h_uid; ! 1676: if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = root_hp->h_meta->h_gid; ! 1677: if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)root_hp->h_meta->h_mode; ! 1678: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ ! 1679: if (a & ATTR_CMN_NAMEDATTRLIST) { ! 1680: attrlength = 0; ! 1681: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; ! 1682: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1683: ! 1684: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1685: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1686: ++((struct attrreference *)attrbufptr); ! 1687: }; ! 1688: if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags; ! 1689: }; ! 1690: ! 1691: *attrbufptrptr = attrbufptr; ! 1692: *varbufptrptr = varbufptr; ! 1693: } ! 1694: ! 1695: ! 1696: ! 1697: void PackVolAttributeBlock(struct attrlist *alist, ! 1698: struct vnode *root_vp, ! 1699: struct hfsCatalogInfo *root_catInfo, ! 1700: void **attrbufptrptr, ! 1701: void **varbufptrptr) { ! 1702: void *attrbufptr; ! 1703: void *varbufptr; ! 1704: attrgroup_t a; ! 1705: struct mount *mp = VTOVFS(root_vp); ! 1706: struct hfsmount *hfsmp = VTOHFS(root_vp); ! 1707: struct ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 1708: u_long attrlength; ! 1709: ! 1710: attrbufptr = *attrbufptrptr; ! 1711: varbufptr = *varbufptrptr; ! 1712: ! 1713: if ((a = alist->volattr) != 0) { ! 1714: VCB_LOCK(vcb); ! 1715: if (a & ATTR_VOL_FSTYPE) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum; ! 1716: if (a & ATTR_VOL_SIGNATURE) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord; ! 1717: if (a & ATTR_VOL_SIZE) *((off_t *)attrbufptr)++ = (off_t)vcb->totalBlocks * (off_t)vcb->blockSize; ! 1718: if (a & ATTR_VOL_SPACEFREE) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize; ! 1719: if (a & ATTR_VOL_SPACEAVAIL) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize; ! 1720: if (a & ATTR_VOL_MINALLOCATION) *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize; ! 1721: if (a & ATTR_VOL_ALLOCATIONCLUMP) *((off_t *)attrbufptr)++ = (off_t)vcb->allocationsClumpSize; ! 1722: if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_log_block_size; ! 1723: if (a & ATTR_VOL_OBJCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt; ! 1724: if (a & ATTR_VOL_FILECOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt; ! 1725: if (a & ATTR_VOL_DIRCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt; ! 1726: if (a & ATTR_VOL_MAXOBJCOUNT) *((u_long *)attrbufptr)++ = 0xFFFFFFFF; ! 1727: if (a & ATTR_VOL_MOUNTPOINT) { ! 1728: attrlength = strlen(hfsmp->hfs_mountpoint) + 1; ! 1729: ((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr; ! 1730: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1731: (void) strcpy((unsigned char *)varbufptr, hfsmp->hfs_mountpoint); ! 1732: ! 1733: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1734: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1735: ++((struct attrreference *)attrbufptr); ! 1736: }; ! 1737: if (a & ATTR_VOL_NAME) { ! 1738: attrlength = VTOH(root_vp)->h_meta->h_namelen + 1; ! 1739: ((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr; ! 1740: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1741: strncpy((char *)varbufptr, H_NAME(VTOH(root_vp)), attrlength); ! 1742: ! 1743: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1744: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1745: ++((struct attrreference *)attrbufptr); ! 1746: }; ! 1747: if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag; ! 1748: VCB_UNLOCK(vcb); ! 1749: }; ! 1750: ! 1751: *attrbufptrptr = attrbufptr; ! 1752: *varbufptrptr = varbufptr; ! 1753: } ! 1754: ! 1755: ! 1756: ! 1757: ! 1758: void PackVolumeInfo(struct attrlist *alist, ! 1759: struct vnode *root_vp, ! 1760: struct hfsCatalogInfo *root_catinfo, ! 1761: void **attrbufptrptr, ! 1762: void **varbufptrptr) { ! 1763: ! 1764: PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr); ! 1765: PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr); ! 1766: }; ! 1767: ! 1768: // Pack the common attribute contents of an objects hfsCatalogInfo ! 1769: void PackCommonCatalogInfoAttributeBlock(struct attrlist *alist, ! 1770: struct vnode *root_vp, ! 1771: struct hfsCatalogInfo *catalogInfo, ! 1772: void **attrbufptrptr, ! 1773: void **varbufptrptr ) ! 1774: { ! 1775: struct hfsnode *hp; ! 1776: void *attrbufptr; ! 1777: void *varbufptr; ! 1778: attrgroup_t a; ! 1779: u_long attrlength; ! 1780: ! 1781: hp = VTOH(root_vp); ! 1782: attrbufptr = *attrbufptrptr; ! 1783: varbufptr = *varbufptrptr; ! 1784: ! 1785: if ((a = alist->commonattr) != 0) ! 1786: { ! 1787: if (a & ATTR_CMN_NAME) ! 1788: { ! 1789: attrlength = strlen(catalogInfo->spec.name) + 1; ! 1790: ((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr; ! 1791: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1792: (void) strncpy((unsigned char *)varbufptr, (unsigned char *) &(catalogInfo->spec.name), attrlength); ! 1793: // ((char *) varbufptr)[attrlength-1] = 0; // Now it's a C string ! 1794: ! 1795: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1796: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1797: ++((struct attrreference *)attrbufptr); ! 1798: }; ! 1799: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hp->h_dev; ! 1800: if (a & ATTR_CMN_FSID) *((fsid_t *)attrbufptr)++ = VTOVFS(root_vp)->mnt_stat.f_fsid; ! 1801: if (a & ATTR_CMN_OBJTYPE) ! 1802: { ! 1803: if ( catalogInfo->nodeData.nodeType == kCatalogFolderNode ) ! 1804: *((fsobj_type_t *)attrbufptr)++ = VDIR; ! 1805: else //XXX could be more robust in object type handling ! 1806: *((fsobj_type_t *)attrbufptr)++ = VREG; ! 1807: } ! 1808: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag; ! 1809: if (a & ATTR_CMN_OBJID) ! 1810: { ! 1811: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.nodeID; // H_FILEID(hp); ! 1812: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1813: ++((fsobj_id_t *)attrbufptr); ! 1814: }; ! 1815: if (a & ATTR_CMN_OBJPERMANENTID) ! 1816: { ! 1817: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.nodeID; // H_FILEID(hp); ! 1818: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1819: ++((fsobj_id_t *)attrbufptr); ! 1820: }; ! 1821: if (a & ATTR_CMN_PAROBJID) ! 1822: { ! 1823: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->spec.parID; // H_DIRID(hp); ! 1824: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1825: ++((fsobj_id_t *)attrbufptr); ! 1826: }; ! 1827: if (a & ATTR_CMN_SCRIPT) ! 1828: { ! 1829: if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) { ! 1830: *((text_encoding_t *)attrbufptr)++ = catalogInfo->nodeData.textEncoding; ! 1831: } else { ! 1832: *((text_encoding_t *)attrbufptr)++ = 0; ! 1833: } ! 1834: }; ! 1835: if (a & ATTR_CMN_CRTIME) ! 1836: { ! 1837: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.createDate); ! 1838: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1839: ++((struct timespec *)attrbufptr); ! 1840: }; ! 1841: if (a & ATTR_CMN_MODTIME) ! 1842: { ! 1843: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.contentModDate); ! 1844: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1845: ++((struct timespec *)attrbufptr); ! 1846: }; ! 1847: if (a & ATTR_CMN_CHGTIME) ! 1848: { ! 1849: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.attributeModDate); ! 1850: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1851: ++((struct timespec *)attrbufptr); ! 1852: }; ! 1853: if (a & ATTR_CMN_ACCTIME) ! 1854: { ! 1855: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.accessDate); ! 1856: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1857: ++((struct timespec *)attrbufptr); ! 1858: }; ! 1859: if (a & ATTR_CMN_BKUPTIME) ! 1860: { ! 1861: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.backupDate); ! 1862: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1863: ++((struct timespec *)attrbufptr); ! 1864: }; ! 1865: if (a & ATTR_CMN_FNDRINFO) ! 1866: { ! 1867: bcopy (&catalogInfo->nodeData.finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.finderInfo)); ! 1868: attrbufptr += sizeof(catalogInfo->nodeData.finderInfo); ! 1869: bcopy (&catalogInfo->nodeData.extFinderInfo, attrbufptr, sizeof(catalogInfo->nodeData.extFinderInfo)); ! 1870: attrbufptr += sizeof(catalogInfo->nodeData.extFinderInfo); ! 1871: }; ! 1872: if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = catalogInfo->nodeData.permissions.ownerID; ! 1873: if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.permissions.groupID; ! 1874: if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)(mode_t)(catalogInfo->nodeData.permissions.permissions & 0x0000FFFF); ! 1875: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ ! 1876: if (a & ATTR_CMN_NAMEDATTRLIST) ! 1877: { ! 1878: attrlength = 0; ! 1879: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; ! 1880: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1881: ! 1882: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1883: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1884: ++((struct attrreference *)attrbufptr); ! 1885: }; ! 1886: if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = (u_long)((((catalogInfo->nodeData.permissions.permissions & 0xFFFF0000) >> 8) & 0x00FF0000) | ! 1887: (((catalogInfo->nodeData.permissions.permissions & 0xFFFF0000) >> 24) & 0x000000FF)); ! 1888: }; ! 1889: ! 1890: *attrbufptrptr = attrbufptr; ! 1891: *varbufptrptr = varbufptr; ! 1892: } ! 1893: ! 1894: ! 1895: void PackCommonAttributeBlock(struct attrlist *alist, ! 1896: struct vnode *vp, ! 1897: struct hfsCatalogInfo *catInfo, ! 1898: void **attrbufptrptr, ! 1899: void **varbufptrptr) { ! 1900: struct hfsnode *hp; ! 1901: void *attrbufptr; ! 1902: void *varbufptr; ! 1903: attrgroup_t a; ! 1904: u_long attrlength; ! 1905: ! 1906: hp = VTOH(vp); ! 1907: ! 1908: attrbufptr = *attrbufptrptr; ! 1909: varbufptr = *varbufptrptr; ! 1910: ! 1911: if ((a = alist->commonattr) != 0) { ! 1912: if (a & ATTR_CMN_NAME) { ! 1913: attrlength = hp->h_meta->h_namelen + 1; ! 1914: ((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr; ! 1915: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1916: (void) strncpy((unsigned char *)varbufptr, H_NAME(hp), attrlength); ! 1917: ! 1918: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1919: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1920: ++((struct attrreference *)attrbufptr); ! 1921: }; ! 1922: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hp->h_dev; ! 1923: if (a & ATTR_CMN_FSID) *((fsid_t *)attrbufptr)++ = VTOVFS(vp)->mnt_stat.f_fsid; ! 1924: if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type; ! 1925: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag; ! 1926: if (a & ATTR_CMN_OBJID) { ! 1927: ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp); ! 1928: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1929: ++((fsobj_id_t *)attrbufptr); ! 1930: }; ! 1931: if (a & ATTR_CMN_OBJPERMANENTID) { ! 1932: ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp); ! 1933: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1934: ++((fsobj_id_t *)attrbufptr); ! 1935: }; ! 1936: if (a & ATTR_CMN_PAROBJID) { ! 1937: ((fsobj_id_t *)attrbufptr)->fid_objno = H_DIRID(hp); ! 1938: ((fsobj_id_t *)attrbufptr)->fid_generation = 0; ! 1939: ++((fsobj_id_t *)attrbufptr); ! 1940: }; ! 1941: if (a & ATTR_CMN_SCRIPT) ! 1942: { ! 1943: if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) { ! 1944: *((text_encoding_t *)attrbufptr)++ = catInfo->nodeData.textEncoding; ! 1945: } else { ! 1946: *((text_encoding_t *)attrbufptr)++ = 0; ! 1947: } ! 1948: }; ! 1949: if (a & ATTR_CMN_CRTIME) { ! 1950: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_crtime; ! 1951: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1952: ++((struct timespec *)attrbufptr); ! 1953: }; ! 1954: if (a & ATTR_CMN_MODTIME) { ! 1955: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_mtime; ! 1956: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1957: ++((struct timespec *)attrbufptr); ! 1958: }; ! 1959: if (a & ATTR_CMN_CHGTIME) { ! 1960: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_ctime; ! 1961: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1962: ++((struct timespec *)attrbufptr); ! 1963: }; ! 1964: if (a & ATTR_CMN_ACCTIME) { ! 1965: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_atime; ! 1966: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1967: ++((struct timespec *)attrbufptr); ! 1968: }; ! 1969: if (a & ATTR_CMN_BKUPTIME) { ! 1970: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_butime; ! 1971: ((struct timespec *)attrbufptr)->tv_nsec = 0; ! 1972: ++((struct timespec *)attrbufptr); ! 1973: }; ! 1974: if (a & ATTR_CMN_FNDRINFO) { ! 1975: bcopy (&catInfo->nodeData.finderInfo, attrbufptr, sizeof(catInfo->nodeData.finderInfo)); ! 1976: attrbufptr += sizeof(catInfo->nodeData.finderInfo); ! 1977: bcopy (&catInfo->nodeData.extFinderInfo, attrbufptr, sizeof(catInfo->nodeData.extFinderInfo)); ! 1978: attrbufptr += sizeof(catInfo->nodeData.extFinderInfo); ! 1979: }; ! 1980: if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = hp->h_meta->h_uid; ! 1981: if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = hp->h_meta->h_gid; ! 1982: if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)hp->h_meta->h_mode; ! 1983: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ ! 1984: if (a & ATTR_CMN_NAMEDATTRLIST) { ! 1985: attrlength = 0; ! 1986: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; ! 1987: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 1988: ! 1989: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 1990: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 1991: ++((struct attrreference *)attrbufptr); ! 1992: }; ! 1993: if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags; ! 1994: }; ! 1995: ! 1996: *attrbufptrptr = attrbufptr; ! 1997: *varbufptrptr = varbufptr; ! 1998: } ! 1999: ! 2000: ! 2001: // Pack the directory attributes given hfsCatalogInfo ! 2002: void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr ) ! 2003: { ! 2004: void *attrbufptr; ! 2005: attrgroup_t a; ! 2006: ! 2007: attrbufptr = *attrbufptrptr; ! 2008: a = alist->dirattr; ! 2009: ! 2010: if ( (catInfo->nodeData.nodeType == kCatalogFolderNode) && (a != 0) ) ! 2011: { ! 2012: /* The 'link count' is faked as 1 (the parent entry and "."). In reality it would include at least an additional link for the ".." in each subdirectory. */ ! 2013: if (a & ATTR_DIR_LINKCOUNT) *((u_long *)attrbufptr)++ = 2; ! 2014: if (a & ATTR_DIR_ENTRYCOUNT) *((u_long *)attrbufptr)++ = catInfo->nodeData.valence; ! 2015: }; ! 2016: ! 2017: *attrbufptrptr = attrbufptr; ! 2018: } ! 2019: ! 2020: ! 2021: void PackDirAttributeBlock(struct attrlist *alist, ! 2022: struct vnode *vp, ! 2023: struct hfsCatalogInfo *catInfo, ! 2024: void **attrbufptrptr, ! 2025: void **varbufptrptr) { ! 2026: void *attrbufptr; ! 2027: // void *varbufptr; ! 2028: attrgroup_t a; ! 2029: // u_long attrlength; ! 2030: ! 2031: attrbufptr = *attrbufptrptr; ! 2032: // varbufptr = *varbufptrptr; ! 2033: ! 2034: a = alist->dirattr; ! 2035: if ((vp->v_type == VDIR) && (a != 0)) { ! 2036: /* The 'link count' is faked as 1 (the parent entry and "."). In reality it would include at least ! 2037: an additional link for the ".." in each subdirectory. */ ! 2038: if (a & ATTR_DIR_LINKCOUNT) *((u_long *)attrbufptr)++ = 2; ! 2039: if (a & ATTR_DIR_ENTRYCOUNT) *((u_long *)attrbufptr)++ = catInfo->nodeData.valence; ! 2040: }; ! 2041: ! 2042: *attrbufptrptr = attrbufptr; ! 2043: // *varbufptrptr = varbufptr; ! 2044: } ! 2045: ! 2046: ! 2047: ! 2048: // Pack the file attributes from the hfsCatalogInfo for the file. ! 2049: void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct hfsCatalogInfo *catInfo, struct vnode *root_vp, void **attrbufptrptr, void **varbufptrptr ) ! 2050: { ! 2051: void *attrbufptr; ! 2052: void *varbufptr; ! 2053: attrgroup_t a; ! 2054: u_long attrlength; ! 2055: ExtendedVCB *vcb = VTOVCB(root_vp); ! 2056: ! 2057: attrbufptr = *attrbufptrptr; ! 2058: varbufptr = *varbufptrptr; ! 2059: ! 2060: a = alist->fileattr; ! 2061: if ( (catInfo->nodeData.nodeType == kCatalogFileNode) && (a != 0) ) ! 2062: { ! 2063: if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; /* There ARE no hard links... */ ! 2064: if (a & ATTR_FILE_TOTALSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize + (off_t)catInfo->nodeData.rsrcLogicalSize; ! 2065: if (a & ATTR_FILE_ALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize + (off_t)catInfo->nodeData.rsrcPhysicalSize; ! 2066: if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_log_block_size); ! 2067: if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = vcb->vcbClpSiz; //XXX Yikes, this is just the vcb clump size ! 2068: if (a & ATTR_FILE_DEVTYPE) *((u_long *)attrbufptr)++ = (u_long)catInfo->nodeData.permissions.specialDevice; ! 2069: if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */ ! 2070: if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */ ! 2071: if (a & ATTR_FILE_FORKLIST) ! 2072: { ! 2073: attrlength = 0; ! 2074: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; ! 2075: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 2076: ! 2077: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 2078: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 2079: ++((struct attrreference *)attrbufptr); ! 2080: }; ! 2081: if (a & ATTR_FILE_DATALENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize; ! 2082: if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize; ! 2083: if (a & ATTR_FILE_DATAEXTENTS) ! 2084: { ! 2085: bcopy(&catInfo->nodeData.dataExtents, attrbufptr, sizeof(extentrecord)); ! 2086: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2087: }; ! 2088: if (a & ATTR_FILE_RSRCLENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcLogicalSize; ! 2089: if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcPhysicalSize; ! 2090: if (a & ATTR_FILE_RSRCEXTENTS) ! 2091: { ! 2092: bcopy(&catInfo->nodeData.rsrcExtents, attrbufptr, sizeof(extentrecord)); ! 2093: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2094: }; ! 2095: }; ! 2096: ! 2097: *attrbufptrptr = attrbufptr; ! 2098: *varbufptrptr = varbufptr; ! 2099: } ! 2100: ! 2101: ! 2102: void PackFileAttributeBlock(struct attrlist *alist, ! 2103: struct vnode *vp, ! 2104: struct hfsCatalogInfo *catInfo, ! 2105: void **attrbufptrptr, ! 2106: void **varbufptrptr) { ! 2107: struct hfsnode *hp = VTOH(vp); ! 2108: FCB *fcb = HTOFCB(hp); ! 2109: ExtendedFCB *extendedFCB; ! 2110: HFSPlusExtentDescriptor *parellextents; ! 2111: ExtendedVCB *vcb = HTOVCB(hp); ! 2112: Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); ! 2113: void *attrbufptr = *attrbufptrptr; ! 2114: void *varbufptr = *varbufptrptr; ! 2115: attrgroup_t a = alist->fileattr; ! 2116: u_long attrlength; ! 2117: ! 2118: if ((vp->v_type == VREG) && (a != 0)) { ! 2119: if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; /* There ARE no hard links... */ ! 2120: if (a & ATTR_FILE_TOTALSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize + ! 2121: (off_t)catInfo->nodeData.rsrcLogicalSize; ! 2122: if (a & ATTR_FILE_ALLOCSIZE) { ! 2123: switch (H_FORKTYPE(hp)) { ! 2124: case kDataFork: ! 2125: *((off_t *)attrbufptr)++ = (off_t)fcb->fcbPLen + (off_t)catInfo->nodeData.rsrcPhysicalSize; ! 2126: case kRsrcFork: ! 2127: *((off_t *)attrbufptr)++ = (off_t)fcb->fcbPLen + (off_t)catInfo->nodeData.dataPhysicalSize; ! 2128: default: ! 2129: *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize + ! 2130: (off_t)catInfo->nodeData.rsrcPhysicalSize; ! 2131: }; ! 2132: }; ! 2133: if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = hp->h_meta->h_logBlockSize; ! 2134: if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize; ! 2135: if (a & ATTR_FILE_DEVTYPE) *((u_long *)attrbufptr)++ = (u_long)catInfo->nodeData.permissions.specialDevice; ! 2136: if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */ ! 2137: if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */ ! 2138: if (a & ATTR_FILE_FORKLIST) { ! 2139: attrlength = 0; ! 2140: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; ! 2141: ((struct attrreference *)attrbufptr)->attr_length = attrlength; ! 2142: ! 2143: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ ! 2144: varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); ! 2145: ++((struct attrreference *)attrbufptr); ! 2146: }; ! 2147: if (H_FORKTYPE(hp) == kDataFork) { ! 2148: if (a & ATTR_FILE_DATALENGTH) ! 2149: #if MACH_NBC ! 2150: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped && ! 2151: (!vp->v_vm_info->filesize)) { ! 2152: *((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size; ! 2153: } ! 2154: else ! 2155: #endif /* MACH_NBC */ ! 2156: *((off_t *)attrbufptr)++ = fcb->fcbEOF; ! 2157: if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen; ! 2158: if (a & ATTR_FILE_DATAEXTENTS) { ! 2159: if ( ! isHFSPlus) { ! 2160: /* HFS, Copy the extents from the FCB part */ ! 2161: int i; ! 2162: HFSPlusExtentRecord extents; ! 2163: for (i = 0; i < kHFSExtentDensity; ++i) { ! 2164: extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock); ! 2165: extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount); ! 2166: }; ! 2167: bcopy ( extents, attrbufptr, sizeof(extentrecord)); ! 2168: } else { ! 2169: /* HFSPlus, Copy the extents from the parallel extents */ ! 2170: extendedFCB = GetParallelFCB (HTOV(hp)); ! 2171: parellextents = extendedFCB->extents; ! 2172: bcopy ( parellextents, attrbufptr, sizeof(extentrecord)); ! 2173: }; ! 2174: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2175: }; ! 2176: } else { ! 2177: if (a & ATTR_FILE_DATALENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize; ! 2178: if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize; ! 2179: if (a & ATTR_FILE_DATAEXTENTS) { ! 2180: bcopy(&catInfo->nodeData.dataExtents, attrbufptr, sizeof(extentrecord)); ! 2181: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2182: }; ! 2183: }; ! 2184: if (H_FORKTYPE(hp) == kRsrcFork) { ! 2185: if (a & ATTR_FILE_RSRCLENGTH) ! 2186: #if MACH_NBC ! 2187: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped && ! 2188: (!vp->v_vm_info->filesize)) { ! 2189: *((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size; ! 2190: } ! 2191: else ! 2192: #endif /* MACH_NBC */ ! 2193: *((off_t *)attrbufptr)++ = fcb->fcbEOF; ! 2194: if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen; ! 2195: if (a & ATTR_FILE_RSRCEXTENTS) { ! 2196: if ( ! isHFSPlus) { ! 2197: /* HFS, Copy the extents from the FCB part */ ! 2198: int i; ! 2199: HFSPlusExtentRecord extents; ! 2200: for (i = 0; i < kHFSExtentDensity; ++i) { ! 2201: extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock); ! 2202: extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount); ! 2203: }; ! 2204: bcopy ( extents, attrbufptr, sizeof(extentrecord)); ! 2205: } else { ! 2206: /* HFSPlus, Copy the extents from the parallel extents */ ! 2207: extendedFCB = GetParallelFCB (HTOV(hp)); ! 2208: parellextents = extendedFCB->extents; ! 2209: bcopy ( parellextents, attrbufptr, sizeof(extentrecord)); ! 2210: }; ! 2211: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2212: }; ! 2213: } else { ! 2214: if (a & ATTR_FILE_RSRCLENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcLogicalSize; ! 2215: if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcPhysicalSize; ! 2216: if (a & ATTR_FILE_RSRCEXTENTS) { ! 2217: bcopy(&catInfo->nodeData.rsrcExtents, attrbufptr, sizeof(extentrecord)); ! 2218: attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); ! 2219: }; ! 2220: }; ! 2221: }; ! 2222: ! 2223: *attrbufptrptr = attrbufptr; ! 2224: *varbufptrptr = varbufptr; ! 2225: } ! 2226: ! 2227: #if 0 ! 2228: void PackForkAttributeBlock(struct attrlist *alist, ! 2229: struct vnode *vp, ! 2230: struct hfsCatalogInfo *catInfo, ! 2231: void **attrbufptrptr, ! 2232: void **varbufptrptr) { ! 2233: /* XXX PPD TBC */ ! 2234: } ! 2235: #endif ! 2236: ! 2237: ! 2238: // This routine takes catInfo, and alist, as inputs and packs it into an attribute block. ! 2239: void PackCatalogInfoAttributeBlock ( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr) ! 2240: { ! 2241: //XXX Preflight that alist only contains bits with fields in catInfo ! 2242: ! 2243: PackCommonCatalogInfoAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr ); ! 2244: ! 2245: switch ( catInfo->nodeData.nodeType ) ! 2246: { ! 2247: case kCatalogFolderNode: ! 2248: PackCatalogInfoDirAttributeBlock( alist, catInfo, attrbufptrptr, varbufptrptr ); ! 2249: break; ! 2250: ! 2251: case kCatalogFileNode: ! 2252: PackCatalogInfoFileAttributeBlock( alist, catInfo, root_vp, attrbufptrptr, varbufptrptr ); ! 2253: break; ! 2254: ! 2255: default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */ ! 2256: /* XXX PPD - Panic? */ ! 2257: break; ! 2258: } ! 2259: } ! 2260: ! 2261: ! 2262: ! 2263: void PackAttributeBlock(struct attrlist *alist, ! 2264: struct vnode *vp, ! 2265: struct hfsCatalogInfo *catInfo, ! 2266: void **attrbufptrptr, ! 2267: void **varbufptrptr) { ! 2268: ! 2269: // DBG_FUNC_NAME("PackAttributeBlock"); ! 2270: ! 2271: if (alist->volattr != 0) { ! 2272: DBG_ASSERT((vp->v_flag & VROOT) != 0); ! 2273: PackVolumeInfo(alist,vp, catInfo, attrbufptrptr, varbufptrptr); ! 2274: } else { ! 2275: PackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2276: ! 2277: switch (vp->v_type) { ! 2278: case VDIR: ! 2279: PackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2280: break; ! 2281: ! 2282: case VREG: ! 2283: /* case VCPLX: */ /* XXX PPD TBC */ ! 2284: PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2285: break; ! 2286: ! 2287: #if 0 /* XXX PPD TBC */ ! 2288: case VFORK: ! 2289: PackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2290: break; ! 2291: #endif ! 2292: ! 2293: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR ! 2294: not being handled... ! 2295: */ ! 2296: default: ! 2297: /* XXX PPD - Panic? */ ! 2298: break; ! 2299: }; ! 2300: }; ! 2301: }; ! 2302: ! 2303: ! 2304: ! 2305: void UnpackVolumeAttributeBlock(struct attrlist *alist, ! 2306: struct vnode *root_vp, ! 2307: ExtendedVCB *vcb, ! 2308: void **attrbufptrptr, ! 2309: void **varbufptrptr) { ! 2310: void *attrbufptr = *attrbufptrptr; ! 2311: attrgroup_t a; ! 2312: text_encoding_t nameEncoding; ! 2313: ! 2314: if ((alist->commonattr == 0) && (alist->volattr == 0)) { ! 2315: return; /* Get out without dirtying the VCB */ ! 2316: }; ! 2317: ! 2318: VCB_LOCK(vcb); ! 2319: ! 2320: a = alist->commonattr; ! 2321: ! 2322: if (a & ATTR_CMN_SCRIPT) { ! 2323: /* XXX PPD No use for this info right now... */ ! 2324: nameEncoding = *(((text_encoding_t *)attrbufptr)++); ! 2325: #if DIAGNOSTIC ! 2326: a &= ~ATTR_CMN_SCRIPT; ! 2327: #endif ! 2328: }; ! 2329: if (a & ATTR_CMN_CRTIME) { ! 2330: /* ! 2331: * HFS Plus stores the volume create date in *local* ! 2332: * time in the volume header. So don't set the create ! 2333: * date in the vcb. Set the root's crtime instead. ! 2334: */ ! 2335: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 2336: VTOH(root_vp)->h_meta->h_crtime = ! 2337: (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2338: } else { ! 2339: vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2340: } ! 2341: ++((struct timespec *)attrbufptr); ! 2342: #if DIAGNOSTIC ! 2343: a &= ~ATTR_CMN_CRTIME; ! 2344: #endif ! 2345: }; ! 2346: if (a & ATTR_CMN_MODTIME) { ! 2347: vcb->vcbLsMod = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2348: ++((struct timespec *)attrbufptr); ! 2349: #if DIAGNOSTIC ! 2350: a &= ~ATTR_CMN_MODTIME; ! 2351: #endif ! 2352: }; ! 2353: if (a & ATTR_CMN_BKUPTIME) { ! 2354: vcb->vcbVolBkUp = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2355: ++((struct timespec *)attrbufptr); ! 2356: #if DIAGNOSTIC ! 2357: a &= ~ATTR_CMN_BKUPTIME; ! 2358: #endif ! 2359: }; ! 2360: if (a & ATTR_CMN_FNDRINFO) { ! 2361: bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); ! 2362: attrbufptr += sizeof(vcb->vcbFndrInfo); ! 2363: #if DIAGNOSTIC ! 2364: a &= ~ATTR_CMN_FNDRINFO; ! 2365: #endif ! 2366: }; ! 2367: ! 2368: DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */ ! 2369: ! 2370: a = alist->volattr & ~ATTR_VOL_INFO; ! 2371: if (a & ATTR_VOL_NAME) { ! 2372: copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); ! 2373: attrbufptr += sizeof(struct attrreference); ! 2374: #if DIAGNOSTIC ! 2375: a &= ~ATTR_VOL_NAME; ! 2376: #endif ! 2377: }; ! 2378: ! 2379: DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */ ! 2380: ! 2381: vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty ! 2382: ! 2383: VCB_UNLOCK(vcb); ! 2384: } ! 2385: ! 2386: ! 2387: void UnpackCommonAttributeBlock(struct attrlist *alist, ! 2388: struct vnode *vp, ! 2389: struct hfsCatalogInfo *catInfo, ! 2390: void **attrbufptrptr, ! 2391: void **varbufptrptr) { ! 2392: struct hfsnode *hp = VTOH(vp); ! 2393: void *attrbufptr; ! 2394: attrgroup_t a; ! 2395: ! 2396: attrbufptr = *attrbufptrptr; ! 2397: ! 2398: DBG_ASSERT(catInfo != NULL); ! 2399: ! 2400: a = alist->commonattr; ! 2401: if (a & ATTR_CMN_SCRIPT) { ! 2402: /* XXX PPD No use for this info right now... */ ! 2403: ++((text_encoding_t *)attrbufptr); ! 2404: #if DIAGNOSTIC ! 2405: a &= ~ATTR_CMN_SCRIPT; ! 2406: #endif ! 2407: }; ! 2408: if (a & ATTR_CMN_CRTIME) { ! 2409: catInfo->nodeData.createDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2410: VTOH(vp)->h_meta->h_crtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2411: ++((struct timespec *)attrbufptr); ! 2412: #if DIAGNOSTIC ! 2413: a &= ~ATTR_CMN_CRTIME; ! 2414: #endif ! 2415: }; ! 2416: if (a & ATTR_CMN_MODTIME) { ! 2417: catInfo->nodeData.contentModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2418: VTOH(vp)->h_meta->h_mtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2419: ++((struct timespec *)attrbufptr); ! 2420: #if DIAGNOSTIC ! 2421: a &= ~ATTR_CMN_MODTIME; ! 2422: #endif ! 2423: }; ! 2424: if (a & ATTR_CMN_CHGTIME) { ! 2425: catInfo->nodeData.attributeModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2426: VTOH(vp)->h_meta->h_ctime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2427: ++((struct timespec *)attrbufptr); ! 2428: #if DIAGNOSTIC ! 2429: a &= ~ATTR_CMN_CHGTIME; ! 2430: #endif ! 2431: }; ! 2432: if (a & ATTR_CMN_ACCTIME) { ! 2433: catInfo->nodeData.accessDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2434: VTOH(vp)->h_meta->h_atime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2435: ++((struct timespec *)attrbufptr); ! 2436: #if DIAGNOSTIC ! 2437: a &= ~ATTR_CMN_ACCTIME; ! 2438: #endif ! 2439: }; ! 2440: if (a & ATTR_CMN_BKUPTIME) { ! 2441: catInfo->nodeData.backupDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); ! 2442: VTOH(vp)->h_meta->h_butime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; ! 2443: ++((struct timespec *)attrbufptr); ! 2444: #if DIAGNOSTIC ! 2445: a &= ~ATTR_CMN_BKUPTIME; ! 2446: #endif ! 2447: }; ! 2448: if (a & ATTR_CMN_FNDRINFO) { ! 2449: bcopy (attrbufptr, &catInfo->nodeData.finderInfo, sizeof(catInfo->nodeData.finderInfo)); ! 2450: attrbufptr += sizeof(catInfo->nodeData.finderInfo); ! 2451: bcopy (attrbufptr, &catInfo->nodeData.extFinderInfo, sizeof(catInfo->nodeData.extFinderInfo)); ! 2452: attrbufptr += sizeof(catInfo->nodeData.extFinderInfo); ! 2453: #if DIAGNOSTIC ! 2454: a &= ~ATTR_CMN_FNDRINFO; ! 2455: #endif ! 2456: }; ! 2457: if (a & ATTR_CMN_OWNERID) { ! 2458: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { ! 2459: u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++; ! 2460: if (uid != (uid_t)VNOVAL) ! 2461: hp->h_meta->h_uid = uid; /* catalog will get updated by hfs_chown() */ ! 2462: } ! 2463: else { ! 2464: ((uid_t *)attrbufptr)++; ! 2465: } ! 2466: #if DIAGNOSTIC ! 2467: a &= ~ATTR_CMN_OWNERID; ! 2468: #endif ! 2469: }; ! 2470: if (a & ATTR_CMN_GRPID) { ! 2471: u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++; ! 2472: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { ! 2473: if (gid != (gid_t)VNOVAL) ! 2474: hp->h_meta->h_gid = gid; /* catalog will get updated by hfs_chown() */ ! 2475: }; ! 2476: #if DIAGNOSTIC ! 2477: a &= ~ATTR_CMN_GRPID; ! 2478: #endif ! 2479: }; ! 2480: if (a & ATTR_CMN_ACCESSMASK) { ! 2481: u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++; ! 2482: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { ! 2483: if (mode != (mode_t)VNOVAL) { ! 2484: hp->h_meta->h_mode &= ~ALLPERMS; ! 2485: hp->h_meta->h_mode |= (mode & ALLPERMS); /* catalog will get updated by hfs_chmod() */ ! 2486: } ! 2487: }; ! 2488: #if DIAGNOSTIC ! 2489: a &= ~ATTR_CMN_ACCESSMASK; ! 2490: #endif ! 2491: }; ! 2492: if (a & ATTR_CMN_FLAGS) { ! 2493: u_long flags = *((u_long *)attrbufptr)++; ! 2494: /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE ! 2495: flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */ ! 2496: if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) || ! 2497: ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && ((flags & ~IMMUTABLE) == 0))) { ! 2498: if (flags != (u_long)VNOVAL) { ! 2499: hp->h_meta->h_pflags = flags; /* catalog will get updated by hfs_chflags */ ! 2500: }; ! 2501: }; ! 2502: #if DIAGNOSTIC ! 2503: a &= ~ATTR_CMN_FLAGS; ! 2504: #endif ! 2505: }; ! 2506: ! 2507: #if DIAGNOSTIC ! 2508: if (a != 0) { ! 2509: DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a)); ! 2510: }; ! 2511: #endif ! 2512: ! 2513: *attrbufptrptr = attrbufptr; ! 2514: // *varbufptrptr = varbufptr; ! 2515: } ! 2516: ! 2517: ! 2518: ! 2519: #if 0 ! 2520: void UnpackDirAttributeBlock(struct attrlist *alist, ! 2521: struct vnode *vp, ! 2522: struct hfsCatalogInfo *catInfo, ! 2523: void **attrbufptrptr, ! 2524: void **varbufptrptr) { ! 2525: void *attrbufptr; ! 2526: void *varbufptr; ! 2527: attrgroup_t a; ! 2528: u_long attrlength; ! 2529: ! 2530: attrbufptr = *attrbufptrptr; ! 2531: varbufptr = *varbufptrptr; ! 2532: ! 2533: /* XXX PPD TBC */ ! 2534: ! 2535: *attrbufptrptr = attrbufptr; ! 2536: *varbufptrptr = varbufptr; ! 2537: } ! 2538: #endif ! 2539: ! 2540: ! 2541: ! 2542: #if 0 ! 2543: void UnpackFileAttributeBlock(struct attrlist *alist, ! 2544: struct vnode *vp, ! 2545: struct hfsCatalogInfo *catInfo, ! 2546: void **attrbufptrptr, ! 2547: void **varbufptrptr) { ! 2548: void *attrbufptr; ! 2549: void *varbufptr; ! 2550: attrgroup_t a; ! 2551: u_long attrlength; ! 2552: ! 2553: attrbufptr = *attrbufptrptr; ! 2554: varbufptr = *varbufptrptr; ! 2555: ! 2556: /* XXX PPD TBC */ ! 2557: ! 2558: *attrbufptrptr = attrbufptr; ! 2559: *varbufptrptr = varbufptr; ! 2560: } ! 2561: #endif ! 2562: ! 2563: ! 2564: ! 2565: #if 0 ! 2566: void UnpackForkAttributeBlock(struct attrlist *alist, ! 2567: struct vnode *vp, ! 2568: struct hfsCatalogInfo *catInfo, ! 2569: void **attrbufptrptr, ! 2570: void **varbufptrptr) { ! 2571: void *attrbufptr; ! 2572: void *varbufptr; ! 2573: attrgroup_t a; ! 2574: u_long attrlength; ! 2575: ! 2576: attrbufptr = *attrbufptrptr; ! 2577: varbufptr = *varbufptrptr; ! 2578: ! 2579: /* XXX PPD TBC */ ! 2580: ! 2581: *attrbufptrptr = attrbufptr; ! 2582: *varbufptrptr = varbufptr; ! 2583: } ! 2584: #endif ! 2585: ! 2586: ! 2587: ! 2588: void UnpackAttributeBlock(struct attrlist *alist, ! 2589: struct vnode *vp, ! 2590: struct hfsCatalogInfo *catInfo, ! 2591: void **attrbufptrptr, ! 2592: void **varbufptrptr) { ! 2593: ! 2594: ! 2595: if (alist->volattr != 0) { ! 2596: UnpackVolumeAttributeBlock(alist, vp, VTOVCB(vp), attrbufptrptr, varbufptrptr); ! 2597: return; ! 2598: }; ! 2599: ! 2600: /* We're dealing with a vnode object here: */ ! 2601: UnpackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2602: ! 2603: #if 0 ! 2604: switch (vp->v_type) { ! 2605: case VDIR: ! 2606: UnpackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2607: break; ! 2608: ! 2609: case VREG: ! 2610: /* case VCPLX: */ /* XXX PPD TBC */ ! 2611: UnpackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2612: break; ! 2613: ! 2614: case VFORK: ! 2615: UnpackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); ! 2616: break; ! 2617: ! 2618: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR ! 2619: not being handled... ! 2620: */ ! 2621: default: ! 2622: /* XXX PPD - Panic? */ ! 2623: break; ! 2624: }; ! 2625: #endif ! 2626: ! 2627: }; ! 2628: ! 2629: ! 2630: unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, ! 2631: unsigned long blockSizeLimit, ! 2632: unsigned long baseMultiple) { ! 2633: /* ! 2634: Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the ! 2635: specified limit but still an even multiple of the baseMultiple. ! 2636: */ ! 2637: int baseBlockCount, blockCount; ! 2638: unsigned long trialBlockSize; ! 2639: ! 2640: if (allocationBlockSize % baseMultiple != 0) { ! 2641: /* ! 2642: Whoops: the allocation blocks aren't even multiples of the specified base: ! 2643: no amount of dividing them into even parts will be a multiple, either then! ! 2644: */ ! 2645: return 512; /* Hope for the best */ ! 2646: }; ! 2647: ! 2648: /* Try the obvious winner first, to prevent 12K allocation blocks, for instance, ! 2649: from being handled as two 6K logical blocks instead of 3 4K logical blocks. ! 2650: Even though the former (the result of the loop below) is the larger allocation ! 2651: block size, the latter is more efficient: */ ! 2652: if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE; ! 2653: ! 2654: /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */ ! 2655: baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */ ! 2656: ! 2657: for (blockCount = baseBlockCount; blockCount > 0; --blockCount) { ! 2658: trialBlockSize = blockCount * baseMultiple; ! 2659: if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */ ! 2660: if ((trialBlockSize <= blockSizeLimit) && ! 2661: (trialBlockSize % baseMultiple == 0)) { ! 2662: return trialBlockSize; ! 2663: }; ! 2664: }; ! 2665: }; ! 2666: ! 2667: /* Note: we should never get here, since blockCount = 1 should always work, ! 2668: but this is nice and safe and makes the compiler happy, too ... */ ! 2669: return 512; ! 2670: } ! 2671: ! 2672: ! 2673: /* ! 2674: * Map HFS Common errors (negative) to BSD error codes (positive). ! 2675: * Positive errors (ie BSD errors) are passed through unchanged. ! 2676: */ ! 2677: short MacToVFSError(OSErr err) ! 2678: { ! 2679: if (err >= 0) { ! 2680: if (err > 0) { ! 2681: DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err)); ! 2682: }; ! 2683: return err; ! 2684: }; ! 2685: ! 2686: if (err != 0) { ! 2687: DBG_ERR(("MacToVFSError: mapping error code %d...\n", err)); ! 2688: }; ! 2689: ! 2690: switch (err) { ! 2691: case dirFulErr: /* -33 */ ! 2692: case dskFulErr: /* -34 */ ! 2693: case btNoSpaceAvail: /* -32733 */ ! 2694: case fxOvFlErr: /* -32750 */ ! 2695: return ENOSPC; /* +28 */ ! 2696: ! 2697: case btBadNode: /* -32731 */ ! 2698: case ioErr: /* -36 */ ! 2699: return EIO; /* +5 */ ! 2700: ! 2701: case badMDBErr: /* -60 */ ! 2702: case fnOpnErr: /* -38 */ ! 2703: return EBADF; /* +9 */ ! 2704: ! 2705: case mFulErr: /* -41 */ ! 2706: case memFullErr: /* -108 */ ! 2707: return ENOMEM; /* +12 */ ! 2708: ! 2709: case tmfoErr: /* -42 */ ! 2710: /* Consider EMFILE (Too many open files, 24)? */ ! 2711: return ENFILE; /* +23 */ ! 2712: ! 2713: case nsvErr: /* -35 */ ! 2714: case fnfErr: /* -43 */ ! 2715: case dirNFErr: /* -120 */ ! 2716: case fidNotFound: /* -1300 */ ! 2717: return ENOENT; /* +2 */ ! 2718: ! 2719: case wPrErr: /* -44 */ ! 2720: case vLckdErr: /* -46 */ ! 2721: case fsDSIntErr: /* -127 */ ! 2722: return EROFS; /* +30 */ ! 2723: ! 2724: case opWrErr: /* -49 */ ! 2725: case fLckdErr: /* -45 */ ! 2726: return EACCES; /* +13 */ ! 2727: ! 2728: case permErr: /* -54 */ ! 2729: case wrPermErr: /* -61 */ ! 2730: return EPERM; /* +1 */ ! 2731: ! 2732: case fBsyErr: /* -47 */ ! 2733: return EBUSY; /* +16 */ ! 2734: ! 2735: case dupFNErr: /* -48 */ ! 2736: case fidExists: /* -1301 */ ! 2737: case cmExists: /* -32718 */ ! 2738: case btExists: /* -32734 */ ! 2739: return EEXIST; /* +17 */ ! 2740: ! 2741: case rfNumErr: /* -51 */ ! 2742: return EBADF; /* +9 */ ! 2743: ! 2744: case notAFileErr: /* -1302 */ ! 2745: return EISDIR; /* +21 */ ! 2746: ! 2747: case cmNotFound: /* -32719 */ ! 2748: case btNotFound: /* -32735 */ ! 2749: return ENOENT; /* 28 */ ! 2750: ! 2751: case cmNotEmpty: /* -32717 */ ! 2752: return ENOTEMPTY; /* 66 */ ! 2753: ! 2754: case cmFThdDirErr: /* -32714 */ ! 2755: return EISDIR; /* 21 */ ! 2756: ! 2757: case fxRangeErr: /* -32751 */ ! 2758: return EIO; /* 5 */ ! 2759: ! 2760: case bdNamErr: /* -37 */ ! 2761: return ENAMETOOLONG; /* 63 */ ! 2762: ! 2763: case eofErr: /* -39 */ ! 2764: case posErr: /* -40 */ ! 2765: case paramErr: /* -50 */ ! 2766: case badMovErr: /* -122 */ ! 2767: case sameFileErr: /* -1306 */ ! 2768: case badFidErr: /* -1307 */ ! 2769: case fileBoundsErr: /* -1309 */ ! 2770: return EINVAL; /* +22 */ ! 2771: ! 2772: default: ! 2773: DBG_UTILS(("Unmapped MacOS error: %d\n", err)); ! 2774: return EIO; /* +5 */ ! 2775: } ! 2776: } ! 2777: ! 2778: ! 2779: /* ! 2780: * All of our debugging functions ! 2781: */ ! 2782: ! 2783: #if DIAGNOSTIC ! 2784: ! 2785: void debug_vn_status (char* introStr, struct vnode *vn) ! 2786: { ! 2787: DBG_VOP(("%s:\t",introStr)); ! 2788: if (vn != NULL) ! 2789: { ! 2790: if (vn->v_tag != VT_HFS) ! 2791: { ! 2792: DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn)); ! 2793: } ! 2794: else if(vn->v_tag==VT_HFS && (vn->v_data==NULL || VTOH((vn))->h_valid != HFS_VNODE_MAGIC)) ! 2795: { ! 2796: DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n")); ! 2797: } ! 2798: else ! 2799: { ! 2800: DBG_VOP(("r: %d & ", vn->v_usecount)); ! 2801: if (lockstatus(&VTOH(vn)->h_lock)) ! 2802: { ! 2803: DBG_VOP_CONT(("is L\n")); ! 2804: } ! 2805: else ! 2806: { ! 2807: DBG_VOP_CONT(("is U\n")); ! 2808: } ! 2809: } ! 2810: } ! 2811: else ! 2812: { ! 2813: DBG_VOP(("vnode is NULL\n")); ! 2814: }; ! 2815: } ! 2816: ! 2817: void debug_vn_print (char* introStr, struct vnode *vn) ! 2818: { ! 2819: // DBG_FUNC_NAME("DBG_VN_PRINT"); ! 2820: DBG_ASSERT (vn != NULL); ! 2821: DBG_VFS(("%s: ",introStr)); ! 2822: DBG_VFS_CONT(("vnode: 0x%x is a ", (uint)vn)); ! 2823: switch (vn->v_tag) ! 2824: { ! 2825: case VT_UFS: ! 2826: DBG_VFS_CONT(("%s","UFS")); ! 2827: break; ! 2828: case VT_HFS: ! 2829: DBG_VFS_CONT(("%s","HFS")); ! 2830: break; ! 2831: default: ! 2832: DBG_VFS_CONT(("%s","UNKNOWN")); ! 2833: break; ! 2834: } ! 2835: ! 2836: DBG_VFS_CONT((" vnode\n")); ! 2837: if (vn->v_tag==VT_HFS) ! 2838: { ! 2839: if (vn->v_data==NULL) ! 2840: { ! 2841: DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n")); ! 2842: } ! 2843: else ! 2844: { ! 2845: DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn)), H_FILEID(VTOH(vn)))); ! 2846: } ! 2847: } ! 2848: else ! 2849: DBG_VFS((" ")); ! 2850: ! 2851: DBG_VFS_CONT(("Refcount: %d\n", vn->v_usecount)); ! 2852: if (VOP_ISLOCKED(vn)) ! 2853: { ! 2854: DBG_VFS((" The vnode is locked\n")); ! 2855: } ! 2856: else ! 2857: { ! 2858: DBG_VFS((" The vnode is not locked\n")); ! 2859: } ! 2860: } ! 2861: ! 2862: void debug_rename_test_locks (char* introStr, ! 2863: struct vnode *fvp, ! 2864: struct vnode *fdvp, ! 2865: struct vnode *tvp, ! 2866: struct vnode *tdvp, ! 2867: int fstatus, ! 2868: int fdstatus, ! 2869: int tstatus, ! 2870: int tdstatus ! 2871: ) ! 2872: { ! 2873: DBG_VOP(("\t%s: ", introStr)); ! 2874: if (fvp) {if(lockstatus(&VTOH(fvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; ! 2875: if (fdvp) {if(lockstatus(&VTOH(fdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; ! 2876: if (tvp) {if(lockstatus(&VTOH(tvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; ! 2877: if (tdvp) {if(lockstatus(&VTOH(tdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; ! 2878: DBG_VFS_CONT(("\n")); ! 2879: ! 2880: if (fvp) { ! 2881: if (lockstatus(&VTOH(fvp)->h_lock)) { ! 2882: if (fstatus==VOPDBG_UNLOCKED) { ! 2883: DBG_VOP(("\tfvp should be NOT LOCKED and it is\n")); ! 2884: } ! 2885: } else if (fstatus == VOPDBG_LOCKED) { ! 2886: DBG_VOP(("\tfvp should be LOCKED and it isnt\n")); ! 2887: } ! 2888: } ! 2889: ! 2890: if (fdvp) { ! 2891: if (lockstatus(&VTOH(fdvp)->h_lock)) { ! 2892: if (fdstatus==VOPDBG_UNLOCKED) { ! 2893: DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n")); ! 2894: } ! 2895: } else if (fdstatus == VOPDBG_LOCKED) { ! 2896: DBG_VOP(("\tfdvp should be LOCKED and it isnt\n")); ! 2897: } ! 2898: } ! 2899: ! 2900: if (tvp) { ! 2901: if (lockstatus(&VTOH(tvp)->h_lock)) { ! 2902: if (tstatus==VOPDBG_UNLOCKED) { ! 2903: DBG_VOP(("\ttvp should be NOT LOCKED and it is\n")); ! 2904: } ! 2905: } else if (tstatus == VOPDBG_LOCKED) { ! 2906: DBG_VOP(("\ttvp should be LOCKED and it isnt\n")); ! 2907: } ! 2908: } ! 2909: ! 2910: if (tdvp) { ! 2911: if (lockstatus(&VTOH(tdvp)->h_lock)) { ! 2912: if (tdstatus==VOPDBG_UNLOCKED) { ! 2913: DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n")); ! 2914: } ! 2915: } else if (tdstatus == VOPDBG_LOCKED) { ! 2916: DBG_VOP(("\ttdvp should be LOCKED and it isnt\n")); ! 2917: ! 2918: } ! 2919: } ! 2920: ! 2921: } ! 2922: #endif /* DIAGNOSTIC */ ! 2923: ! 2924: ! 2925: #if DIAGNOSTIC ! 2926: void debug_check_buffersizes(struct vnode *vp, struct hfsnode *hp, struct buf *bp) { ! 2927: DBG_ASSERT(bp->b_validoff == 0); ! 2928: DBG_ASSERT(bp->b_dirtyoff == 0); ! 2929: if (bp->b_lblkno < hp->h_uniformblocksizestart) { ! 2930: DBG_ASSERT((bp->b_bcount == MAXLOGBLOCKSIZE) || ! 2931: (bp->b_bcount == LogicalBlockSize(hp, bp->b_lblkno)) || ! 2932: ((bp->b_bcount % 512 == 0) && ! 2933: (bp->b_validend > 0) && ! 2934: (bp->b_dirtyend >= 0) && /* Could be partial block due to file growth */ ! 2935: (bp->b_bcount < LogicalBlockSize(hp, bp->b_lblkno)))); ! 2936: } else { ! 2937: DBG_ASSERT((bp->b_bcount == hp->h_meta->h_logBlockSize) || ! 2938: ((bp->b_bcount % 512 == 0) && ! 2939: (bp->b_validend > 0) && ! 2940: (bp->b_dirtyend > 0) && ! 2941: (bp->b_bcount < hp->h_meta->h_logBlockSize))); ! 2942: }; ! 2943: ! 2944: if (bp->b_validend == 0) { ! 2945: DBG_ASSERT(bp->b_dirtyend == 0); ! 2946: } else { ! 2947: DBG_ASSERT(bp->b_validend == bp->b_bcount); ! 2948: DBG_ASSERT(bp->b_dirtyend <= bp->b_bcount); ! 2949: }; ! 2950: ! 2951: if ((bp->b_lblkno == 0x21) || (bp->b_lblkno == 0x22)) DBG_ASSERT((hp->h_uniformblocksizestart > 0x21) || (bp->b_bcount != MAXLOGBLOCKSIZE)); ! 2952: } ! 2953: ! 2954: ! 2955: void debug_check_blocksizes(struct vnode *vp) { ! 2956: struct hfsnode *hp = VTOH(vp); ! 2957: struct buf *bp; ! 2958: ! 2959: if (vp->v_flag & VSYSTEM) return; ! 2960: ! 2961: for (bp = vp->v_cleanblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) { ! 2962: debug_check_buffersizes(vp, hp, bp); ! 2963: }; ! 2964: ! 2965: for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) { ! 2966: debug_check_buffersizes(vp, hp, bp); ! 2967: }; ! 2968: } ! 2969: ! 2970: #endif /* DIAGNOSTIC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.