Annotation of XNU/bsd/hfs/hfs_vfsutils.c, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.