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