Annotation of XNU/bsd/hfs/hfs_vnodeops.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_vnodeops.c      3.0
        !            23:  *
        !            24: *      (c) 1997-1999   Apple Computer, Inc.  All Rights Reserved
        !            25:  *     (c) 1990, 1992 NeXT Computer, Inc.  All Rights Reserved
        !            26:  *     
        !            27:  *
        !            28:  *     hfs_vnodeops.c -- vnode layer for loadable Macintosh file system
        !            29:  *
        !            30:  *     MODIFICATION HISTORY:
        !            31:  *             11-Nov-1999     Scott Roberts   Does not update if times have not changed (#2409116)
        !            32:  *              9-Nov-1999     Scott Roberts   Added cluster_close to hfs_fsync(#2398208)
        !            33:  *       9-Nov-1999    Don Brady       Fix locking bug in hfs_close [#2399157].
        !            34:  *             15-Sep-1999     Pat Dirks       Changed hfs_setattrlist to allow changing flags on plain-HFS volumes w/o ownership [#2365108];
        !            35:  *                                                             Changed to use hfs_write_access instead of obsolete hfs_writepermission uniformly throughout.
        !            36:  *       7-Sep-1999    Don Brady       Add HFS Plus hard-link support.
        !            37:  *              8-Sep-1999             Pat Dirks       Changed hfs_rename to change mod. date on parent directory [#2297825].
        !            38:  *             26-Aug-1999             Pat Dirks       Changed hfs_chflags to allow locking on HFS volumes w. write access only as workaround [#2313439].
        !            39:  *       2-Sep-1999     Pat Dirks       Fixed hfs_pathconf to return same info for hfs/hfs+ for max. name length [#2382208]
        !            40:  *     26-Aug-1999     Pat Dirks       Changed hfs_chflags to allow locking on HFS volumes w. write access only as workaround [#2313439].
        !            41: *       24-Jul-1999    Earsh Nandkeshwar       Rewrote readdirattr.
        !            42: *      15-Jul-1999     Pat Dirks       Fixed hfs_readdir to return EINVAL if design assumption of uio->uio_iovcnt�== 1 is violated
        !            43:  *                                                             and cleaned up call to uiomove to check space available first.
        !            44:  *       2-Jul-1999     Pat Dirks       Fixed hfs_setattrlist to ignore attempts to set null volume name (#2331829).
        !            45:  *      18-May-1999    Don Brady               Add support for rooting from HFS Plus.
        !            46:  *      4-May-1999     Don Brady               Split off hfs_search.c
        !            47:  *      15-Apr-1999    Don Brady               Change va_nlink back to 1 for directories in hfs_getattr.
        !            48:  *       6-Apr-1999    Don Brady               Fix deference of NULL h_sibling in hfs_chid.
        !            49:  *  29-Mar-1999 Scott Roberts  Put in the correct . and .. entries for readdir
        !            50:  *  22-Mar-1999 Don Brady              Add UFS delete semantic support to hfs_remove.
        !            51:  *       1-Mar-1999    Scott Roberts   h_meta is now released when the complex vnode is relesed
        !            52:  *      26-Feb-1999    Pat Dirks (copied by Chw) Fixed hfs_lookup to check for
        !            53:  *                                error return on vget.
        !            54:  *      25-Feb-1999     Pat Dirks       Fixed hfs_remove to use a local copy of the h_sibling pointer around vnode_uncache.
        !            55:  *      3-Feb-1999     Pat Dirks               Changed to stop updating wrapper volume name in MDB since wrapper volume's
        !            56:  *                                                             catalog isn't updated and this inconsistency trips Disk First Aid's checks.
        !            57:  *     22-Jan-1999     Pat Dirks               Changed hfs_rename, hfs_remove, and hfs_rmdir to call cache_purge.
        !            58:  *     22-Jan-1999     Don Brady               After calling hfsMoveRename call hfsLookup to get new name.
        !            59:  *     12-Jan-1999     Don Brady               Fixed the size of ATTR_CMN_NAME buffer to NAME_MAX + 1.
        !            60:  *      8-Jan-1999     Pat Dirks               Added hfs_writepermission and change hfs_setattrlist to use it instead of
        !            61:  *                                                             including an incorrect derivative of hfs_access in-line.
        !            62:  *     15-Dec-1998 Pat Dirks           Changed setattrlist to do permission checking as appropriate (Radar #2290212).
        !            63:  *     17-Nov-1998 Scott Roberts       Added support for long volume names in SetAttrList().
        !            64:  *     6-Nov-1998 Don Brady            Add support for UTF-8 names.
        !            65:  *      3-Nov-1998     Umesh Vaishampayan      Changes to deal with "struct timespec"
        !            66:  *                                             change in the kernel.   
        !            67:  *  21-Oct-1998 Scott Roberts  Added support for advisory locking (Radar #2237914).
        !            68:  *  25-Sep-1998 Don Brady              Changed hfs_exchange to call hfs_chid after updating catalog (radar #2276605).
        !            69:  *     23-Sep-1998 Don Brady           hfs_setattrlist now calls hfs_chown and hfs_chmod to change values.
        !            70:  *     15-Sep-1998 Pat Dirks           Cleaned up vnode unlocking on various error exit paths and changed
        !            71:  *                                                             to use new error stub routines in place of hfs_mknod and hfs_link.
        !            72:  *  16-Sep-1998        Don Brady               When renaming a volume in hfs_setattrlist, also update hfs+ wrapper name (radar #2272925).
        !            73:  *   1-Sep-1998        Don Brady               Fix uninitiazed time variable in hfs_makenode (radar #2270372).
        !            74:  *  31-Aug-1998        Don Brady               Adjust change time for DST in hfs_update (radar #2265075).
        !            75:  *  12-Aug-1998        Don Brady               Update complex node name in hfs_rename (radar #2262111).
        !            76:  *   5-Aug-1998        Don Brady               In hfs_setattrlist call MacToVFSError after calling UpdateCatalogNode (radar #2261247).
        !            77:  *  21-Jul-1998        Don Brady               Fixed broken preflight in hfs_getattrlist.
        !            78:  *      17-Jul-1998    Clark Warner            Fixed the one left out case of freeing M_NAMEI in hfs_abort
        !            79:  *     13-Jul-1998     Don Brady               Add uio_resid preflight check to hfs_search (radar #2251855).
        !            80:  *     30-Jun-1998     Scott Roberts           Changed hfs_makenode and its callers to free M_NAMEI.
        !            81:  *     29-Jun-1998     Don Brady               Fix unpacking order in UnpackSearchAttributeBlock (radar #2249248).
        !            82:  *     13-Jun-1998     Scott Roberts           Integrated changes to hfs_lock (radar #2237243).
        !            83:  *      4-Jun-1998     Pat Dirks               Split off hfs_lookup.c and hfs_readwrite.c
        !            84:  *      3-Jun-1998     Don Brady               Fix hfs_rename bugs (radar #2229259, #2239823, 2231108 and #2237380).
        !            85:  *                                                             Removed extra vputs in hfs_rmdir (radar #2240309).
        !            86:  *     28-May-1998     Don Brady               Fix hfs_truncate to correctly extend files (radar #2237242).
        !            87:  *     20-May-1998     Don Brady               In hfs_close shrink the peof to the smallest size neccessary (radar #2230094).
        !            88:  *      5-May-1998     Don Brady               Fixed typo in hfs_rename (apply H_FILEID macro to VTOH result).
        !            89:  *     29-Apr-1998     Joe Sokol               Don't do cluster I/O when logical block size is not 4K multiple.
        !            90:  *     28-Apr-1998     Pat Dirks               Cleaned up unused variable physBlockNo in hfs_write.
        !            91:  *     28-Apr-1998     Joe Sokol               Touched up support for cluster_read/cluster_write and enabled it.
        !            92:  *     27-Apr-1998     Don Brady               Remove some DEBUG_BREAK calls in DbgVopTest.
        !            93:  *     24-Apr-1998     Pat Dirks               Fixed read logic to read-ahead only ONE block, and of only logBlockSize instead of 64K...
        !            94:  *                                                             Added calls to brelse() on errors from bread[n]().
        !            95:  *                                                             Changed logic to add overall length field to AttrBlockSize only on attribute return operations.
        !            96:  *     23-Apr-1998     Don Brady               The hfs_symlink call is only supported on HFS Plus disks.
        !            97:  *     23-Apr-1998     Deric Horn              Fixed hfs_search bug where matches were skipped when buffer was full.
        !            98:  *     22-Apr-1998     Scott Roberts           Return on error if catalog mgr returns an error in truncate.
        !            99:  *     21-Apr-1998     Don Brady               Fix up time/date conversions.
        !           100:  *     20-Apr-1998     Don Brady               Remove course-grained hfs metadata locking.
        !           101:  *     17-Apr-1998     Pat Dirks               Officially enabled searchfs in vops table.
        !           102:  *     17-Apr-1998     Deric Horn              Bug fixes to hfs_search, reenabled searchfs trap for upcoming kernel build.
        !           103:  *     15-Apr-1998     Don Brady               Add locking for HFS B-trees. Don't lock file meta lock for VSYSTEM files.
        !           104:  *                                                             Don't call VOP_UPDATE for system files. Roll set_time into hfs_update.
        !           105:  *     14-Apr-1998     Pat Dirks               Cleaned up fsync to skip complex nodes and not hit sibling nodes.
        !           106:  *     14-Apr-1998     Deric Horn              Added hfs_search() and related routines for searchfs() support.
        !           107:  *     14-Apr-1998     Scott Roberts           Fixed paramaters to ExchangeFileIDs()
        !           108:  *     13-Apr-1998     Pat Dirks               Changed to update H_HINT whenever hfsLookup was called.
        !           109:  *      8-Apr-1998     Pat Dirks               Added page-in and page-out passthrough routines to keep MapFS happy.
        !           110:  *      6-Apr-1998     Pat Dirks               Changed hfs_write to clean up code and fix bug that caused
        !           111:  *                                                             zeroes to be interspersed in data.  Added debug printf to hfs_read.
        !           112:  *      6-Apr-1998     Scott Roberts           Added complex file support.
        !           113:  *     02-apr-1998     Don Brady               UpdateCatalogNode now takes parID and name as input.
        !           114:  *     31-mar-1998     Don Brady               Sync up with final HFSVolumes.h header file.
        !           115:  *     27-mar-1998     Don Brady               Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater than 31 characters.
        !           116:  *     27-mar-1998     chw                     minor link fixes.
        !           117:  *     19-Mar-1998     ser                     Added hfs_readdirattr.
        !           118:  *     17-Mar-1998     ser                     Removed CheckUserAccess. Added code to implement ExchangeFileIDs
        !           119:  *     16-Mar-1998     Pat Dirks               Fixed logic in hfs_read to properly account for space
        !           120:  *                                                             remaining past selected offset and avoid premature panic.
        !           121:  *     16-jun-1997     Scott Roberts
        !           122:  *        Dec-1991     Kevin Wells at NeXT:
        !           123:  *                     Significantly modified for Macintosh file system.
        !           124:  *                     Added support for NFS exportability.
        !           125:  *     25-Jun-1990     Doug Mitchell at NeXT:
        !           126:  *                     Created (for DOS file system).
        !           127:  */
        !           128: 
        !           129: #include <sys/systm.h>
        !           130: #include <sys/kernel.h>
        !           131: #include <sys/file.h>
        !           132: #include <sys/dirent.h>
        !           133: #include <sys/stat.h>
        !           134: #include <sys/buf.h>
        !           135: #include <sys/mount.h>
        !           136: #include <sys/vnode.h>
        !           137: #include <sys/malloc.h>
        !           138: #include <sys/namei.h>
        !           139: #include <sys/attr.h>
        !           140: #include <miscfs/specfs/specdev.h>
        !           141: #include <miscfs/fifofs/fifo.h>
        !           142: 
        !           143: #include <machine/spl.h>
        !           144: #include <kern/mapfs.h>
        !           145: 
        !           146: #include       "hfs.h"
        !           147: #include       "hfs_lockf.h"
        !           148: #include       "hfs_dbg.h"
        !           149: 
        !           150: #include "hfscommon/headers/CatalogPrivate.h"
        !           151: #include "hfscommon/headers/BTreesInternal.h"
        !           152: #include "hfscommon/headers/FileMgrInternal.h"
        !           153: #include "hfscommon/headers/HFSUnicodeWrappers.h"
        !           154: 
        !           155: #define OWNERSHIP_ONLY_ATTRS (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS)
        !           156: 
        !           157: #define MAKE_DELETED_NAME(NAME,FID) \
        !           158:            (void) sprintf((NAME), "%s%d", HFS_DELETE_PREFIX, (FID))
        !           159: 
        !           160: 
        !           161: /* Global vfs data structures for hfs */
        !           162: int (**hfs_vnodeop_p)();
        !           163: 
        !           164: /* external routines defined in hfs_vhash.c */
        !           165: extern void hfs_vhashrem(struct hfsnode *hp);
        !           166: extern int     vinvalbuf_vhash(register struct vnode *vp, int flags, struct ucred *cred, struct proc *p);
        !           167: extern void hfs_vhashmove( struct hfsnode *hp,UInt32 nodeID);
        !           168: 
        !           169: /* external routines defined in vfs_cache.c */
        !           170: 
        !           171: void hfs_vhashrem(struct hfsnode *hp);
        !           172: 
        !           173: extern OSErr PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op);
        !           174: 
        !           175: extern void cache_purge (struct vnode *vp);
        !           176: extern int cache_lookup (struct vnode *dvp, struct vnode **vpp, struct componentname *cnp);
        !           177: extern void cache_enter (struct vnode *dvp, struct vnode *vpp, struct componentname *cnp);
        !           178: 
        !           179: extern void vnode_pager_setsize( struct vnode *vp, u_long nsize);
        !           180: extern int vnode_uncache( struct vnode *vp);
        !           181: 
        !           182: extern cluster_close(struct vnode *vp, int  bsize, long secsize);
        !           183: 
        !           184: extern void hfs_set_metaname(char *name, struct hfsfilemeta *fm);
        !           185: 
        !           186: extern groupmember(gid_t gid, struct ucred *cred);
        !           187: 
        !           188: static int hfs_makenode( int mode, dev_t rawdev, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp);
        !           189: 
        !           190: static void hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name);
        !           191: 
        !           192: static int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags);
        !           193: 
        !           194: static int hfs_chown( struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p);
        !           195: static int hfs_chmod( struct vnode *vp, int mode, struct ucred *cred, struct proc *p);
        !           196: static int hfs_chflags( struct vnode *vp, u_long flags, struct ucred *cred, struct proc *p);
        !           197: 
        !           198: /*
        !           199:  * Enabling cluster read/write operations.
        !           200:  */
        !           201: extern int doclusterread;
        !           202: extern int doclusterwrite;
        !           203: 
        !           204: int hfs_cache_lookup();                /* in hfs_lookup.c */
        !           205: int hfs_lookup();              /* in hfs_lookup.c */
        !           206: int hfs_read();                        /* in hfs_readwrite.c */
        !           207: int hfs_write();               /* in hfs_readwrite.c */
        !           208: int hfs_ioctl();               /* in hfs_readwrite.c */
        !           209: int hfs_select();              /* in hfs_readwrite.c */
        !           210: int hfs_mmap();                        /* in hfs_readwrite.c */
        !           211: int hfs_seek();                        /* in hfs_readwrite.c */
        !           212: int hfs_bmap();                        /* in hfs_readwrite.c */
        !           213: int hfs_strategy();            /* in hfs_readwrite.c */
        !           214: int hfs_reallocblks(); /* in hfs_readwrite.c */
        !           215: int hfs_truncate();            /* in hfs_readwrite.c */
        !           216: int hfs_allocate();            /* in hfs_readwrite.c */
        !           217: int hfs_pagein();              /* in hfs_readwrite.c */
        !           218: int hfs_pageout();             /* in hfs_readwrite.c */
        !           219: int hfs_search();              /* in hfs_search.c */
        !           220: int hfs_link();                        /* in hfs_link.c */
        !           221: 
        !           222: /*****************************************************************************
        !           223: *
        !           224: *      Operations on vnodes
        !           225: *
        !           226: *****************************************************************************/
        !           227: 
        !           228: /*
        !           229:  * Create a regular file
        !           230: #% create      dvp     L U U
        !           231: #% create      vpp     - L -
        !           232: #
        !           233:  vop_create {
        !           234:      IN WILLRELE struct vnode *dvp;
        !           235:      OUT struct vnode **vpp;
        !           236:      IN struct componentname *cnp;
        !           237:      IN struct vattr *vap;
        !           238:        
        !           239:      We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
        !           240:        a previous error.
        !           241: 
        !           242: */
        !           243: 
        !           244: static int
        !           245: hfs_create(ap)
        !           246: struct vop_create_args /* {
        !           247:     struct vnode *a_dvp;
        !           248:     struct vnode **a_vpp;
        !           249:     struct componentname *a_cnp;
        !           250:     struct vattr *a_vap;
        !           251: } */ *ap;
        !           252: {
        !           253:        struct proc             *p = current_proc();
        !           254:     int                                retval;
        !           255:     int                                mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
        !           256:     DBG_FUNC_NAME("create");
        !           257:     DBG_VOP_LOCKS_DECL(2);
        !           258:     DBG_VOP_PRINT_FUNCNAME();
        !           259:     DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
        !           260:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);
        !           261: 
        !           262:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !           263:     DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
        !           264:     DBG_VOP_CONT(("\tva_type %d va_mode 0x%x\n",
        !           265:              ap->a_vap->va_type, ap->a_vap->va_mode));
        !           266: 
        !           267: #if HFS_DIAGNOSTIC
        !           268:     DBG_HFS_NODE_CHECK(ap->a_dvp);
        !           269:     DBG_ASSERT(ap->a_dvp->v_type == VDIR);
        !           270:     if(ap->a_vap == NULL) {
        !           271:         panic("NULL attr on create");
        !           272:     }
        !           273: 
        !           274:     switch(ap->a_vap->va_type) {
        !           275:         case VDIR:
        !           276:                VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           277:             VPUT(ap->a_dvp);
        !           278:             DBG_VOP_LOCKS_TEST(EISDIR);
        !           279:             return (EISDIR);   /* use hfs_mkdir instead */
        !           280:         case VREG:
        !           281:         case VLNK:
        !           282:             break;
        !           283:         default:
        !           284:             DBG_ERR(("%s: INVALID va_type: %d, %s, %s\n", funcname, ap->a_vap->va_type, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
        !           285:                VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           286:             VPUT(ap->a_dvp);
        !           287:             DBG_VOP_LOCKS_TEST(EINVAL);
        !           288:             return (EINVAL);
        !           289:             }
        !           290: //    if(ap->a_vap->va_mode & (VSUID | VSGID | VSVTX)) {
        !           291: //        DBG_ERR(("%s: INVALID va_mode (%o): %s, %s\n", funcname, ap->a_vap->va_mode, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
        !           292: //        DBG_VOP_LOCKS_TEST(EINVAL);
        !           293: //               VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           294: //        VPUT(ap->a_dvp);
        !           295: //        return (EINVAL);             /* Can't do these */
        !           296: //    };
        !           297: #endif
        !           298: 
        !           299:        /* lock catalog b-tree */
        !           300:        retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !           301:        if (retval != E_NONE) {
        !           302:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           303:                VPUT(ap->a_dvp);
        !           304:         DBG_VOP_LOCKS_TEST( retval);
        !           305:         return (retval);
        !           306:        }
        !           307: 
        !           308:        /* Create the vnode */
        !           309:     retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp);
        !           310:     DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
        !           311: 
        !           312:        /* unlock catalog b-tree */
        !           313:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
        !           314: 
        !           315:     if (retval != E_NONE) {
        !           316:         DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp))));
        !           317:        }
        !           318:     DBG_VOP_LOCKS_TEST(retval);
        !           319:     return (retval);
        !           320: }
        !           321: 
        !           322: 
        !           323: /*
        !           324:  * Mknod vnode call
        !           325: 
        !           326: #% mknod       dvp     L U U
        !           327: #% mknod       vpp     - X -
        !           328: #
        !           329:  vop_mknod {
        !           330:      IN WILLRELE struct vnode *dvp;
        !           331:      OUT WILLRELE struct vnode **vpp;
        !           332:      IN struct componentname *cnp;
        !           333:      IN struct vattr *vap;
        !           334:      */
        !           335: /* ARGSUSED */
        !           336: 
        !           337: static int
        !           338: hfs_mknod(ap)
        !           339: struct vop_mknod_args /* {
        !           340:     struct vnode *a_dvp;
        !           341:     struct vnode **a_vpp;
        !           342:     struct componentname *a_cnp;
        !           343:     struct vattr *a_vap;
        !           344: } */ *ap;
        !           345: {
        !           346:        struct vattr *vap = ap->a_vap;
        !           347:        struct vnode **vpp = ap->a_vpp;
        !           348:     struct proc *p = current_proc();
        !           349:        dev_t rawdev = 0;
        !           350:        int error;
        !           351: 
        !           352:        if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
        !           353:                VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           354:                VPUT(ap->a_dvp);
        !           355:                return (EOPNOTSUPP);
        !           356:        }
        !           357: 
        !           358:        if (vap->va_rdev != VNOVAL) {
        !           359:                /*
        !           360:                 * Want to be able to use this to make badblock
        !           361:                 * inodes, so don't truncate the dev number.
        !           362:                 */
        !           363:                rawdev = vap->va_rdev;
        !           364:        }
        !           365: 
        !           366:        /* lock catalog b-tree */
        !           367:        error = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !           368:        if (error != E_NONE) {
        !           369:                VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !           370:                VPUT(ap->a_dvp);
        !           371:                return (error);
        !           372:        }
        !           373: 
        !           374:        /* Create the vnode */
        !           375:        error = hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), rawdev, ap->a_dvp, vpp, ap->a_cnp);
        !           376: 
        !           377:        /* unlock catalog b-tree */
        !           378:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
        !           379: 
        !           380:        if (error != E_NONE) {
        !           381:                return (error);
        !           382:        }
        !           383: 
        !           384:        /*
        !           385:         * Remove inode so that it will be reloaded by lookup and
        !           386:         * checked to see if it is an alias of an existing vnode.
        !           387:         * Note: unlike UFS, we don't bash v_type here.
        !           388:         */
        !           389:        VPUT(*vpp);
        !           390:        vgone(*vpp);
        !           391:        *vpp = 0;
        !           392:        return (0);
        !           393: }
        !           394: 
        !           395: 
        !           396: /*
        !           397:  * mkcomplex vnode call
        !           398:  *
        !           399: 
        !           400: #% mkcomplex   dvp     L U U
        !           401: #% mkcomplex   vpp     - L -
        !           402: #
        !           403: vop_mkcomplex {
        !           404:        IN WILLRELE struct vnode *dvp;
        !           405:        OUT struct vnode **vpp;
        !           406:        IN struct componentname *cnp;
        !           407:        IN struct vattr *vap;
        !           408:        IN u_long type;
        !           409: }
        !           410: 
        !           411:  */
        !           412:  
        !           413: static int
        !           414: hfs_mkcomplex(ap)
        !           415: struct vop_mkcomplex_args /* {
        !           416:        struct vnode *a_dvp;
        !           417:        struct vnode **a_vpp;
        !           418:        struct componentname *a_cnp;
        !           419:        struct vattr *a_vap;
        !           420:        u_long a_type;
        !           421: } */ *ap;
        !           422: {
        !           423:     int                retval = E_NONE;
        !           424:     DBG_FUNC_NAME("make_complex");
        !           425:     DBG_VOP_LOCKS_DECL(2);
        !           426:     DBG_VOP_PRINT_FUNCNAME();
        !           427:     DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
        !           428:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
        !           429: 
        !           430:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !           431:     DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
        !           432: 
        !           433:     retval = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
        !           434: 
        !           435:     DBG_VOP_LOCKS_TEST(retval);
        !           436:     return retval;
        !           437: }
        !           438: 
        !           439: 
        !           440: /*
        !           441:  * Open called.
        !           442: #% open                vp      L L L
        !           443: #
        !           444:  vop_open {
        !           445:      IN struct vnode *vp;
        !           446:      IN int mode;
        !           447:      IN struct ucred *cred;
        !           448:      IN struct proc *p;
        !           449:      */
        !           450: 
        !           451: 
        !           452: static int
        !           453: hfs_open(ap)
        !           454: struct vop_open_args /* {
        !           455:     struct vnode *a_vp;
        !           456:     int  a_mode;
        !           457:     struct ucred *a_cred;
        !           458:     struct proc *a_p;
        !           459: } */ *ap;
        !           460: {
        !           461:        struct hfsnode  *hp = VTOH(ap->a_vp);
        !           462:        int                             retval = E_NONE;
        !           463:        DBG_FUNC_NAME("open");
        !           464:        DBG_VOP_LOCKS_DECL(1);
        !           465:        DBG_VOP_PRINT_FUNCNAME();
        !           466:        DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           467:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !           468: 
        !           469:     if (ap->a_vp->v_type == VREG)       /* Only files */
        !           470:       {        
        !           471:         /*
        !           472:          * Files marked append-only must be opened for appending.
        !           473:          */
        !           474:         if ((hp->h_meta->h_pflags & APPEND) &&
        !           475:             (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
        !           476:             retval = EPERM;
        !           477:         }
        !           478: 
        !           479: 
        !           480:     DBG_VOP_LOCKS_TEST(retval);
        !           481:     return (retval);
        !           482: }
        !           483: 
        !           484: /*
        !           485:  * Close called.
        !           486:  *
        !           487:  * Update the times on the hfsnode.
        !           488: #% close       vp      U U U
        !           489: #
        !           490:  vop_close {
        !           491:      IN struct vnode *vp;
        !           492:      IN int fflag;
        !           493:      IN struct ucred *cred;
        !           494:      IN struct proc *p;
        !           495:      */
        !           496: 
        !           497: 
        !           498: static int
        !           499: hfs_close(ap)
        !           500: struct vop_close_args /* {
        !           501:     struct vnode *a_vp;
        !           502:     int  a_fflag;
        !           503:     struct ucred *a_cred;
        !           504:     struct proc *a_p;
        !           505: } */ *ap;
        !           506: {
        !           507:     register struct vnode      *vp = ap->a_vp;
        !           508:     struct hfsnode                     *hp = VTOH(vp);
        !           509:     struct proc                                *p = ap->a_p;
        !           510:        FCB                                             *fcb;
        !           511:     struct timeval                     tv;
        !           512:        off_t                                   leof;
        !           513:        u_long                                  blks, blocksize;
        !           514:     int                                        retval = E_NONE;
        !           515: 
        !           516:        DBG_FUNC_NAME("close");
        !           517:        DBG_VOP_LOCKS_DECL(1);
        !           518:        DBG_VOP_PRINT_FUNCNAME();
        !           519:        DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           520:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !           521: 
        !           522:     simple_lock(&vp->v_interlock);
        !           523:     if (vp->v_usecount > 1) {
        !           524:                tv = time;
        !           525:         HFSTIMES(hp, &tv, &tv);
        !           526:        }
        !           527:     simple_unlock(&vp->v_interlock);
        !           528: 
        !           529:        /*
        !           530:         * VOP_CLOSE can be called with vp locked (from vclean).
        !           531:         * We check for this case using VOP_ISLOCKED and bail.
        !           532:         *
        !           533:         * also, ignore complex nodes; there's no data associated with them.
        !           534:         */
        !           535:        if (H_FORKTYPE(hp) == kDirectory || VOP_ISLOCKED(vp)) {
        !           536:                DBG_VOP_LOCKS_TEST(E_NONE);
        !           537:                return E_NONE;
        !           538:        };
        !           539: 
        !           540:        fcb = HTOFCB(hp);
        !           541:        leof = fcb->fcbEOF;
        !           542:        
        !           543:        if (leof != 0) {
        !           544:                enum vtype our_type = vp->v_type;
        !           545:                u_long our_id = vp->v_id;
        !           546:                
        !           547:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
        !           548:                /*
        !           549:                 * Since we can contact switch in vn_lock our vnode
        !           550:                 * could get recycled (eg umount -f).  Double check
        !           551:                 * that its still ours.
        !           552:                 */
        !           553:                if (vp->v_type != our_type || vp->v_id != our_id) {
        !           554:                        VOP_UNLOCK(vp, 0, p);
        !           555:                        DBG_VOP_LOCKS_TEST(E_NONE);
        !           556:                        return(E_NONE);
        !           557:                }
        !           558: 
        !           559:                blocksize = HTOVCB(hp)->blockSize;
        !           560:                blks = leof / blocksize;
        !           561:                if ((blks * blocksize) != leof)
        !           562:                        blks++;
        !           563:        
        !           564:                /*
        !           565:                 * Shrink the peof to the smallest size neccessary to contain the leof.
        !           566:                 */
        !           567:                if ((blks * blocksize) < fcb->fcbPLen) {
        !           568:                        retval = VOP_TRUNCATE(vp, leof, 0, ap->a_cred, p);
        !           569:                }
        !           570: 
        !           571:                if (doclusterwrite) {
        !           572:                        long devBlockSize = 0;
        !           573: 
        !           574:                        VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize);
        !           575:                        cluster_close(vp, PAGE_SIZE, devBlockSize);
        !           576:                }
        !           577: 
        !           578:                VOP_UNLOCK(vp, 0, p);
        !           579:        }
        !           580: 
        !           581:        DBG_VOP_LOCKS_TEST(retval);
        !           582:        return (retval);
        !           583: }
        !           584: 
        !           585: /*
        !           586: #% access      vp      L L L
        !           587: #
        !           588:  vop_access {
        !           589:      IN struct vnode *vp;
        !           590:      IN int mode;
        !           591:      IN struct ucred *cred;
        !           592:      IN struct proc *p;
        !           593: 
        !           594:      */
        !           595: 
        !           596: static int
        !           597: hfs_access(ap)
        !           598: struct vop_access_args /* {
        !           599:     struct vnode *a_vp;
        !           600:     int  a_mode;
        !           601:     struct ucred *a_cred;
        !           602:     struct proc *a_p;
        !           603: } */ *ap;
        !           604: {
        !           605:     struct vnode *vp                   = ap->a_vp;
        !           606:     struct ucred *cred                         = ap->a_cred;
        !           607:     struct hfsnode *hp                         = VTOH(vp);
        !           608:     ExtendedVCB        *vcb                    = HTOVCB(hp);
        !           609:     register gid_t *gp;
        !           610:     mode_t mask, mode;
        !           611:     Boolean isHFSPlus;
        !           612:     int retval                                         = E_NONE;
        !           613:     int i;
        !           614:     DBG_FUNC_NAME("access");
        !           615:     DBG_VOP_LOCKS_DECL(1);
        !           616: //    DBG_VOP_PRINT_FUNCNAME();
        !           617: //    DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           618: 
        !           619:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !           620:    
        !           621:         mode           = ap->a_mode;
        !           622:      isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord );
        !           623: 
        !           624:      /*
        !           625:       * Disallow write attempts on read-only file systems;
        !           626:       * unless the file is a socket, fifo, or a block or
        !           627:       * character device resident on the file system.
        !           628:       */
        !           629:      if (mode & VWRITE) {
        !           630:          switch (vp->v_type) {
        !           631:          case VDIR:
        !           632:          case VLNK:
        !           633:          case VREG:
        !           634:              if (VTOVFS(vp)->mnt_flag & MNT_RDONLY)
        !           635:                  return (EROFS);
        !           636:              break;
        !           637:                default:
        !           638:                        break;
        !           639:          }
        !           640:      }
        !           641: 
        !           642:      /* If immutable bit set, nobody gets to write it. */
        !           643:      if ((mode & VWRITE) && (hp->h_meta->h_pflags & IMMUTABLE))
        !           644:          return (EPERM);
        !           645: 
        !           646:      /* Otherwise, user id 0 always gets access. */
        !           647:      if (ap->a_cred->cr_uid == 0) {
        !           648:          retval = 0;
        !           649:          goto Exit;
        !           650:      };
        !           651: 
        !           652:      mask = 0;
        !           653: 
        !           654:     /* Otherwise, check the owner. */
        !           655:     if (cred->cr_uid == hp->h_meta->h_uid) {
        !           656:         if (mode & VEXEC)
        !           657:             mask |= S_IXUSR;
        !           658:         if (mode & VREAD)
        !           659:             mask |= S_IRUSR;
        !           660:         if (mode & VWRITE)
        !           661:             mask |= S_IWUSR;
        !           662:         retval =  ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
        !           663:         goto Exit;
        !           664:     }
        !           665: 
        !           666:     /* Otherwise, check the groups. */
        !           667:     for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
        !           668:         if (hp->h_meta->h_gid == *gp) {
        !           669:             if (mode & VEXEC)
        !           670:                 mask |= S_IXGRP;
        !           671:             if (mode & VREAD)
        !           672:                 mask |= S_IRGRP;
        !           673:             if (mode & VWRITE)
        !           674:                 mask |= S_IWGRP;
        !           675:             retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
        !           676:                        goto Exit;
        !           677:         }
        !           678: 
        !           679:     /* Otherwise, check everyone else. */
        !           680:     if (mode & VEXEC)
        !           681:         mask |= S_IXOTH;
        !           682:     if (mode & VREAD)
        !           683:         mask |= S_IROTH;
        !           684:     if (mode & VWRITE)
        !           685:         mask |= S_IWOTH;
        !           686:     retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
        !           687: 
        !           688: Exit:
        !           689:        DBG_VOP_LOCKS_TEST(retval);
        !           690:        return (retval);    
        !           691: }
        !           692: 
        !           693: 
        !           694: 
        !           695: /*
        !           696: #% getattr     vp      = = =
        !           697: #
        !           698:  vop_getattr {
        !           699:      IN struct vnode *vp;
        !           700:      IN struct vattr *vap;
        !           701:      IN struct ucred *cred;
        !           702:      IN struct proc *p;
        !           703: 
        !           704:      */
        !           705: 
        !           706: 
        !           707: /* ARGSUSED */
        !           708: static int
        !           709: hfs_getattr(ap)
        !           710: struct vop_getattr_args /* {
        !           711:     struct vnode *a_vp;
        !           712:     struct vattr *a_vap;
        !           713:     struct ucred *a_cred;
        !           714:     struct proc *a_p;
        !           715: } */ *ap;
        !           716: {
        !           717:     register struct vnode      *vp = ap->a_vp;
        !           718:     register struct hfsnode *hp = VTOH(vp);
        !           719:     register struct vattr      *vap = ap->a_vap;
        !           720:     struct timeval                     tv;
        !           721:     DBG_FUNC_NAME("getattr");
        !           722:     DBG_VOP_LOCKS_DECL(1);
        !           723:     DBG_VOP_PRINT_FUNCNAME();
        !           724:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           725: 
        !           726:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
        !           727: 
        !           728:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !           729: 
        !           730:     tv = time;
        !           731:     HFSTIMES(hp, &tv, &tv);
        !           732: 
        !           733:     vap->va_fsid = H_DEV(hp);
        !           734:     vap->va_fileid = H_FILEID(hp);
        !           735:     vap->va_mode = hp->h_meta->h_mode;
        !           736:     vap->va_uid = hp->h_meta->h_uid;
        !           737:     vap->va_gid = hp->h_meta->h_gid;
        !           738:     vap->va_rdev = hp->h_meta->h_rdev;
        !           739: #if    MACH_NBC
        !           740:     if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
        !           741:         (!vp->v_vm_info->filesize)) {
        !           742:         vap->va_size = vp->v_vm_info->vnode_size;
        !           743:        } 
        !           744:        else 
        !           745: #endif /* MACH_NBC */
        !           746:     if (vp->v_type == VDIR) {
        !           747:         vap->va_size = hp->h_meta->h_size;
        !           748:         vap->va_bytes = 0;
        !           749:        vap->va_nlink = 2 + hp->h_meta->h_valence;
        !           750:                /* 
        !           751:                 * account for hidden data nodes directory
        !           752:                 */
        !           753:                if ((H_FILEID(hp) == kRootDirID) &&
        !           754:                    (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
        !           755:                        vap->va_size -= AVERAGE_HFSDIRENTRY_SIZE;
        !           756:                        vap->va_nlink--;
        !           757:                }
        !           758:     }
        !           759:     else {
        !           760:         vap->va_size = hp->fcbEOF;
        !           761:         vap->va_bytes = hp->h_meta->h_size;
        !           762: 
        !           763:                if (hp->h_meta->h_metaflags & IN_DELETED)
        !           764:                        vap->va_nlink = 0;
        !           765: #if HFS_HARDLINKS
        !           766:                else if ((hp->h_meta->h_metaflags & IN_DATANODE) &&
        !           767:                         (hp->h_meta->h_nlink > 0))
        !           768:                        vap->va_nlink = hp->h_meta->h_nlink;
        !           769: #endif
        !           770:                else
        !           771:                        vap->va_nlink = 1;
        !           772: 
        !           773:     }
        !           774: 
        !           775:     vap->va_atime.tv_nsec = 0;
        !           776:     vap->va_atime.tv_sec = hp->h_meta->h_atime;
        !           777:     vap->va_mtime.tv_nsec = 0;
        !           778:     vap->va_mtime.tv_sec = hp->h_meta->h_mtime;
        !           779:     vap->va_ctime.tv_nsec = 0;
        !           780:     vap->va_ctime.tv_sec = hp->h_meta->h_ctime;
        !           781:     vap->va_flags = hp->h_meta->h_pflags;
        !           782:     vap->va_gen = 0;
        !           783:     /* this doesn't belong here */
        !           784:     if (vp->v_type == VBLK)
        !           785:         vap->va_blocksize = BLKDEV_IOSIZE;
        !           786:     else if (vp->v_type == VCHR)
        !           787:         vap->va_blocksize = MAXPHYSIO;
        !           788:     else
        !           789:         vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize;
        !           790:        vap->va_type = vp->v_type;
        !           791:     vap->va_filerev = 0;
        !           792: 
        !           793:     DBG_VOP_LOCKS_TEST(E_NONE);
        !           794:     return (E_NONE);
        !           795: }
        !           796: 
        !           797: /*
        !           798:  * Set attribute vnode op. called from several syscalls
        !           799: #% setattr     vp      L L L
        !           800: #
        !           801:  vop_setattr {
        !           802:      IN struct vnode *vp;
        !           803:      IN struct vattr *vap;
        !           804:      IN struct ucred *cred;
        !           805:      IN struct proc *p;
        !           806: 
        !           807:      */
        !           808: 
        !           809: static int
        !           810: hfs_setattr(ap)
        !           811: struct vop_setattr_args /* {
        !           812: struct vnode *a_vp;
        !           813: struct vattr *a_vap;
        !           814: struct ucred *a_cred;
        !           815: struct proc *a_p;
        !           816: } */ *ap;
        !           817: {
        !           818:     struct vnode       *vp = ap->a_vp;
        !           819:     struct hfsnode     *hp = VTOH(vp);
        !           820:     struct vattr       *vap = ap->a_vap;
        !           821:     struct ucred       *cred = ap->a_cred;
        !           822:     struct proc        *p = ap->a_p;
        !           823:     struct timeval     atimeval, mtimeval;
        !           824:     int                                retval;
        !           825:     DBG_FUNC_NAME("setattr");
        !           826:     DBG_VOP_LOCKS_DECL(1);
        !           827:     DBG_VOP_PRINT_FUNCNAME();
        !           828:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           829:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !           830:     WRITE_CK(vp, funcname);
        !           831:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !           832: 
        !           833:     /*
        !           834:      * Check for unsettable attributes.
        !           835:      */
        !           836:     if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
        !           837:         (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
        !           838:         (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
        !           839:         ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
        !           840:         retval = EINVAL;
        !           841:         goto ErrorExit;
        !           842:     }
        !           843: 
        !           844:     if (vap->va_flags != VNOVAL) {
        !           845:         if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !           846:             retval = EROFS;
        !           847:             goto ErrorExit;
        !           848:         };
        !           849:         if ((retval = hfs_chflags(vp, vap->va_flags, cred, p))) {
        !           850:             goto ErrorExit;
        !           851:         };
        !           852:         if (vap->va_flags & (IMMUTABLE | APPEND)) {
        !           853:             retval = 0;
        !           854:             goto ErrorExit;
        !           855:         };
        !           856:     }
        !           857: 
        !           858:     if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) {
        !           859:         retval = EPERM;
        !           860:         goto ErrorExit;
        !           861:     };
        !           862:     /*
        !           863:      * Go through the fields and update iff not VNOVAL.
        !           864:      */
        !           865:     if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
        !           866:         if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !           867:             retval = EROFS;
        !           868:             goto ErrorExit;
        !           869:         };
        !           870:         if ((retval = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) {
        !           871:             goto ErrorExit;
        !           872:         };
        !           873:     }
        !           874:     if (vap->va_size != VNOVAL) {
        !           875:         /*
        !           876:          * Disallow write attempts on read-only file systems;
        !           877:          * unless the file is a socket, fifo, or a block or
        !           878:          * character device resident on the file system.
        !           879:          */
        !           880:         switch (vp->v_type) {
        !           881:             case VDIR:
        !           882:                 retval = EISDIR;
        !           883:                 goto ErrorExit;
        !           884:             case VLNK:
        !           885:             case VREG:
        !           886:                 if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !           887:                     retval = EROFS;
        !           888:                     goto ErrorExit;
        !           889:                 };
        !           890:                 break;
        !           891:             default:
        !           892:                 break;
        !           893:         }
        !           894:         if ((retval = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))) {
        !           895:             goto ErrorExit;
        !           896:         };
        !           897:     }
        !           898:     hp = VTOH(vp);
        !           899:     if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
        !           900:         if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !           901:             retval = EROFS;
        !           902:             goto ErrorExit;
        !           903:         };
        !           904:         if (cred->cr_uid != hp->h_meta->h_uid &&
        !           905:             (retval = suser(cred, &p->p_acflag)) &&
        !           906:             ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
        !           907:              (retval = VOP_ACCESS(vp, VWRITE, cred, p)))) {
        !           908:             goto ErrorExit;
        !           909:         };
        !           910:         if (vap->va_atime.tv_sec != VNOVAL)
        !           911:             hp->h_nodeflags |= IN_ACCESS;
        !           912:         if (vap->va_mtime.tv_sec != VNOVAL)
        !           913:             hp->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !           914:         atimeval.tv_sec = vap->va_atime.tv_sec;
        !           915:         atimeval.tv_usec = 0;
        !           916:         mtimeval.tv_sec = vap->va_mtime.tv_sec;
        !           917:         mtimeval.tv_usec = 0;
        !           918:         if ((retval = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))) {
        !           919:             goto ErrorExit;
        !           920:         };
        !           921:     }
        !           922:     retval = 0;
        !           923:     if (vap->va_mode != (mode_t)VNOVAL) {
        !           924:         if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !           925:             retval = EROFS;
        !           926:             goto ErrorExit;
        !           927:         };
        !           928:         retval = hfs_chmod(vp, (int)vap->va_mode, cred, p);
        !           929:     };
        !           930: 
        !           931: ErrorExit: ;
        !           932: 
        !           933:     DBG_VOP(("hfs_setattr: returning %d...\n", retval));
        !           934:     DBG_VOP_LOCKS_TEST(retval);
        !           935:     return (retval);
        !           936: }
        !           937: 
        !           938: 
        !           939: /*
        !           940: 
        !           941: #
        !           942: #% getattrlist vp      = = =
        !           943: #
        !           944:  vop_getattrlist {
        !           945:      IN struct vnode *vp;
        !           946:      IN struct attrlist *alist;
        !           947:      INOUT struct uio *uio;
        !           948:      IN struct ucred *cred;
        !           949:      IN struct proc *p;
        !           950:  };
        !           951: 
        !           952:  */
        !           953: 
        !           954: static int
        !           955: hfs_getattrlist(ap)
        !           956: struct vop_getattrlist_args /* {
        !           957: struct vnode *a_vp;
        !           958: struct attrlist *a_alist
        !           959: struct uio *a_uio;
        !           960: struct ucred *a_cred;
        !           961: struct proc *a_p;
        !           962: } */ *ap;
        !           963: {
        !           964:     struct vnode *vp = ap->a_vp;
        !           965:     struct hfsnode *hp = VTOH(vp);
        !           966:     struct attrlist *alist = ap->a_alist;
        !           967:     int error = 0;
        !           968:     struct hfsCatalogInfo catalogInfo;
        !           969:     struct hfsCatalogInfo *catInfoPtr = NULL;
        !           970:     int fixedblocksize;
        !           971:     int attrblocksize;
        !           972:     int attrbufsize;
        !           973:     void *attrbufptr;
        !           974:     void *attrptr;
        !           975:     void *varptr;
        !           976:     u_int32_t fileID;
        !           977:     DBG_FUNC_NAME("getattrlist");
        !           978:     DBG_VOP_LOCKS_DECL(1);
        !           979: 
        !           980:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
        !           981:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !           982:     DBG_VOP(("%s: Common attr:0x%lx, buff size Ox%lX,\n",funcname, (u_long)alist->commonattr,(u_long)ap->a_uio->uio_resid));
        !           983: 
        !           984:     DBG_ASSERT(ap->a_uio->uio_rw == UIO_READ);
        !           985: 
        !           986:     if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
        !           987:         ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
        !           988:         ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) ||
        !           989:         ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
        !           990:         ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) ||
        !           991:         ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) {
        !           992:         DBG_ERR(("%s: bad attrlist\n", funcname));
        !           993:         DBG_VOP_LOCKS_TEST(EINVAL);
        !           994:         return EINVAL;
        !           995:         };
        !           996: 
        !           997:     /* Requesting volume information requires setting the ATTR_VOL_INFO bit and
        !           998:         volume info requests are mutually exclusive with all other info requests: */
        !           999:    if ((alist->volattr != 0) && (((alist->volattr & ATTR_VOL_INFO) == 0) ||
        !          1000:         (alist->dirattr != 0) || (alist->fileattr != 0) || (alist->forkattr != 0)
        !          1001:                )) {
        !          1002:         DBG_ERR(("%s: conflicting information requested\n", funcname));
        !          1003:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1004:         return EINVAL;
        !          1005:         };
        !          1006: 
        !          1007:     /* Reject requests for unsupported options for now: */
        !          1008:     if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
        !          1009:         (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
        !          1010:         DBG_ERR(("%s: illegal bits in attlist\n", funcname));
        !          1011:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1012:         return EINVAL;
        !          1013:         };
        !          1014: 
        !          1015:        /* Requesting volume information requires root vnode */ 
        !          1016:     if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) {
        !          1017:         DBG_ERR(("%s: not root vnode\n", funcname));
        !          1018:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1019:         return EINVAL;
        !          1020:        };
        !          1021: 
        !          1022:        /* If a FileID (ATTR_CMN_OBJPERMANENTID) is requested on an HFS volume we must be sure
        !          1023:                to create the thread record before returning it:
        !          1024:                */
        !          1025:        if ((vp->v_type == VREG) &&
        !          1026:                (alist->commonattr & ATTR_CMN_OBJPERMANENTID)) {
        !          1027:                /* Only HFS-Plus volumes are guaranteed to have a thread record in place already: */
        !          1028:                if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) {
        !          1029:                        /* Create a thread record and return the FileID [which is the file's fileNumber] */
        !          1030:                        /* lock catalog b-tree */
        !          1031:                        error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p);
        !          1032:                        error = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID);
        !          1033:                        (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p);
        !          1034:                        if (error) {
        !          1035:                                DBG_VOP_LOCKS_TEST(error);
        !          1036:                                DBG_ERR(("hfs_getattrlist: error %d on CreateFileIDRef.\n", error));
        !          1037:                                return error;
        !          1038:                        };
        !          1039:                        DBG_ASSERT(fileID == H_FILEID(hp));
        !          1040:                };
        !          1041:        };
        !          1042: 
        !          1043:     /*
        !          1044:         * Avoid unnecessary catalog lookups for volume info which is available directly
        !          1045:         * in the VCB and root vnode, or can be synthesized.
        !          1046:         */
        !          1047:     if (((alist->volattr == 0) && ((alist->commonattr & HFS_ATTR_CMN_LOOKUPMASK) != 0)) ||
        !          1048:         ((alist->dirattr & HFS_ATTR_DIR_LOOKUPMASK) != 0) ||
        !          1049:         ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0)) {
        !          1050: 
        !          1051:         /* lock catalog b-tree */
        !          1052:         error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, ap->a_p);
        !          1053:         if (error) {
        !          1054:             DBG_VOP_LOCKS_TEST(error);
        !          1055:             return (error);
        !          1056:             }
        !          1057: 
        !          1058:         if (alist->volattr != 0) {
        !          1059:             /* Look up the root info, regardless of the vnode provided */
        !          1060:                        catalogInfo.hint = kNoHint;
        !          1061:             error = hfsLookup(VTOVCB(vp), 2, NULL,  -1, &catalogInfo);
        !          1062:             } else {
        !          1063:                                catalogInfo.hint = kNoHint;
        !          1064:                 error = hfsLookup(VTOVCB(vp), H_DIRID(hp), H_NAME(hp),  -1, &catalogInfo);
        !          1065:                 if (error == 0) H_HINT(hp) = catalogInfo.hint;                                         /* Remember the last valid hint */
        !          1066:                 };
        !          1067:         catInfoPtr = &catalogInfo;
        !          1068: 
        !          1069:         /* unlock catalog b-tree */
        !          1070:         (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p);
        !          1071:     };
        !          1072: 
        !          1073:     fixedblocksize = AttributeBlockSize(alist);
        !          1074:     attrblocksize = fixedblocksize + (sizeof(u_long));                                                 /* u_long for length longword */
        !          1075:     if (alist->commonattr & ATTR_CMN_NAME) attrblocksize += NAME_MAX + 1;
        !          1076:     if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) attrblocksize += 0;                        /* XXX PPD */
        !          1077:     if (alist->volattr & ATTR_VOL_MOUNTPOINT) attrblocksize += PATH_MAX;
        !          1078:     if (alist->volattr & ATTR_VOL_NAME) attrblocksize += NAME_MAX + 1;
        !          1079:     if (alist->fileattr & ATTR_FILE_FORKLIST) attrblocksize += 0;                              /* XXX PPD */
        !          1080: 
        !          1081:     attrbufsize = MIN(ap->a_uio->uio_resid, attrblocksize);
        !          1082:     DBG_VOP(("hfs_getattrlist: allocating Ox%X byte buffer (Ox%X + Ox%X) for attributes...\n",
        !          1083:              attrblocksize,
        !          1084:              fixedblocksize,
        !          1085:              attrblocksize - fixedblocksize));
        !          1086:     MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
        !          1087:     attrptr = attrbufptr;
        !          1088:     *((u_long *)attrptr) = 0;                                                                  /* Set buffer length in case of errors */
        !          1089:     ++((u_long *)attrptr);                                                                             /* Reserve space for length field */
        !          1090:     varptr = ((char *)attrptr) + fixedblocksize;                               /* Point to variable-length storage */
        !          1091:     DBG_VOP(("hfs_getattrlist: attrptr = 0x%08X, varptr = 0x%08X...\n", (u_int)attrptr, (u_int)varptr));
        !          1092: 
        !          1093:     PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr);
        !          1094:     attrbufsize = MIN(attrbufsize, (u_int)varptr - (u_int)attrbufptr); /* Don't copy out more data than was generated */
        !          1095:     DBG_VOP(("hfs_getattrlist: copying Ox%X bytes to user address 0x%08X.\n", attrbufsize, (u_int)ap->a_uio->uio_iov->iov_base));
        !          1096:     error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio);
        !          1097:     if (error != E_NONE) {
        !          1098:         DBG_ERR(("hfs_getattrlist: error %d on uiomove.\n", error));
        !          1099:         };
        !          1100: 
        !          1101:     FREE(attrbufptr, M_TEMP);
        !          1102: 
        !          1103:     DBG_VOP_LOCKS_TEST(error);
        !          1104:     return error;
        !          1105: }
        !          1106: 
        !          1107: 
        !          1108: 
        !          1109: #if 0 // OBSOLETE
        !          1110: /* This is a special permission-checking routine that tests for "write" access without
        !          1111:    regard for the UF_IMMUTABLE or SF_IMMUTABLE bits in the flags.  hfs_setattrlist cannot
        !          1112:    use VOP_ACCESS for this check so this is a derivative of that code that does this check.
        !          1113:  */
        !          1114: static int hfs_writepermission(struct vnode *vp, struct ucred *cred, struct proc *p) {
        !          1115:     struct hfsnode *hp = VTOH(vp);
        !          1116:     int i;
        !          1117:     register gid_t *gp;
        !          1118: 
        !          1119:        /* Start by checking for root */
        !          1120:        if (suser(cred, &p->p_acflag) == 0) return 0;
        !          1121:        
        !          1122:        /* Check the owner: */
        !          1123:        if (cred->cr_uid == hp->h_meta->h_uid) {
        !          1124:                return (hp->h_meta->h_mode & S_IWUSR) ? 0 : EACCES;
        !          1125:        };
        !          1126: 
        !          1127:        /* Otherwise, check the groups: */
        !          1128:     for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) {
        !          1129:                if (hp->h_meta->h_gid == *gp) {
        !          1130:                        return (hp->h_meta->h_mode & S_IWGRP) ? 0 : EACCES;
        !          1131:         };
        !          1132:    };
        !          1133: 
        !          1134:    /* Otherwise, check everyone else. */
        !          1135:    return (hp->h_meta->h_mode & S_IWOTH) ? 0 : EACCES;
        !          1136: }
        !          1137: #endif
        !          1138: 
        !          1139: 
        !          1140: 
        !          1141: /*
        !          1142: 
        !          1143: #
        !          1144: #% setattrlist vp      L L L
        !          1145: #
        !          1146:  vop_setattrlist {
        !          1147:      IN struct vnode *vp;
        !          1148:      IN struct attrlist *alist;
        !          1149:      INOUT struct uio *uio;
        !          1150:      IN struct ucred *cred;
        !          1151:      IN struct proc *p;
        !          1152:  };
        !          1153: 
        !          1154:  */
        !          1155: 
        !          1156: static int
        !          1157: hfs_setattrlist(ap)
        !          1158: struct vop_setattrlist_args /* {
        !          1159: struct vnode *a_vp;
        !          1160: struct attrlist *a_alist
        !          1161: struct uio *a_uio;
        !          1162: struct ucred *a_cred;
        !          1163: struct proc *a_p;
        !          1164: } */ *ap;
        !          1165: {
        !          1166:     struct vnode *vp = ap->a_vp;
        !          1167:     struct hfsnode *hp = VTOH(vp);
        !          1168:     struct attrlist *alist = ap->a_alist;
        !          1169:     struct ucred *cred = ap->a_cred;
        !          1170:     struct proc *p = ap->a_p;
        !          1171:     int error;
        !          1172:     struct hfsCatalogInfo catalogInfo;
        !          1173:     int attrblocksize;
        !          1174:     void *attrbufptr = NULL;
        !          1175:     void *attrptr;
        !          1176:     void *varptr = NULL;
        !          1177:        uid_t saved_uid;
        !          1178:        gid_t saved_gid;
        !          1179:        mode_t saved_mode;
        !          1180:     u_long saved_flags;
        !          1181:        char * filename;
        !          1182:        u_int32_t pid;
        !          1183:     int retval = 0;
        !          1184: 
        !          1185:     DBG_FUNC_NAME("setattrlist");
        !          1186:     DBG_VOP_LOCKS_DECL(1);
        !          1187: 
        !          1188:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
        !          1189:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !          1190:     DBG_VOP(("%s: Common attr:0x%x, buff size Ox%X,\n",funcname, (u_int)alist->commonattr,(u_int)ap->a_uio->uio_resid));
        !          1191: 
        !          1192:     DBG_ASSERT(ap->a_uio->uio_rw == UIO_WRITE);
        !          1193: 
        !          1194:     if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
        !          1195:         ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) ||
        !          1196:         ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) ||
        !          1197:         ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) ||
        !          1198:         ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0) ||
        !          1199:         ((alist->forkattr & ~ATTR_FORK_SETMASK) != 0)) {
        !          1200:         DBG_ERR(("%s: Bad attrlist\n", funcname));
        !          1201:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1202:         return EINVAL;
        !          1203:         };
        !          1204: 
        !          1205:     if ((alist->volattr != 0) &&                                                       /* Setting volume info */
        !          1206:                (((alist->volattr & ATTR_VOL_INFO) == 0) ||                     /* Not explicitly indicating this or ... */
        !          1207:                 (alist->commonattr & ~ATTR_CMN_VOLSETMASK)))           /* ... setting invalid attributes for volume */
        !          1208:       {
        !          1209:         DBG_ERR(("%s: Bad attrlist\n", funcname));
        !          1210:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1211:         return EINVAL;
        !          1212:       };
        !          1213: 
        !          1214:     if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
        !          1215:         DBG_VOP_LOCKS_TEST(EROFS);
        !          1216:         return EROFS;
        !          1217:     };
        !          1218: 
        !          1219:        /*
        !          1220:                Ownership of the file (in addition to write access, checked below,
        !          1221:                is required in one of two classes of calls:
        !          1222:                
        !          1223:                (a) When setting any ownership-requiring attribute other than ATTR_CMN_FLAGS, or
        !          1224:                (b) When setting ATTR_CMN_FLAGS on a volume that's not plain HFS (for which no
        !          1225:                        real per-object ownership information is stored):
        !          1226:         */
        !          1227:        if ((alist->commonattr & (OWNERSHIP_ONLY_ATTRS & ~ATTR_CMN_FLAGS)) ||
        !          1228:                ((alist->commonattr & ATTR_CMN_FLAGS) && (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) {
        !          1229:                /* NOTE: The following isn't ENTIRELY complete: even if you're the superuser
        !          1230:                                 you cannot change the flags as long as SF_IMMUTABLE or SF_APPEND is
        !          1231:                                 set and securelevel > 0.  This is verified in hfs_chflags which gets
        !          1232:                                 invoked to do the actual flags field change so this check is sufficient
        !          1233:                                 for now.
        !          1234:                 */
        !          1235:                /* Check to see if the user owns the object [or is superuser]: */
        !          1236:        if (cred->cr_uid != hp->h_meta->h_uid &&
        !          1237:                (retval = suser(cred, &p->p_acflag))) {
        !          1238:                DBG_VOP_LOCKS_TEST(retval);
        !          1239:                return retval;
        !          1240:         };
        !          1241:        } else {
        !          1242:                DBG_ASSERT(((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == 0) ||
        !          1243:                                   (((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == ATTR_CMN_FLAGS) &&
        !          1244:                                        (VTOVCB(vp)->vcbSigWord == kHFSSigWord)));
        !          1245:                /* No ownership access is required: mere write access (checked below) will do... */
        !          1246:        };
        !          1247:        
        !          1248:        /* For any other attributes, check to see if the user has write access to
        !          1249:            the object in question [unlike VOP_ACCESS, ignore IMMUTABLE here]: */
        !          1250:            
        !          1251:        if ((((alist->commonattr & ~(OWNERSHIP_ONLY_ATTRS)) != 0) ||
        !          1252:                 (alist->volattr != 0) ||
        !          1253:                 (alist->dirattr != 0) ||
        !          1254:                 (alist->fileattr != 0) ||
        !          1255:                 (alist->forkattr != 0)) &&
        !          1256:                ((retval = hfs_write_access(vp, cred, p, false)) != 0)) {
        !          1257:         DBG_VOP_LOCKS_TEST(retval);
        !          1258:         return retval;
        !          1259:        }; /* end of if ownership attr */
        !          1260:        
        !          1261:     /* Allocate the buffer now to minimize the time we might be blocked holding the catalog lock */
        !          1262:     attrblocksize = ap->a_uio->uio_resid;
        !          1263:     if (attrblocksize < AttributeBlockSize(alist)) {
        !          1264:         DBG_ERR(("%s: bad attrblocksize\n", funcname));
        !          1265:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1266:         return EINVAL;
        !          1267:     };
        !          1268: 
        !          1269:    MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
        !          1270:     
        !          1271:     /* lock catalog b-tree */
        !          1272:     error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          1273:     if (error != E_NONE) {
        !          1274:         goto FreeBuffer;
        !          1275:     };
        !          1276: 
        !          1277:        filename = H_NAME(hp);
        !          1278:        pid = H_DIRID(hp);
        !          1279: 
        !          1280: #if HFS_HARDLINKS
        !          1281:        /*
        !          1282:         * Force an update of the data node instead of the link node
        !          1283:         * by passing the fileID instead of parID and name.
        !          1284:         */
        !          1285:        if (hp->h_meta->h_metaflags & IN_DATANODE) {
        !          1286:                filename = NULL;
        !          1287:                pid = H_FILEID(hp);
        !          1288:        }
        !          1289: #endif
        !          1290:        catalogInfo.hint = kNoHint;
        !          1291:        error = hfsLookup(VTOVCB(vp), pid, filename, -1, &catalogInfo);
        !          1292:     if (error != E_NONE) {
        !          1293:         DBG_ERR(("%s: Lookup failed on file '%s'\n", funcname,  filename));
        !          1294:         goto ErrorExit;
        !          1295:     };
        !          1296:     H_HINT(hp) = catalogInfo.hint;                                             /* Remember the last valid hint */
        !          1297: 
        !          1298:     error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
        !          1299:     if (error) goto ErrorExit;
        !          1300: 
        !          1301:     if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) {
        !          1302:         error = EINVAL;
        !          1303:         goto ErrorExit;
        !          1304:     };
        !          1305: 
        !          1306:        /* do we have permission to change the dates? */
        !          1307: //  if (alist->commonattr & (ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME)) {
        !          1308:     if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) {
        !          1309:         if (cred->cr_uid != hp->h_meta->h_uid && (error = suser(cred, &p->p_acflag))) {
        !          1310:             goto ErrorExit;
        !          1311:         };
        !          1312:     };
        !          1313: 
        !          1314:     /* save these in case hfs_chown() or hfs_chmod() fail */
        !          1315:        saved_uid = hp->h_meta->h_uid;
        !          1316:        saved_gid = hp->h_meta->h_gid;
        !          1317:     saved_mode = hp->h_meta->h_mode;
        !          1318:     saved_flags = hp->h_meta->h_pflags;
        !          1319: 
        !          1320:     attrptr = attrbufptr;
        !          1321:     UnpackAttributeBlock(alist, vp, &catalogInfo, &attrptr, &varptr);
        !          1322: 
        !          1323:        /* if unpacking changed the owner or group then call hfs_chown() */
        !          1324:     if (saved_uid != hp->h_meta->h_uid || saved_gid != hp->h_meta->h_gid) {
        !          1325:                uid_t uid;
        !          1326:                gid_t gid;
        !          1327:                
        !          1328:                uid = hp->h_meta->h_uid;
        !          1329:                hp->h_meta->h_uid = saved_uid;
        !          1330:                gid = hp->h_meta->h_gid;
        !          1331:                hp->h_meta->h_gid = saved_gid;
        !          1332:         if ((error = hfs_chown(vp, uid, gid, cred, p)))
        !          1333:                        goto ErrorExit;
        !          1334:     }
        !          1335: 
        !          1336:        /* if unpacking changed the mode then call hfs_chmod() */
        !          1337:        if (saved_mode != hp->h_meta->h_mode) {
        !          1338:                mode_t mode;
        !          1339: 
        !          1340:                mode = hp->h_meta->h_mode;
        !          1341:                hp->h_meta->h_mode = saved_mode;
        !          1342:                if ((error = hfs_chmod(vp, mode, cred, p)))
        !          1343:                        goto ErrorExit;
        !          1344:        };
        !          1345: 
        !          1346:     /* if unpacking changed the flags then call hfs_chflags */
        !          1347:     if (saved_flags != hp->h_meta->h_pflags) {
        !          1348:         u_long flags;
        !          1349: 
        !          1350:         flags = hp->h_meta->h_pflags;
        !          1351:         hp->h_meta->h_pflags = saved_flags;
        !          1352:         if ((error = hfs_chflags(vp, flags, cred, p)))
        !          1353:             goto ErrorExit;
        !          1354:     };
        !          1355: 
        !          1356:        if (alist->volattr == 0) {
        !          1357:                error = MacToVFSError( UpdateCatalogNode(HTOVCB(hp), pid, filename, H_HINT(hp), &catalogInfo.nodeData));
        !          1358:        }
        !          1359: 
        !          1360:    if (alist->volattr & ATTR_VOL_NAME) {
        !          1361:         ExtendedVCB *vcb       = VTOVCB(vp);
        !          1362:         int                    namelen = strlen(vcb->vcbVN);
        !          1363:        
        !          1364:        if (vcb->vcbVN[0] == 0) {
        !          1365:          /*
        !          1366:            Ignore attempts to rename a volume to a zero-length name:
        !          1367:            restore the original name from the metadata.
        !          1368:           */
        !          1369:          copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
        !          1370:        } else {
        !          1371:          error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp), kRootParID, vcb->vcbVN, &H_HINT(hp));
        !          1372:          if (error) {
        !          1373:             VCB_LOCK(vcb);
        !          1374:             copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */
        !          1375:             vcb->vcbFlags |= 0xFF00;           // Mark the VCB dirty
        !          1376:             VCB_UNLOCK(vcb);
        !          1377:             goto ErrorExit;
        !          1378:          };
        !          1379: 
        !          1380:                hfs_set_metaname(vcb->vcbVN, hp->h_meta);
        !          1381:                hp->h_nodeflags |= IN_CHANGE;
        !          1382:                
        !          1383: #if 0
        !          1384:          /* if hfs wrapper exists, update its name too */
        !          1385:          if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->vcbAlBlSt != 0) {
        !          1386:            HFSMasterDirectoryBlock *mdb;
        !          1387:            struct buf *bp = NULL;
        !          1388:            int size = kMDBSize;        /* 512 */
        !          1389:             int volnamelen = MIN(sizeof(Str27), namelen);
        !          1390:            
        !          1391:            if ( bread(VTOHFS(vp)->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
        !          1392:                       IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp) == 0) {
        !          1393:              
        !          1394:              mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
        !          1395:              if (mdb->drSigWord == kHFSSigWord) {
        !          1396:                /* Convert the string to MacRoman, ignoring any errors, */
        !          1397:                (void) utf8_to_hfs(vcb, volnamelen, vcb->vcbVN, Str31 mdb->drVN)
        !          1398:                bawrite(bp);
        !          1399:                bp = NULL;
        !          1400:              }
        !          1401:            }
        !          1402:            
        !          1403:            if (bp) brelse(bp);
        !          1404:          }
        !          1405: #endif
        !          1406:        }; /* vcb->vcbVN[0] == 0 ... else ... */
        !          1407:    }; /* alist->volattr & ATTR_VOL_NAME */
        !          1408: 
        !          1409: ErrorExit:
        !          1410:     /* unlock catalog b-tree */
        !          1411:     (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          1412: 
        !          1413: FreeBuffer:
        !          1414:     if (attrbufptr) FREE(attrbufptr, M_TEMP);
        !          1415: 
        !          1416:     DBG_VOP_LOCKS_TEST(error);
        !          1417:     return error;
        !          1418: }
        !          1419: 
        !          1420: /*
        !          1421:  * Change the mode on a file.
        !          1422:  * Inode must be locked before calling.
        !          1423:  */
        !          1424: static int
        !          1425: hfs_chmod(vp, mode, cred, p)
        !          1426: register struct vnode *vp;
        !          1427: register int mode;
        !          1428: register struct ucred *cred;
        !          1429: struct proc *p;
        !          1430: {
        !          1431:     register struct hfsnode *hp = VTOH(vp);
        !          1432:     int retval;
        !          1433: 
        !          1434:     if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
        !          1435:         return E_NONE;
        !          1436: 
        !          1437:        if (cred->cr_uid != hp->h_meta->h_uid &&
        !          1438:                (retval = suser(cred, &p->p_acflag)))
        !          1439:                return (retval);
        !          1440:        if (cred->cr_uid) {
        !          1441:                if (vp->v_type != VDIR && (mode & S_ISTXT))
        !          1442:                        return (EFTYPE);
        !          1443:                if (!groupmember(hp->h_meta->h_gid, cred) && (mode & ISGID))
        !          1444:                        return (EPERM);
        !          1445:        }
        !          1446:        hp->h_meta->h_mode &= ~ALLPERMS;
        !          1447:        hp->h_meta->h_mode |= (mode & ALLPERMS);
        !          1448:        hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
        !          1449:        hp->h_nodeflags |= IN_CHANGE;
        !          1450:        if ((vp->v_flag & VTEXT) && (hp->h_meta->h_mode & S_ISTXT) == 0)
        !          1451:                (void) vnode_uncache(vp);
        !          1452:        return (0);
        !          1453: }
        !          1454: 
        !          1455: 
        !          1456: static int
        !          1457: hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags)
        !          1458: {
        !          1459:     struct hfsnode *hp                         = VTOH(vp);
        !          1460:     ExtendedVCB        *vcb                    = HTOVCB(hp);
        !          1461:     gid_t *gp;
        !          1462:     Boolean isHFSPlus;
        !          1463:     int retval                                         = E_NONE;
        !          1464:     int i;
        !          1465: 
        !          1466:     isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord );
        !          1467: 
        !          1468:     /*
        !          1469:      * Disallow write attempts on read-only file systems;
        !          1470:      * unless the file is a socket, fifo, or a block or
        !          1471:      * character device resident on the file system.
        !          1472:      */
        !          1473:        switch (vp->v_type) {
        !          1474:          case VDIR:
        !          1475:       case VLNK:
        !          1476:       case VREG:
        !          1477:         if (VTOVFS(vp)->mnt_flag & MNT_RDONLY)
        !          1478:             return (EROFS);
        !          1479:         break;
        !          1480:       default:
        !          1481:                break;
        !          1482:        }
        !          1483:  
        !          1484:        /* If immutable bit set, nobody gets to write it. */
        !          1485:     if (considerFlags && (hp->h_meta->h_pflags & IMMUTABLE))
        !          1486:         return (EPERM);
        !          1487: 
        !          1488:     /* Otherwise, user id 0 always gets access. */
        !          1489:     if (cred->cr_uid == 0) {
        !          1490:         retval = 0;
        !          1491:         goto Exit;
        !          1492:     };
        !          1493: 
        !          1494:     /* Otherwise, check the owner. */
        !          1495:     if (cred->cr_uid == hp->h_meta->h_uid) {
        !          1496:         retval = ((hp->h_meta->h_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES);
        !          1497:         goto Exit;
        !          1498:     }
        !          1499:  
        !          1500:     /* Otherwise, check the groups. */
        !          1501:     for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
        !          1502:         if (hp->h_meta->h_gid == *gp) {
        !          1503:             retval = ((hp->h_meta->h_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES);
        !          1504:                        goto Exit;
        !          1505:         }
        !          1506:  
        !          1507:     /* Otherwise, check everyone else. */
        !          1508:        retval = ((hp->h_meta->h_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES);
        !          1509: 
        !          1510: Exit:
        !          1511:        return (retval);    
        !          1512: }
        !          1513: 
        !          1514: /*
        !          1515:  * Change the flags on a file or directory.
        !          1516:  * Inode must be locked before calling.
        !          1517:  */
        !          1518: static int
        !          1519: hfs_chflags(vp, flags, cred, p)
        !          1520: register struct vnode *vp;
        !          1521: register u_long flags;
        !          1522: register struct ucred *cred;
        !          1523: struct proc *p;
        !          1524: {
        !          1525:     register struct hfsnode *hp = VTOH(vp);
        !          1526:     int retval;
        !          1527: 
        !          1528:        if (VTOVCB(vp)->vcbSigWord == kHFSSigWord) {
        !          1529:                if ((retval = hfs_write_access(vp, cred, p, false)) != 0) {
        !          1530:                        return retval;
        !          1531:                };
        !          1532:        } else if ((cred->cr_uid != hp->h_meta->h_uid) &&
        !          1533:                       (retval = suser(cred, &p->p_acflag))) {
        !          1534:                return retval;
        !          1535:        };
        !          1536: 
        !          1537:        if (cred->cr_uid == 0) {
        !          1538:                if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND)) &&
        !          1539:                        securelevel > 0) {
        !          1540:                        return EPERM;
        !          1541:                };
        !          1542:                hp->h_meta->h_pflags = flags;
        !          1543:        } else {
        !          1544:                if (hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND) ||
        !          1545:                        (flags & UF_SETTABLE) != flags) {
        !          1546:                        return EPERM;
        !          1547:                };
        !          1548:                hp->h_meta->h_pflags &= SF_SETTABLE;
        !          1549:                hp->h_meta->h_pflags |= (flags & UF_SETTABLE);
        !          1550:        }
        !          1551:        hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
        !          1552:        hp->h_nodeflags |= IN_CHANGE;
        !          1553: 
        !          1554:     return 0;
        !          1555: }
        !          1556: 
        !          1557: 
        !          1558: /*
        !          1559:  * Perform chown operation on hfsnode hp;
        !          1560:  * hfsnode must be locked prior to call.
        !          1561:  */
        !          1562: static int
        !          1563: hfs_chown(vp, uid, gid, cred, p)
        !          1564: register struct vnode *vp;
        !          1565: uid_t uid;
        !          1566: gid_t gid;
        !          1567: struct ucred *cred;
        !          1568: struct proc *p;
        !          1569: {
        !          1570:     register struct hfsnode *hp = VTOH(vp);
        !          1571:     uid_t ouid;
        !          1572:     gid_t ogid;
        !          1573:     int retval = 0;
        !          1574: 
        !          1575:     if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
        !          1576:         return EOPNOTSUPP;
        !          1577: 
        !          1578:     if (uid == (uid_t)VNOVAL)
        !          1579:         uid = hp->h_meta->h_uid;
        !          1580:     if (gid == (gid_t)VNOVAL)
        !          1581:         gid = hp->h_meta->h_gid;
        !          1582:     /*
        !          1583:      * If we don't own the file, are trying to change the owner
        !          1584:      * of the file, or are not a member of the target group,
        !          1585:      * the caller must be superuser or the call fails.
        !          1586:      */
        !          1587:     if ((cred->cr_uid != hp->h_meta->h_uid || uid != hp->h_meta->h_uid ||
        !          1588:          (gid != hp->h_meta->h_gid && !groupmember((gid_t)gid, cred))) &&
        !          1589:         (retval = suser(cred, &p->p_acflag)))
        !          1590:         return (retval);
        !          1591:     ogid = hp->h_meta->h_gid;
        !          1592:     ouid = hp->h_meta->h_uid;
        !          1593: 
        !          1594:     hp->h_meta->h_gid = gid;
        !          1595:     hp->h_meta->h_uid = uid;
        !          1596: 
        !          1597:     hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
        !          1598:     if (ouid != uid || ogid != gid)
        !          1599:         hp->h_nodeflags |= IN_CHANGE;
        !          1600:     if (ouid != uid && cred->cr_uid != 0)
        !          1601:         hp->h_meta->h_mode &= ~ISUID;
        !          1602:     if (ogid != gid && cred->cr_uid != 0)
        !          1603:         hp->h_meta->h_mode &= ~ISGID;
        !          1604:     return (0);
        !          1605: }
        !          1606: 
        !          1607: 
        !          1608: 
        !          1609: /*
        !          1610: #
        !          1611: #% exchange fvp                L L L
        !          1612: #% exchange tvp                L L L
        !          1613: #
        !          1614:  vop_exchange {
        !          1615:      IN struct vnode *fvp;
        !          1616:      IN struct vnode *tvp;
        !          1617:      IN struct ucred *cred;
        !          1618:      IN struct proc *p;
        !          1619:  };
        !          1620: 
        !          1621:  */
        !          1622:  /*
        !          1623:   * exchange is a very tricky routine, because we might have to unlock the
        !          1624:   * passed in vnode, and then retry locking it and all its siblings, and then
        !          1625:   * unlocking them in reverse.
        !          1626:   * Also the sibling list lock must be kept during the whole operation to
        !          1627:   * make sure nothing changes underneath us.
        !          1628:   * Also it depends on behavior of the sibling list and hash, so
        !          1629:   * careful if you change anything.
        !          1630:   */
        !          1631:   
        !          1632: static int
        !          1633: hfs_exchange(ap)
        !          1634: struct vop_exchange_args /* {
        !          1635: struct vnode *a_fvp;
        !          1636: struct vnode *a_tvp;
        !          1637: struct ucred *a_cred;
        !          1638: struct proc *a_p;
        !          1639: } */ *ap;
        !          1640: {
        !          1641:        struct hfsnode *from_hp, *to_hp, *nhp;
        !          1642:        struct hfsnode *fromSkipIfFirst, *toSkipIfFirst;
        !          1643:        struct vnode *from_vp, *to_vp;
        !          1644:        struct hfsmount *hfsmp;
        !          1645:        u_char tmp_name[NAME_MAX+1];            /* 256 bytes! */
        !          1646:        ExtendedVCB *vcb;
        !          1647:        u_int32_t fromFileID, toFileID;
        !          1648:        u_int32_t fromParID;
        !          1649:        u_int32_t tmpLong;
        !          1650:        int retval = E_NONE;
        !          1651:        DBG_FUNC_NAME("exchange");
        !          1652:        DBG_VOP_LOCKS_DECL(2);
        !          1653:        DBG_VOP_PRINT_FUNCNAME();
        !          1654:        DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n"));
        !          1655:        DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n"));
        !          1656: 
        !          1657:        DBG_VOP_LOCKS_INIT(0,ap->a_fvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1658:        DBG_VOP_LOCKS_INIT(1,ap->a_tvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1659: 
        !          1660:        /* Set up variables and checks */
        !          1661:        from_vp         = ap->a_fvp;
        !          1662:     to_vp              = ap->a_tvp;
        !          1663:        from_hp         = VTOH(from_vp);
        !          1664:        to_hp           = VTOH(to_vp);
        !          1665:        hfsmp           = VTOHFS(from_vp);
        !          1666:        vcb                     = HTOVCB(from_hp);
        !          1667:        toFileID        = H_FILEID(to_hp);
        !          1668:        fromFileID      = H_FILEID(from_hp);
        !          1669:        fromParID       = H_DIRID(from_hp);
        !          1670: 
        !          1671:     if (from_vp->v_mount != to_vp->v_mount) {
        !          1672:                DBG_VOP_LOCKS_TEST(EXDEV);
        !          1673:                return EXDEV;
        !          1674:        }
        !          1675: 
        !          1676:        /* Can only exchange file objects */
        !          1677:     if (from_vp->v_type != VREG || to_vp->v_type != VREG) {
        !          1678:                DBG_VOP_LOCKS_TEST(EINVAL);
        !          1679:                return EINVAL;
        !          1680:        }
        !          1681: 
        !          1682:        /*
        !          1683:         * Lock the siblink list
        !          1684:         * Check for multiple forks
        !          1685:         * If there are, we would need to:
        !          1686:         * 1. Unlock ourselves
        !          1687:         * 3. Traverse the list in a forward order...locking all vnodes
        !          1688:         * 4. Flush all buffers
        !          1689:         * 5. Perform the exchange
        !          1690:         * 6. Traverse the list in a reverse order...unlocking all vnodes, except orignal
        !          1691:         * Notice that the sibling lock is kept during the whole operation. This quarentees
        !          1692:         * that no new forks are taken off or put on
        !          1693:         */
        !          1694:        DBG_ASSERT(H_FORKTYPE(from_hp)==kDataFork && H_FORKTYPE(to_hp)==kDataFork);     
        !          1695:        fromSkipIfFirst = toSkipIfFirst = NULL;
        !          1696:        simple_lock(&from_hp->h_meta->h_siblinglock);
        !          1697:        if (from_hp->h_meta->h_usecount > 1) {
        !          1698:                /*
        !          1699:                 * This has siblings, so remember the passed-in vnode,
        !          1700:                 * unlock it if it is not the 'first' sibling,
        !          1701:                 * and then lock the rest of the vnodes by sibling order.
        !          1702:                 * Notice that the passed-in vnode is not vrele(), this
        !          1703:                 * keeps the usecount>0, so it wont go away.
        !          1704:                 */
        !          1705:                if (from_hp->h_meta->h_siblinghead.cqh_first == from_hp) {
        !          1706:                fromSkipIfFirst = from_hp;
        !          1707:                        nhp = from_hp->h_sibling.cqe_next;
        !          1708:        }
        !          1709:        else {
        !          1710:                VOP_UNLOCK(from_vp, 0, ap->a_p);
        !          1711:                        nhp = from_hp->h_meta->h_siblinghead.cqh_first;
        !          1712:         };
        !          1713: 
        !          1714:                for (; nhp != (void *)&from_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
        !          1715:                        
        !          1716:                if (vget(HTOV(nhp), LK_EXCLUSIVE | LK_RETRY, ap->a_p))
        !          1717:                                continue;               /* skip it, this shouldnt happen */
        !          1718: 
        !          1719:                        /* Ignore any errors, we are doing a 'best effort' on flushing */
        !          1720:                        (void) vinvalbuf(HTOV(nhp), V_SAVE, ap->a_cred, ap->a_p, 0, 0);
        !          1721:                };
        !          1722:        };
        !          1723: 
        !          1724:        simple_lock(&to_hp->h_meta->h_siblinglock);
        !          1725:     if (to_hp->h_meta->h_usecount > 1) {
        !          1726: 
        !          1727:                if (to_hp->h_meta->h_siblinghead.cqh_first == to_hp) {
        !          1728:                toSkipIfFirst = to_hp;
        !          1729:             nhp = to_hp->h_sibling.cqe_next;
        !          1730:        }
        !          1731:        else {
        !          1732:             VOP_UNLOCK(to_vp, 0, ap->a_p);
        !          1733:             nhp = to_hp->h_meta->h_siblinghead.cqh_first;
        !          1734:         };
        !          1735: 
        !          1736: 
        !          1737:         for (; nhp != (void *)&to_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
        !          1738: 
        !          1739: 
        !          1740:             if (vget(HTOV(nhp), LK_EXCLUSIVE | LK_RETRY, ap->a_p))
        !          1741:                 continue;              /* skip it, this shouldnt happen */
        !          1742: 
        !          1743:             /* Ignore any errors, we are doing a 'best effort' on flushing */
        !          1744:             (void) vinvalbuf(HTOV(nhp), V_SAVE, ap->a_cred, ap->a_p, 0, 0);
        !          1745:             };
        !          1746:         };
        !          1747: 
        !          1748:        /* lock catalog b-tree */
        !          1749:        retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p);
        !          1750:        if (retval) goto Err_Exit;
        !          1751: 
        !          1752:        /* lock extents b-tree iff there are overflow extents */
        !          1753:        /* XXX SER ExchangeFileIDs() always tries to delete the virtual extent id for exchanging files
        !          1754:                so we neeed the tree to be always locked.
        !          1755:        */
        !          1756:        retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
        !          1757:        if (retval) goto Err_Exit_Relse;
        !          1758: 
        !          1759:        /* Do the exchange */
        !          1760:        retval = MacToVFSError( ExchangeFileIDs(vcb, H_NAME(from_hp), H_NAME(to_hp), H_DIRID(from_hp), H_DIRID(to_hp), H_HINT(from_hp), H_HINT(to_hp) ));
        !          1761: 
        !          1762:        (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, ap->a_p);
        !          1763: 
        !          1764:        if (retval != E_NONE) {
        !          1765:                DBG_ERR(("/tError trying to exchange: %d\n", retval));
        !          1766:                goto Err_Exit_Relse;
        !          1767:        }
        !          1768: 
        !          1769:        
        !          1770:        /* Now exchange fileID, parID, name for the vnode itself */
        !          1771:        copystr(H_NAME(from_hp), (char*) tmp_name, strlen(H_NAME(from_hp))+1, NULL);
        !          1772:        hfs_chid(from_hp, toFileID, H_DIRID(to_hp), H_NAME(to_hp));
        !          1773:        hfs_chid(to_hp, fromFileID, fromParID, (char*) tmp_name);
        !          1774:        
        !          1775:        /* copy rest */
        !          1776:        tmpLong = HTOFCB(from_hp)->fcbFlags;
        !          1777:        HTOFCB(from_hp)->fcbFlags = HTOFCB(to_hp)->fcbFlags;
        !          1778:        HTOFCB(to_hp)->fcbFlags = tmpLong;
        !          1779: 
        !          1780:        tmpLong = from_hp->h_meta->h_crtime;
        !          1781:        from_hp->h_meta->h_crtime = to_hp->h_meta->h_crtime;
        !          1782:        to_hp->h_meta->h_crtime = tmpLong;
        !          1783: 
        !          1784:        tmpLong = from_hp->h_meta->h_butime;
        !          1785:        from_hp->h_meta->h_butime = to_hp->h_meta->h_butime;
        !          1786:        to_hp->h_meta->h_butime = tmpLong;
        !          1787: 
        !          1788:        tmpLong = from_hp->h_meta->h_atime;
        !          1789:        from_hp->h_meta->h_atime = to_hp->h_meta->h_atime;
        !          1790:        to_hp->h_meta->h_atime = tmpLong;
        !          1791: 
        !          1792:        tmpLong = from_hp->h_meta->h_ctime;
        !          1793:        from_hp->h_meta->h_ctime = to_hp->h_meta->h_ctime;
        !          1794:        to_hp->h_meta->h_ctime = tmpLong;
        !          1795: 
        !          1796: 
        !          1797:        tmpLong = from_hp->h_meta->h_gid;
        !          1798:        from_hp->h_meta->h_gid = to_hp->h_meta->h_gid;
        !          1799:        to_hp->h_meta->h_gid = tmpLong;
        !          1800: 
        !          1801:        tmpLong = from_hp->h_meta->h_uid;
        !          1802:        from_hp->h_meta->h_uid = to_hp->h_meta->h_uid;
        !          1803:        to_hp->h_meta->h_uid = tmpLong;
        !          1804: 
        !          1805:        tmpLong = from_hp->h_meta->h_pflags; 
        !          1806:        from_hp->h_meta->h_pflags = to_hp->h_meta->h_pflags;
        !          1807:        to_hp->h_meta->h_pflags = tmpLong;
        !          1808: 
        !          1809:        tmpLong = from_hp->h_meta->h_mode;      
        !          1810:        from_hp->h_meta->h_mode = to_hp->h_meta->h_mode;
        !          1811:        to_hp->h_meta->h_mode = tmpLong;
        !          1812: 
        !          1813:        tmpLong = from_hp->h_meta->h_rdev;      
        !          1814:        from_hp->h_meta->h_rdev = to_hp->h_meta->h_rdev;
        !          1815:        to_hp->h_meta->h_rdev = tmpLong;
        !          1816: 
        !          1817:        tmpLong = from_hp->h_meta->h_size;      
        !          1818:        from_hp->h_meta->h_size = to_hp->h_meta->h_size;
        !          1819:        to_hp->h_meta->h_size = tmpLong;
        !          1820: 
        !          1821:        
        !          1822: 
        !          1823: Err_Exit_Relse:;
        !          1824: 
        !          1825:        /* unlock catalog b-tree */
        !          1826:        (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p);
        !          1827: 
        !          1828: 
        !          1829: 
        !          1830: Err_Exit:;
        !          1831: 
        !          1832:        /* Unlock any forks, and the sibling list */
        !          1833:     if (to_hp->h_meta->h_usecount > 1) {
        !          1834:         for (nhp = to_hp->h_meta->h_siblinghead.cqh_last;
        !          1835:                nhp != (void *)&to_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_prev) {
        !          1836:             if (toSkipIfFirst && (nhp == toSkipIfFirst))
        !          1837:                 continue;
        !          1838:             else if (HTOV(nhp)==to_vp)
        !          1839:                 VRELE(HTOV(nhp));              /* decrement,  return it locked */
        !          1840:             /*
        !          1841:              * A gotcha here, is that when locking, it might of failed
        !          1842:              * because the vnode was going away. Since vput() does not test for this,
        !          1843:              * we have to do this ourselves....but using the VXLOCK is bad, because
        !          1844:              * it should be private to vfs routines...but until another way is thought of...
        !          1845:              */
        !          1846:             else if (!(HTOV(nhp)->v_flag & VXLOCK)) {
        !          1847:                 cache_purge(HTOV(nhp));
        !          1848:                 VPUT(HTOV(nhp));
        !          1849:                 };
        !          1850:             };
        !          1851:         };
        !          1852:        
        !          1853:        simple_unlock(&to_hp->h_meta->h_siblinglock);
        !          1854:                
        !          1855:        if (from_hp->h_meta->h_usecount > 1) {
        !          1856:                for (nhp = from_hp->h_meta->h_siblinghead.cqh_last; 
        !          1857:                                        nhp != (void *)&from_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_prev) {
        !          1858:                if (fromSkipIfFirst && (nhp == fromSkipIfFirst))
        !          1859:                        continue;
        !          1860:                else if (HTOV(nhp)==from_vp)
        !          1861:                                VRELE(HTOV(nhp));               /* decrement,  return it locked */
        !          1862:             else if (!(HTOV(nhp)->v_flag & VXLOCK)){
        !          1863:                 cache_purge(HTOV(nhp));
        !          1864:                        VPUT(HTOV(nhp));
        !          1865:             };
        !          1866:                };
        !          1867:        };
        !          1868: 
        !          1869:        simple_unlock(&from_hp->h_meta->h_siblinglock);
        !          1870: 
        !          1871:     /* Purge the vnodes from the namei...the names do not match vnodes now */
        !          1872:     cache_purge(from_vp);
        !          1873:     cache_purge(to_vp);
        !          1874:        
        !          1875:        /* XXX SER
        !          1876:         * At this point, the vnodes' data is switched, but are on the old hash list.
        !          1877:         * so move them to the right bucket. This couldnt be done until now, because the h_siblinglock
        !          1878:         * was being held.
        !          1879:         * Scenario:
        !          1880:         * A fork is trying to be added while exchanging...It got the hash lock,
        !          1881:         * but is waiting for the h_siblinglock. So we cannot try get the hash lock
        !          1882:         * until we release h_siblinglock, so it could continue, so it adds to the sibling list
        !          1883:         * and at the old place, so hfs_vhashmove has to move all vnodes with the old file id.
        !          1884:         * Not very pretty, becarefull that this works ok
        !          1885:         * Scenario 2:
        !          1886:         * Same as the above, but before the move is made (like at this very spot), the new vnode
        !          1887:         * is added and a vget is requested for that new vnode, it would have old data
        !          1888:         *      WE MIGHT NEED TO LOCK THE HASH BECAUSE OF THIS !!!
        !          1889:         * Scenario 3:
        !          1890:         * Hey! Same as above, but it is added after all the moving
        !          1891:         * So now there is a vnode with the old data, on the old hash...it will become
        !          1892:         * lost next time that a vget()  is done
        !          1893:         *
        !          1894:         * XXX SER A solution might be to NOT move the hash, but the data (extents) or the
        !          1895:         * opposite that we are doing now
        !          1896:         */
        !          1897:        hfs_vhashmove(from_hp, fromFileID);
        !          1898:        hfs_vhashmove(to_hp, toFileID);
        !          1899: 
        !          1900:        DBG_VOP_LOCKS_TEST(retval);
        !          1901:        return (retval);
        !          1902: }
        !          1903: 
        !          1904: 
        !          1905: /*
        !          1906:  * Change a vnode's file id, parent id and name
        !          1907:  * 
        !          1908:  * Assumes the vnode is locked and is of type VREG
        !          1909:  */
        !          1910: static void
        !          1911: hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name)
        !          1912: {
        !          1913:        DBG_ASSERT(HTOV(hp)->v_type == VREG);
        !          1914: 
        !          1915:        H_HINT(hp) = 0;
        !          1916:        H_FILEID(hp) = fid;                                     /* change h_nodeID */
        !          1917:        H_DIRID(hp) = pid;
        !          1918:        
        !          1919:        hfs_set_metaname(name, hp->h_meta);
        !          1920: 
        !          1921: 
        !          1922: }
        !          1923: 
        !          1924: 
        !          1925: /*
        !          1926: 
        !          1927: #% fsync       vp      L L L
        !          1928: #
        !          1929:  vop_fsync {
        !          1930:      IN struct vnode *vp;
        !          1931:      IN struct ucred *cred;
        !          1932:      IN int waitfor;
        !          1933:      IN struct proc *p;
        !          1934: 
        !          1935:      */
        !          1936: 
        !          1937: 
        !          1938: static int
        !          1939: hfs_fsync(ap)
        !          1940: struct vop_fsync_args /* {
        !          1941:     struct vnode *a_vp;
        !          1942:     struct ucred *a_cred;
        !          1943:     int a_waitfor;
        !          1944:     struct proc *a_p;
        !          1945: } */ *ap;
        !          1946: {
        !          1947:     struct vnode               *vp = ap->a_vp ;
        !          1948:     struct hfsnode             *hp     = VTOH(vp);
        !          1949:     int                                        retval = 0;
        !          1950:     register struct buf *bp;
        !          1951:     struct timeval             tv;
        !          1952:     struct buf                         *nbp;
        !          1953:     int                                s;
        !          1954: 
        !          1955:     DBG_FUNC_NAME("fsync");
        !          1956:     DBG_VOP_LOCKS_DECL(1);
        !          1957:     DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("  "));
        !          1958:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          1959:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
        !          1960:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !          1961:        
        !          1962: #if HFS_DIAGNOSTIC
        !          1963:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
        !          1964: #endif
        !          1965: 
        !          1966: 
        !          1967:     /*
        !          1968:      * First of all, write out any clusters.
        !          1969:      */
        !          1970:     if (doclusterwrite) {
        !          1971:         long devBlockSize = 0;
        !          1972: 
        !          1973:                VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize);
        !          1974:                cluster_close(vp, PAGE_SIZE, devBlockSize);
        !          1975:     };
        !          1976: 
        !          1977:     /*
        !          1978:      * Flush all dirty buffers associated with a vnode.
        !          1979:      */
        !          1980: loop:
        !          1981:     s = splbio();
        !          1982:     for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
        !          1983:         nbp = bp->b_vnbufs.le_next;
        !          1984:         if ((bp->b_flags & B_BUSY))
        !          1985:             continue;
        !          1986:         if ((bp->b_flags & B_DELWRI) == 0)
        !          1987:             panic("hfs_fsync: not dirty");
        !          1988:         bremfree(bp);
        !          1989:         bp->b_flags |= B_BUSY;
        !          1990:         bp->b_flags &= ~B_LOCKED;      /* Clear flag, should only be set on meta files */
        !          1991:         splx(s);
        !          1992:         /*
        !          1993:          * Wait for I/O associated with indirect blocks to complete,
        !          1994:          * since there is no way to quickly wait for them below.
        !          1995:          */
        !          1996:         DBG_VOP(("\t\t\tFlushing out phys block %d == log block %d\n", bp->b_blkno, bp->b_lblkno));
        !          1997:         if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) {
        !          1998:             (void) bawrite(bp);
        !          1999:         } else {
        !          2000:             (void) bwrite(bp);
        !          2001:        }
        !          2002:         goto loop;
        !          2003:     }
        !          2004: 
        !          2005:     if (ap->a_waitfor == MNT_WAIT) {
        !          2006:         while (vp->v_numoutput) {
        !          2007:             vp->v_flag |= VBWAIT;
        !          2008:             tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0);
        !          2009:         }
        !          2010: 
        !          2011:         /* I have seen this happen for swapfile. So it is safer to
        !          2012:          * check for dirty buffers again.  --Umesh
        !          2013:          */
        !          2014:         if (vp->v_dirtyblkhd.lh_first) {
        !          2015:             vprint("hfs_fsync: dirty", vp);
        !          2016:             splx(s);
        !          2017:             goto loop;
        !          2018:         }
        !          2019:     }
        !          2020:     splx(s);
        !          2021: 
        !          2022: #if HFS_DIAGNOSTIC
        !          2023:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
        !          2024: #endif
        !          2025: 
        !          2026:        tv = time;
        !          2027:        if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL))
        !          2028:                BTSetLastSync(HTOFCB(hp), tv.tv_sec);
        !          2029: 
        !          2030:        if (H_FORKTYPE(hp) != kSysFile) {
        !          2031:        retval = VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT);
        !          2032: 
        !          2033:        if (retval != E_NONE) {
        !          2034:                DBG_ERR(("%s: FLUSH FAILED: %s\n", funcname, H_NAME(hp)));
        !          2035:        }
        !          2036:     }
        !          2037:        else
        !          2038:                hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          2039: 
        !          2040:     if (ap->a_waitfor == MNT_WAIT) {
        !          2041:       DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL);
        !          2042:     };
        !          2043:     DBG_VOP_LOCKS_TEST(retval);
        !          2044:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
        !          2045:     return (retval);
        !          2046: }
        !          2047: 
        !          2048: 
        !          2049: int
        !          2050: hfs_fsync_transaction(struct vnode *vp)
        !          2051: {
        !          2052:     struct hfsnode             *hp = VTOH(vp);
        !          2053:     register struct buf         *bp;
        !          2054:     struct timeval             tv;
        !          2055:     struct buf                         *nbp;
        !          2056:     int                        s;
        !          2057: 
        !          2058:     /*
        !          2059:      * Flush all dirty buffers associated with a vnode.
        !          2060:      */
        !          2061: loop:
        !          2062:     s = splbio();
        !          2063: 
        !          2064:     for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
        !          2065:         nbp = bp->b_vnbufs.le_next;
        !          2066:         if ((bp->b_flags & B_BUSY))
        !          2067:             continue;
        !          2068:         if ((bp->b_flags & B_DELWRI) == 0)
        !          2069:             panic("hfs_fsync: not dirty");
        !          2070:        if ( !(bp->b_flags & B_LOCKED))
        !          2071:            continue;
        !          2072: 
        !          2073:         bremfree(bp);
        !          2074:         bp->b_flags |= B_BUSY;
        !          2075:         bp->b_flags &= ~B_LOCKED;      /* Clear flag, should only be set on meta files */
        !          2076:         splx(s);
        !          2077: 
        !          2078:        (void) bawrite(bp);
        !          2079: 
        !          2080:         goto loop;
        !          2081:     }
        !          2082:     splx(s);
        !          2083: 
        !          2084:     tv = time;
        !          2085:        if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL))
        !          2086:                (void) BTSetLastSync(VTOFCB(vp), tv.tv_sec);
        !          2087:     hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          2088: 
        !          2089:     return 0;
        !          2090: }
        !          2091: 
        !          2092: /*
        !          2093: 
        !          2094: #% remove      dvp     L U U
        !          2095: #% remove      vp      L U U
        !          2096: #
        !          2097:  vop_remove {
        !          2098:      IN WILLRELE struct vnode *dvp;
        !          2099:      IN WILLRELE struct vnode *vp;
        !          2100:      IN struct componentname *cnp;
        !          2101: 
        !          2102:      */
        !          2103: 
        !          2104: int
        !          2105: hfs_remove(ap)
        !          2106: struct vop_remove_args /* {
        !          2107:     struct vnode *a_dvp;
        !          2108:     struct vnode *a_vp;
        !          2109:     struct componentname *a_cnp;
        !          2110: } */ *ap;
        !          2111: {
        !          2112:        struct vnode *vp = ap->a_vp;
        !          2113:        struct vnode *dvp = ap->a_dvp;
        !          2114:        struct hfsnode *hp = VTOH(ap->a_vp);
        !          2115:        struct hfsmount *hfsmp = HTOHFS(hp);
        !          2116:        struct proc *p = current_proc();
        !          2117:        struct timeval tv;
        !          2118:        int retval, use_count, hasSiblings;
        !          2119:        int filebusy = 0;
        !          2120:        DBG_FUNC_NAME("remove");
        !          2121:        DBG_VOP_LOCKS_DECL(2);
        !          2122:        DBG_VOP_PRINT_FUNCNAME();
        !          2123:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
        !          2124:        DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
        !          2125:        DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2126:        DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2127: 
        !          2128:        hasSiblings = false;
        !          2129:        retval = E_NONE;
        !          2130: 
        !          2131:        if ((hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
        !          2132:                (VTOH(dvp)->h_meta->h_pflags & APPEND)) {
        !          2133:                retval = EPERM;
        !          2134:                        goto out;
        !          2135:        }
        !          2136: 
        !          2137:     if (vp->v_usecount > 1) {
        !          2138:        /* Mac OS clients can't delete busy files */
        !          2139:                if ((ap->a_cnp->cn_flags & NODELETEBUSY) || (hfsmp->hfs_private_metadata_dir == 0)) {
        !          2140:                        retval = EBUSY;
        !          2141:                        goto out;
        !          2142:         } else
        !          2143:                filebusy = 1;
        !          2144:     }
        !          2145:        
        !          2146:        tv = time;                                      /* Done here, so all times are the same */
        !          2147:        
        !          2148:        /* Check other siblings for in use also */
        !          2149:        /* XXX SER MUST BE CHANGED BY MACOS X because of vnode_uncache */
        !          2150:        /* Uncache everything and make sure no other usecount */
        !          2151:        /*
        !          2152:         * a. loop through the siblings looking for matches
        !          2153:         * b. If we find ourselves...skip it
        !          2154:         * If there was a sibling:
        !          2155:         * a. Check for a positve usecount
        !          2156:         * b. uncache any pages
        !          2157:         * c. Write out and memory changes
        !          2158:         * The idea is to keep the h_siblinglock as little as possible
        !          2159:         */
        !          2160:        if (hp->h_meta->h_siblinghead.cqh_first && (hp->h_meta->h_siblinghead.cqh_first != hp->h_meta->h_siblinghead.cqh_last)) {
        !          2161:                simple_lock(&hp->h_meta->h_siblinglock);
        !          2162:                hasSiblings = true;
        !          2163:        }
        !          2164: 
        !          2165:        if (hasSiblings) {
        !          2166:                struct vnode *tvp;
        !          2167:                struct hfsnode *nhp;
        !          2168:                
        !          2169:                DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork);
        !          2170:                /* Lock the sibling list, this ensures no entry leaves or is added unexpectanly */
        !          2171:                
        !          2172:                /* Loop through all siblings, skipping ourselves */
        !          2173:                for (nhp = hp->h_meta->h_siblinghead.cqh_first; nhp != (void *)&hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
        !          2174:                        if (nhp == hp)          /* skip ourselves */
        !          2175:                                continue;
        !          2176:                        tvp = HTOV(nhp);
        !          2177:                
        !          2178:                        /* Check to see if other forks are in use */
        !          2179:                        simple_lock(&tvp->v_interlock);
        !          2180:                        use_count = tvp->v_usecount;    
        !          2181:                        simple_unlock(&tvp->v_interlock);
        !          2182:                        if (use_count > 0) {
        !          2183:                                if (ap->a_cnp->cn_flags & NODELETEBUSY || hfsmp->hfs_private_metadata_dir == 0) {
        !          2184:                                        retval = EBUSY;
        !          2185:                                        break;
        !          2186:                                        }
        !          2187:                                else
        !          2188:                                        filebusy = 1;
        !          2189:                        };
        !          2190:        
        !          2191:                        /* Get a lock, for the rest */
        !          2192:                        /* The only error that vget returns is when the vnode is going away, so ignore it */
        !          2193:                if (vget(tvp, LK_EXCLUSIVE | LK_RETRY, p))
        !          2194:                        continue;
        !          2195:                
        !          2196:                        /*
        !          2197:                         * XXX SER vnode_uncache() unlocks the vnode and the wait
        !          2198:                         * to regain the lock. VERY BAD. This behavior should be changed in
        !          2199:                         * the future.
        !          2200:                         * See the comment in vnode_uncache()
        !          2201:                         */
        !          2202:                        (void) vnode_uncache(tvp);
        !          2203:                        
        !          2204:                        /* 
        !          2205:                         * Should be relocked at this point..now flush out the memory
        !          2206:                         * XXX SER An intelligient person would ask, why flush out changes
        !          2207:                         * that are going to be deleted? See the next comment.
        !          2208:                         */
        !          2209:                        if ((nhp->h_nodeflags & IN_MODIFIED) || (VTOFCB(tvp)->fcbFlags & fcbModifiedMask))
        !          2210:                                {
        !          2211:                                DBG_ASSERT((VTOH(tvp)->h_nodeflags & IN_MODIFIED) != 0);
        !          2212:                                VOP_UPDATE(tvp, &tv, &tv, 0);
        !          2213:                        };
        !          2214: 
        !          2215:                        VPUT(tvp);
        !          2216: 
        !          2217:                };
        !          2218:                
        !          2219:                simple_unlock(&hp->h_meta->h_siblinglock);
        !          2220:                
        !          2221:                if (retval)
        !          2222:                        goto out;               
        !          2223: 
        !          2224:        };
        !          2225: 
        !          2226:     /* 
        !          2227:         * remove the entry from the namei cache: 
        !          2228:      * We do it early before any linking/busy file wierdness, make sure the 
        !          2229:         * original is gone
        !          2230:         */
        !          2231:     cache_purge(vp);
        !          2232: 
        !          2233:        /* Flush out any catalog changes */
        !          2234:        /* XXX SER: This is a hack, becasue hfsDelete reads the data from the disk
        !          2235:         * and not from memory which is more correct
        !          2236:         */
        !          2237:        if ((hp->h_nodeflags & IN_MODIFIED) || (HTOFCB(hp)->fcbFlags & fcbModifiedMask))
        !          2238:                {
        !          2239:                DBG_ASSERT((hp->h_nodeflags & IN_MODIFIED) != 0);
        !          2240:                VOP_UPDATE(vp, &tv, &tv, 0);
        !          2241:                }
        !          2242: 
        !          2243:        /* lock catalog b-tree */
        !          2244:        retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          2245:        if (retval != E_NONE) {
        !          2246:                retval = EBUSY;
        !          2247:                goto out;
        !          2248:        }
        !          2249: 
        !          2250: 
        !          2251: #if HFS_HARDLINKS
        !          2252:        /*
        !          2253:         * Multi-linked files just need their link node deleted from the catalog
        !          2254:         */
        !          2255:        if (hp->h_meta->h_metaflags & IN_DATANODE) {
        !          2256: 
        !          2257:                if ((ap->a_cnp->cn_flags & HASBUF) == 0 ||
        !          2258:                        ap->a_cnp->cn_nameptr[0] == '\0') {
        !          2259:                        retval = ENOENT;        /* name missing */
        !          2260:                        goto out2;
        !          2261:                }
        !          2262: 
        !          2263:         /* lock extents b-tree (also protects volume bitmap) */
        !          2264:         retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
        !          2265:         if (retval != E_NONE) {
        !          2266:             retval = EBUSY;
        !          2267:             goto out2;                                         /* unlock catalog b-tree on the way out */
        !          2268:         }
        !          2269: 
        !          2270:                retval = hfsDelete (HTOVCB(hp), H_FILEID(VTOH(dvp)),
        !          2271:                            ap->a_cnp->cn_nameptr, TRUE, H_HINT(hp));
        !          2272: 
        !          2273:         (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
        !          2274: 
        !          2275:                if (retval != 0)
        !          2276:                        goto out2;
        !          2277: 
        !          2278:                hp->h_nodeflags |= IN_CHANGE;
        !          2279:                if (--hp->h_meta->h_nlink < 1)
        !          2280:                        hp->h_meta->h_metaflags |= IN_DELETED;
        !          2281:                
        !          2282:                /* name and parent fields are no longer valid so invalidate them */
        !          2283:                H_DIRID(hp) = kUnknownID;
        !          2284:                hfs_set_metaname("\0", hp->h_meta);
        !          2285: 
        !          2286:                if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME))
        !          2287:                        FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
        !          2288: 
        !          2289:                goto out2;      /* link deleted, all done */
        !          2290:        }
        !          2291: #endif
        !          2292: 
        !          2293:        /*
        !          2294:         * To make the HFS filesystem follow UFS unlink semantics, a remove of
        !          2295:         * an active vnode is translated to a move/rename so the file appears
        !          2296:         * deleted. Later, the file is removed by hfs_inactive on the hfsnode.
        !          2297:         */
        !          2298:        if (filebusy) {
        !          2299:                UInt32 hint = H_HINT(hp);
        !          2300:                char nodeName[32];
        !          2301:                
        !          2302:                MAKE_DELETED_NAME(nodeName, H_FILEID(hp));
        !          2303:                
        !          2304:                retval = hfsMoveRename (HTOVCB(hp), H_DIRID(hp), H_NAME(hp),
        !          2305:                                        hfsmp->hfs_private_metadata_dir, nodeName, &hint);
        !          2306:                if (retval) goto out2;
        !          2307:        
        !          2308:                hp->h_meta->h_metaflags |= IN_DELETED;
        !          2309:                hp->h_nodeflags |= IN_CHANGE;
        !          2310: 
        !          2311:                /* update name so Catalog lookups succeed */
        !          2312:                H_HINT(hp) = hint;
        !          2313:                H_DIRID(hp) = hfsmp->hfs_private_metadata_dir;
        !          2314:                hfs_set_metaname(nodeName, hp->h_meta);
        !          2315: 
        !          2316:                goto out2;      /* all done, unlock the catalog */
        !          2317:        }
        !          2318: 
        !          2319:        /* Invalidate the buffers */
        !          2320:        if ((retval= vinvalbuf(vp, 0, NOCRED, p, 0, 0)))
        !          2321:                goto out2;
        !          2322:        
        !          2323:        /* lock extents b-tree (also protects volume bitmap) */
        !          2324:        retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
        !          2325:        if (retval != E_NONE) {
        !          2326:                retval = EBUSY;
        !          2327:                goto out2;                                              /* unlock catalog b-tree on the way out */
        !          2328:        }
        !          2329: 
        !          2330:        /* remove entry from catalog and free any blocks used */
        !          2331:        retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp));
        !          2332: 
        !          2333:        /* Clean up */
        !          2334:        (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
        !          2335:        
        !          2336:        hp->h_meta->h_mode = 0;                         /* Makes the node go away...see inactive */
        !          2337:        /* XXX SER Anything else so that sibling, if any, goes away */
        !          2338: 
        !          2339: out2:
        !          2340:        (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
        !          2341: 
        !          2342: out:;
        !          2343: 
        !          2344:        if (! retval)
        !          2345:                VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          2346: 
        !          2347:        if (dvp == vp) {
        !          2348:                VRELE(vp);
        !          2349:        } else {
        !          2350:                VPUT(vp);
        !          2351:        };
        !          2352: 
        !          2353:        VPUT(dvp);
        !          2354:        DBG_VOP_LOCKS_TEST(retval);
        !          2355:        return (retval);
        !          2356: }
        !          2357: 
        !          2358: 
        !          2359: /*
        !          2360: 
        !          2361: #% rename      sourcePar_vp    U U U
        !          2362: #% rename      source_vp               U U U
        !          2363: #% rename      targetPar_vp    L U U
        !          2364: #% rename      target_vp               X U U
        !          2365: #
        !          2366:  vop_rename {
        !          2367:      IN WILLRELE struct vnode *sourcePar_vp;
        !          2368:      IN WILLRELE struct vnode *source_vp;
        !          2369:      IN struct componentname *source_cnp;
        !          2370:      IN WILLRELE struct vnode *targetPar_vp;
        !          2371:      IN WILLRELE struct vnode *target_vp;
        !          2372:      IN struct componentname *target_cnp;
        !          2373: 
        !          2374: 
        !          2375:      */
        !          2376: /*
        !          2377: * On entry:
        !          2378: *      source's parent directory is unlocked
        !          2379: *      source file or directory is unlocked
        !          2380: *      destination's parent directory is locked
        !          2381: *      destination file or directory is locked if it exists
        !          2382: *
        !          2383: * On exit:
        !          2384: *      all denodes should be released
        !          2385: *
        !          2386: */
        !          2387: 
        !          2388: static int
        !          2389: hfs_rename(ap)
        !          2390: struct vop_rename_args  /* {
        !          2391:     struct vnode *a_fdvp;
        !          2392:     struct vnode *a_fvp;
        !          2393:     struct componentname *a_fcnp;
        !          2394:     struct vnode *a_tdvp;
        !          2395:     struct vnode *a_tvp;
        !          2396:     struct componentname *a_tcnp;
        !          2397: } */ *ap;
        !          2398: {
        !          2399:        struct vnode                    *target_vp = ap->a_tvp;
        !          2400:        struct vnode                    *targetPar_vp = ap->a_tdvp;
        !          2401:        struct vnode                    *source_vp = ap->a_fvp;
        !          2402:        struct vnode                    *sourcePar_vp = ap->a_fdvp;
        !          2403:        struct componentname    *target_cnp = ap->a_tcnp;
        !          2404:        struct componentname    *source_cnp = ap->a_fcnp;
        !          2405:        struct proc                             *p = source_cnp->cn_proc;
        !          2406:        struct hfsnode                  *target_hp, *targetPar_hp, *source_hp, *sourcePar_hp;
        !          2407:        u_short                                 doingdirectory = 0, oldparent = 0, newparent = 0;
        !          2408:        int                                             retval = 0;
        !          2409:        struct timeval                  tv;
        !          2410:        struct hfsCatalogInfo catInfo;
        !          2411:        DBG_VOP_LOCKS_DECL(4);
        !          2412: 
        !          2413:     DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
        !          2414:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Source:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n"));
        !          2415:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourcePar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_fdvp);DBG_VOP_CONT(("\n"));
        !          2416:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Target:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n"));
        !          2417:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetPar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_tdvp);DBG_VOP_CONT(("\n"));
        !          2418:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourceName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_fcnp);DBG_VOP_CONT(("\n"));
        !          2419:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_tcnp);DBG_VOP_CONT(("\n"));
        !          2420:     DBG_VOP_LOCKS_INIT(0,ap->a_fdvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2421:     DBG_VOP_LOCKS_INIT(1,ap->a_fvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2422:     DBG_VOP_LOCKS_INIT(2,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2423:     DBG_VOP_LOCKS_INIT(3,ap->a_tvp, VOPDBG_LOCKNOTNIL, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2424:     WRITE_CK(ap->a_fdvp, funcname);
        !          2425:     DBG_HFS_NODE_CHECK(ap->a_fdvp);
        !          2426:     DBG_HFS_NODE_CHECK(ap->a_tdvp);
        !          2427: 
        !          2428: #if HFS_DIAGNOSTIC
        !          2429:     if ((target_cnp->cn_flags & HASBUF) == 0 ||
        !          2430:         (source_cnp->cn_flags & HASBUF) == 0)
        !          2431:         panic("hfs_rename: no name");
        !          2432: #endif
        !          2433: 
        !          2434:        DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
        !          2435:        target_hp = targetPar_hp = source_hp = sourcePar_hp = 0;
        !          2436: 
        !          2437:        /*
        !          2438:         * Check for cross-device rename.
        !          2439:         */
        !          2440:        if ((source_vp->v_mount != targetPar_vp->v_mount) ||
        !          2441:                (target_vp && (source_vp->v_mount != target_vp->v_mount))) {
        !          2442:                retval = EXDEV;
        !          2443:                goto abortit;
        !          2444:        }
        !          2445: 
        !          2446:        /*
        !          2447:         * Check for access permissions
        !          2448:         */
        !          2449:        if (target_vp && ((VTOH(target_vp)->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
        !          2450:                                          (VTOH(targetPar_vp)->h_meta->h_pflags & APPEND))) {
        !          2451:                retval = EPERM;
        !          2452:                goto abortit;
        !          2453:        }
        !          2454: 
        !          2455:        if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p)))
        !          2456:                goto abortit;
        !          2457: 
        !          2458:        sourcePar_hp = VTOH(sourcePar_vp);
        !          2459:        source_hp = VTOH(source_vp);
        !          2460:        oldparent = H_FILEID(sourcePar_hp);
        !          2461:        if ((source_hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || (sourcePar_hp->h_meta->h_pflags & APPEND)) {
        !          2462:                VOP_UNLOCK(source_vp, 0, p);
        !          2463:                retval = EPERM;
        !          2464:                goto abortit;
        !          2465:        }
        !          2466: 
        !          2467:        /*
        !          2468:         * Be sure we are not renaming ".", "..", or an alias of ".". This
        !          2469:         * leads to a crippled directory tree.  It's pretty tough to do a
        !          2470:         * "ls" or "pwd" with the "." directory entry missing, and "cd .."
        !          2471:         * doesn't work if the ".." entry is missing.
        !          2472:         */
        !          2473:        if ((source_hp->h_meta->h_mode & IFMT) == IFDIR) {
        !          2474:                if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.')
        !          2475:                        || sourcePar_hp == source_hp
        !          2476:                        || (source_cnp->cn_flags&ISDOTDOT)
        !          2477:                        || (source_hp->h_nodeflags & IN_RENAME)) {
        !          2478:                        VOP_UNLOCK(source_vp, 0, p);
        !          2479:                        retval = EINVAL;
        !          2480:                        goto abortit;
        !          2481:                }
        !          2482:                source_hp->h_nodeflags |= IN_RENAME;
        !          2483:                doingdirectory = TRUE;
        !          2484:        }
        !          2485: 
        !          2486:     /*
        !          2487:      *
        !          2488:      * >>>> Transit between abort and bad <<<<
        !          2489:      *
        !          2490:      */
        !          2491: 
        !          2492:     targetPar_hp = VTOH(targetPar_vp);
        !          2493:     if (target_vp)
        !          2494:        target_hp = VTOH(target_vp);
        !          2495:     else
        !          2496:        DBG_ASSERT(target_hp == NULL);
        !          2497: 
        !          2498:     newparent = H_FILEID(targetPar_hp);
        !          2499: 
        !          2500:        /* Test to make sure we are not crossing devices */
        !          2501:        /* XXX SER Is this necesary, does catalog manager take care of this? */
        !          2502:        if (target_vp) {
        !          2503:                if (H_DEV(target_hp) != H_DEV(targetPar_hp) || H_DEV(target_hp) != H_DEV(source_hp))
        !          2504:                        panic("rename: EXDEV");
        !          2505:        }
        !          2506:         else {
        !          2507:                if (H_DEV(targetPar_hp) != H_DEV(source_hp))
        !          2508:                        panic("rename: EXDEV");
        !          2509:        };
        !          2510:        
        !          2511:     retval = VOP_ACCESS(source_vp, VWRITE, target_cnp->cn_cred, target_cnp->cn_proc);
        !          2512:     if (doingdirectory && (newparent != oldparent)) {
        !          2513:         if (retval)            /* write access check above */
        !          2514:             goto bad;
        !          2515:     }
        !          2516:        retval = 0;             /* Reset value from above, we dont care about it anymore */
        !          2517:        
        !          2518:        /*
        !          2519:         * If the destination exists, then be sure its type (file or dir)
        !          2520:         * matches that of the source.  And, if it is a directory make sure
        !          2521:         * it is empty.  Then delete the destination.
        !          2522:         */
        !          2523:        if (target_vp) {
        !          2524: 
        !          2525:         /*
        !          2526:          * If the parent directory is "sticky", then the user must
        !          2527:          * own the parent directory, or the destination of the rename,
        !          2528:          * otherwise the destination may not be changed (except by
        !          2529:          * root). This implements append-only directories.
        !          2530:          */
        !          2531:         if ((targetPar_hp->h_meta->h_mode & S_ISTXT) && (target_cnp->cn_cred->cr_uid != 0) &&
        !          2532:             target_cnp->cn_cred->cr_uid != targetPar_hp->h_meta->h_uid &&
        !          2533:             target_cnp->cn_cred->cr_uid != target_hp->h_meta->h_uid) {
        !          2534:             retval = EPERM;
        !          2535:             goto bad;
        !          2536:         }
        !          2537: 
        !          2538:                /*
        !          2539:                 * VOP_REMOVE will vput targetPar_vp so we better bump 
        !          2540:                 * its ref count and relockit, always set target_vp to
        !          2541:                 * NULL afterwards to indicate that were done with it.
        !          2542:                 */
        !          2543:                VREF(targetPar_vp);
        !          2544:         if (target_vp->v_type == VREG) {
        !          2545:             (void) vnode_uncache(target_vp);
        !          2546:             if (ISMAPPEDFILE(target_vp)) {
        !          2547:                 ubc_unlink(target_vp);
        !          2548:             }
        !          2549:         }
        !          2550:         cache_purge(target_vp);
        !          2551:             
        !          2552: #if HFS_HARDLINKS
        !          2553:                target_cnp->cn_flags &= ~SAVENAME;
        !          2554: #endif
        !          2555:                retval = VOP_REMOVE(targetPar_vp, target_vp, target_cnp);
        !          2556:                (void) vn_lock(targetPar_vp, LK_EXCLUSIVE | LK_RETRY, p);
        !          2557: 
        !          2558:                target_vp = NULL;
        !          2559:                target_hp = NULL;               
        !          2560:                
        !          2561:                if (retval) goto bad;
        !          2562: 
        !          2563:        };
        !          2564: 
        !          2565: 
        !          2566:        if (newparent != oldparent)
        !          2567:                vn_lock(sourcePar_vp, LK_EXCLUSIVE | LK_RETRY, p);
        !          2568: 
        !          2569:        /* lock catalog b-tree */
        !          2570:        retval = hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          2571:        if (retval) {
        !          2572:                if (newparent != oldparent)             /* unlock the lock we just got */
        !          2573:                        VOP_UNLOCK(sourcePar_vp, 0, p);
        !          2574:                 goto bad;
        !          2575:        };
        !          2576:        
        !          2577:        /* remove the existing entry from the namei cache: */
        !          2578:        cache_purge(source_vp);
        !          2579: 
        !          2580:        /* use source_cnp instead of H_NAME(source_hp) in case source is a hard link */
        !          2581:        retval = hfsMoveRename( HTOVCB(source_hp), H_DIRID(source_hp), source_cnp->cn_nameptr,
        !          2582:                                                        H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, &H_HINT(source_hp));
        !          2583: 
        !          2584:        if (retval == 0) {      
        !          2585:            /* Look up the catalog entry just renamed since it might have been auto-decomposed */
        !          2586:            catInfo.hint = H_HINT(source_hp);
        !          2587:            retval = hfsLookup(HTOVCB(source_hp), H_FILEID(targetPar_hp), target_cnp->cn_nameptr, target_cnp->cn_namelen, &catInfo);
        !          2588:        }
        !          2589: 
        !          2590:        /* unlock catalog b-tree */
        !          2591:        (void) hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          2592: 
        !          2593:        if (newparent != oldparent)
        !          2594:                VOP_UNLOCK(sourcePar_vp, 0, p);
        !          2595: 
        !          2596:        if (retval)  goto bad;
        !          2597: 
        !          2598:        H_DIRID(source_hp) = H_FILEID(targetPar_hp);
        !          2599: 
        !          2600:        hfs_set_metaname(catInfo.spec.name, source_hp->h_meta);
        !          2601:        
        !          2602:        source_hp->h_nodeflags &= ~IN_RENAME;
        !          2603: 
        !          2604: 
        !          2605:        /*
        !          2606:         * Timestamp both parent directories.
        !          2607:         * Note that if this is a rename within the same directory,
        !          2608:         * (where targetPar_hp == sourcePar_hp)
        !          2609:         * the code below is still safe and correct.
        !          2610:         */
        !          2611:        targetPar_hp->h_nodeflags |= IN_UPDATE;
        !          2612:        sourcePar_hp->h_nodeflags |= IN_UPDATE;
        !          2613:        tv = time;
        !          2614:        HFSTIMES(targetPar_hp, &tv, &tv);
        !          2615:        HFSTIMES(sourcePar_hp, &tv, &tv);
        !          2616: 
        !          2617:        VPUT(targetPar_vp);
        !          2618:        VRELE(sourcePar_vp);
        !          2619:        VPUT(source_vp);
        !          2620: 
        !          2621:        DBG_VOP_LOCKS_TEST(retval);
        !          2622:        if (retval != E_NONE) {
        !          2623:                DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
        !          2624:        }
        !          2625:        return (retval);
        !          2626: 
        !          2627: bad:;
        !          2628:        if (retval && doingdirectory)
        !          2629:                source_hp->h_nodeflags &= ~IN_RENAME;
        !          2630: 
        !          2631:     if (targetPar_vp == target_vp)
        !          2632:            VRELE(targetPar_vp);
        !          2633:     else
        !          2634:            VPUT(targetPar_vp);
        !          2635: 
        !          2636:     if (target_vp)
        !          2637:            VPUT(target_vp);
        !          2638: 
        !          2639:        VRELE(sourcePar_vp);
        !          2640: 
        !          2641:     if (VOP_ISLOCKED(source_vp))
        !          2642:         VPUT(source_vp);
        !          2643:        else
        !          2644:        VRELE(source_vp);
        !          2645: 
        !          2646:     DBG_VOP_LOCKS_TEST(retval);
        !          2647:     if (retval != E_NONE) {
        !          2648:         DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
        !          2649:     }
        !          2650:     return (retval);
        !          2651: 
        !          2652: abortit:;
        !          2653: 
        !          2654:     VOP_ABORTOP(targetPar_vp, target_cnp); /* XXX, why not in NFS? */
        !          2655: 
        !          2656:     if (targetPar_vp == target_vp)
        !          2657:            VRELE(targetPar_vp);
        !          2658:     else
        !          2659:            VPUT(targetPar_vp);
        !          2660: 
        !          2661:     if (target_vp)
        !          2662:            VPUT(target_vp);
        !          2663: 
        !          2664:     VOP_ABORTOP(sourcePar_vp, source_cnp); /* XXX, why not in NFS? */
        !          2665: 
        !          2666:        VRELE(sourcePar_vp);
        !          2667:     VRELE(source_vp);
        !          2668: 
        !          2669:     DBG_VOP_LOCKS_TEST(retval);
        !          2670:     if (retval != E_NONE) {
        !          2671:         DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
        !          2672:     }
        !          2673:     return (retval);
        !          2674: }
        !          2675: 
        !          2676: 
        !          2677: 
        !          2678: /*
        !          2679:  * Mkdir system call
        !          2680: #% mkdir       dvp     L U U
        !          2681: #% mkdir       vpp     - L -
        !          2682: #
        !          2683:  vop_mkdir {
        !          2684:      IN WILLRELE struct vnode *dvp;
        !          2685:      OUT struct vnode **vpp;
        !          2686:      IN struct componentname *cnp;
        !          2687:      IN struct vattr *vap;
        !          2688: 
        !          2689:      We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
        !          2690:     a previous error.
        !          2691: 
        !          2692: */
        !          2693: 
        !          2694: int
        !          2695: hfs_mkdir(ap)
        !          2696: struct vop_mkdir_args /* {
        !          2697:     struct vnode *a_dvp;
        !          2698:     struct vnode **a_vpp;
        !          2699:     struct componentname *a_cnp;
        !          2700:     struct vattr *a_vap;
        !          2701: } */ *ap;
        !          2702: {
        !          2703:        struct proc             *p = current_proc();
        !          2704:        int                             retval;
        !          2705:        int                             mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
        !          2706: 
        !          2707:        DBG_FUNC_NAME("mkdir");
        !          2708:        DBG_VOP_LOCKS_DECL(2);
        !          2709:        DBG_VOP_PRINT_FUNCNAME();
        !          2710:        DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
        !          2711:        DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
        !          2712: 
        !          2713:        DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2714:        DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
        !          2715: 
        !          2716:        DBG_VOP(("%s: parent 0x%x (%s)  ap->a_cnp->cn_nameptr %s\n", funcname, (u_int)VTOH(ap->a_dvp), H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
        !          2717:        WRITE_CK( ap->a_dvp, funcname);
        !          2718:        DBG_HFS_NODE_CHECK(ap->a_dvp);
        !          2719:        DBG_ASSERT(ap->a_dvp->v_type == VDIR);
        !          2720: 
        !          2721:        /* lock catalog b-tree */
        !          2722:        retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          2723:     if (retval != E_NONE) {
        !          2724:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !          2725:                VPUT(ap->a_dvp);
        !          2726:         DBG_VOP_LOCKS_TEST( retval);
        !          2727:         return (retval);
        !          2728:     }
        !          2729: 
        !          2730:        /* Create the vnode */
        !          2731:     DBG_ASSERT((ap->a_cnp->cn_flags & SAVESTART) == 0);
        !          2732:        retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp);
        !          2733:     DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
        !          2734: 
        !          2735:        /* unlock catalog b-tree */
        !          2736:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
        !          2737: 
        !          2738:     if (retval != E_NONE) {
        !          2739:         DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp))));
        !          2740:         DBG_VOP_LOCKS_TEST(retval);
        !          2741:         return (retval);               
        !          2742:     }
        !          2743: 
        !          2744:     DBG_VOP_LOCKS_TEST(E_NONE);
        !          2745:     return (E_NONE);
        !          2746: }
        !          2747: 
        !          2748: /*
        !          2749:  * Rmdir system call.
        !          2750: #% rmdir       dvp     L U U
        !          2751: #% rmdir       vp      L U U
        !          2752: #
        !          2753:  vop_rmdir {
        !          2754:      IN WILLRELE struct vnode *dvp;
        !          2755:      IN WILLRELE struct vnode *vp;
        !          2756:      IN struct componentname *cnp;
        !          2757: 
        !          2758:      */
        !          2759: 
        !          2760: int
        !          2761: hfs_rmdir(ap)
        !          2762: struct vop_rmdir_args /* {
        !          2763:     struct vnode *a_dvp;
        !          2764:     struct vnode *a_vp;
        !          2765:     struct componentname *a_cnp;
        !          2766: } */ *ap;
        !          2767: {
        !          2768:     struct vnode *vp = ap->a_vp;
        !          2769:     struct vnode *dvp = ap->a_dvp;
        !          2770:     struct hfsnode *hp = VTOH(vp);
        !          2771:     struct proc *p = current_proc();
        !          2772:     int retval;
        !          2773:     DBG_FUNC_NAME("rmdir");
        !          2774:     DBG_VOP_LOCKS_DECL(2);
        !          2775:     DBG_VOP_PRINT_FUNCNAME();
        !          2776:     DBG_VOP(("\tParent: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n"));
        !          2777:     DBG_VOP(("\tTarget: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          2778:     DBG_VOP(("\tTarget Name: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
        !          2779: 
        !          2780:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2781:     DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2782: 
        !          2783:     if (dvp == vp) {
        !          2784:         VRELE(vp);
        !          2785:         VPUT(vp);
        !          2786:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          2787:         return (EINVAL);
        !          2788:     }
        !          2789:        
        !          2790:        /*
        !          2791:         * HFS differs from UFS here in that we don't allow removing
        !          2792:         * a directory that in use by others - even if its empty.
        !          2793:         *
        !          2794:         * In the future we might want to allow this just like we do
        !          2795:         * for files (by renaming the busy directory).
        !          2796:         */
        !          2797: #if 0
        !          2798:     if (vp->v_usecount > 1) {
        !          2799:         DBG_ERR(("%s: dir is busy, usecount is %d\n", funcname, vp->v_usecount ));
        !          2800:                retval = EBUSY;
        !          2801:                goto Err_Exit;
        !          2802:     }
        !          2803: #endif
        !          2804:     /* remove the entry from the namei cache: */
        !          2805:     cache_purge(vp);
        !          2806: 
        !          2807:        /* lock catalog b-tree */
        !          2808:        retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          2809:        if (retval != E_NONE) {
        !          2810:                goto Err_Exit;
        !          2811:        }
        !          2812: 
        !          2813:        /* remove entry from catalog */
        !          2814:     retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), FALSE, H_HINT(hp));
        !          2815:     hp->h_meta->h_mode = 0;                            /* Makes the vnode go away...see inactive */
        !          2816: 
        !          2817:        /* unlock catalog b-tree */
        !          2818:        (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          2819: 
        !          2820:        /* Set the parent to be updated */
        !          2821:        if (! retval)
        !          2822:                VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          2823: 
        !          2824: Err_Exit:;
        !          2825:     if (dvp != 0) 
        !          2826:                VPUT(dvp);
        !          2827:     VPUT(vp);
        !          2828: 
        !          2829:     DBG_VOP_LOCKS_TEST(retval);
        !          2830:     return (retval);
        !          2831: }
        !          2832: 
        !          2833: /*
        !          2834:  * symlink -- make a symbolic link
        !          2835: #% symlink     dvp     L U U
        !          2836: #% symlink     vpp     - U -
        !          2837: #
        !          2838: # XXX - note that the return vnode has already been VRELE'ed
        !          2839: #      by the filesystem layer.  To use it you must use vget,
        !          2840: #      possibly with a further namei.
        !          2841: #
        !          2842:  vop_symlink {
        !          2843:      IN WILLRELE struct vnode *dvp;
        !          2844:      OUT WILLRELE struct vnode **vpp;
        !          2845:      IN struct componentname *cnp;
        !          2846:      IN struct vattr *vap;
        !          2847:      IN char *target;
        !          2848: 
        !          2849:      We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
        !          2850:     a previous error.
        !          2851: 
        !          2852: 
        !          2853: */
        !          2854: 
        !          2855: int
        !          2856: hfs_symlink(ap)
        !          2857:     struct vop_symlink_args /* {
        !          2858:         struct vnode *a_dvp;
        !          2859:         struct vnode **a_vpp;
        !          2860:         struct componentname *a_cnp;
        !          2861:         struct vattr *a_vap;
        !          2862:         char *a_target;
        !          2863:     } */ *ap;
        !          2864: {
        !          2865:     register struct vnode *vp, **vpp = ap->a_vpp;
        !          2866:        struct proc *p = current_proc();
        !          2867:        struct hfsnode *hp;
        !          2868:        u_int32_t dfltClump;
        !          2869:     int len, retval;
        !          2870:     DBG_FUNC_NAME("symlink");
        !          2871:     DBG_VOP_LOCKS_DECL(2);
        !          2872:     DBG_VOP_PRINT_FUNCNAME();
        !          2873:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          2874:     DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS);
        !          2875: 
        !          2876:     if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
        !          2877:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !          2878:         VPUT(ap->a_dvp);
        !          2879:         DBG_VOP((" ...sorry HFS disks don't support symbolic links.\n"));
        !          2880:         DBG_VOP_LOCKS_TEST(EOPNOTSUPP);
        !          2881:         return (EOPNOTSUPP);
        !          2882:     }
        !          2883: 
        !          2884:        /* lock catalog b-tree */
        !          2885:        retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          2886:        if (retval != E_NONE) {
        !          2887:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
        !          2888:        VPUT(ap->a_dvp);
        !          2889:         DBG_VOP_LOCKS_TEST( retval);
        !          2890:         return (retval);
        !          2891:        }
        !          2892: 
        !          2893:        /* Create the vnode */
        !          2894:        retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, 0, ap->a_dvp, vpp, ap->a_cnp);
        !          2895:     DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
        !          2896: 
        !          2897:        /* unlock catalog b-tree */
        !          2898:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
        !          2899: 
        !          2900:     if (retval != E_NONE) {
        !          2901:         DBG_VOP_LOCKS_TEST(retval);
        !          2902:         return (retval);
        !          2903:        }
        !          2904: 
        !          2905: 
        !          2906:     vp = *vpp;
        !          2907:     len = strlen(ap->a_target);
        !          2908:        hp = VTOH(vp);
        !          2909:        dfltClump = hp->fcbClmpSize;
        !          2910:        /* make clump size minimal */
        !          2911:        hp->fcbClmpSize = VTOVCB(vp)->blockSize;
        !          2912:     retval = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
        !          2913:                      UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
        !          2914:                      (struct proc *)0);
        !          2915:        hp->fcbClmpSize = dfltClump;
        !          2916: 
        !          2917: 
        !          2918:     VPUT(vp);
        !          2919:     DBG_VOP_LOCKS_TEST(retval);
        !          2920:     return (retval);
        !          2921: }
        !          2922: 
        !          2923: 
        !          2924: /*
        !          2925:  * Dummy dirents to simulate the "." and ".." entries of the directory
        !          2926:  * in a hfs filesystem.  HFS doesn't provide these on disk.  Note that
        !          2927:  * the size of these entries is the smallest needed to represent them
        !          2928:  * (only 12 byte each).
        !          2929:  */
        !          2930: static hfsdotentry  rootdots[2] = {
        !          2931:        {
        !          2932:                1,                              /* d_fileno */
        !          2933:                sizeof(struct hfsdotentry),     /* d_reclen */
        !          2934:                DT_DIR,                         /* d_type */
        !          2935:                1,                              /* d_namlen */
        !          2936:                "."                             /* d_name */
        !          2937:     },
        !          2938:     {
        !          2939:                1,                              /* d_fileno */
        !          2940:                sizeof(struct hfsdotentry),     /* d_reclen */
        !          2941:                DT_DIR,                         /* d_type */
        !          2942:                2,                              /* d_namlen */
        !          2943:                ".."                            /* d_name */
        !          2944:        }
        !          2945: };
        !          2946: 
        !          2947: static hfsdotentry  emptyentry = { 0 };
        !          2948: 
        !          2949: /*     4.3 Note:
        !          2950: *      There is some confusion as to what the semantics of uio_offset are.
        !          2951: *      In ufs, it represents the actual byte offset within the directory
        !          2952: *      "file."  HFS, however, just uses it as an entry counter - essentially
        !          2953: *      assuming that it has no meaning except to the hfs_readdir function.
        !          2954: *      This approach would be more efficient here, but some callers may
        !          2955: *      assume the uio_offset acts like a byte offset.  NFS in fact
        !          2956: *      monkeys around with the offset field a lot between readdir calls.
        !          2957: *
        !          2958: *      The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len
        !          2959: *      fields is a mess as well.  The libc function readdir() returns
        !          2960: *      NULL (indicating the end of a directory) when either
        !          2961: *      the getdirentries() syscall (which calls this and returns
        !          2962: *      the size of the buffer passed in less the value of uiop->uio_resid)
        !          2963: *      returns 0, or a direct record with a d_reclen of zero.
        !          2964: *      nfs_server.c:rfs_readdir(), on the other hand, checks for the end
        !          2965: *      of the directory by testing uiop->uio_resid == 0.  The solution
        !          2966: *      is to pad the size of the last struct direct in a given
        !          2967: *      block to fill the block if we are not at the end of the directory.
        !          2968: */
        !          2969: 
        !          2970: struct callbackstate {
        !          2971:        u_int32_t       cbs_parentID;
        !          2972:        u_int32_t       cbs_hiddenDirID;
        !          2973:        off_t           cbs_lastoffset;
        !          2974:        struct uio *    cbs_uio;
        !          2975:        ExtendedVCB *   cbs_vcb;
        !          2976:        int16_t         cbs_hfsPlus;
        !          2977:        int16_t         cbs_result;
        !          2978: };
        !          2979: 
        !          2980: 
        !          2981: SInt32
        !          2982: ProcessCatalogEntry(const CatalogKey *ckp, const CatalogRecord *crp,
        !          2983:                    u_int16_t recordLen, struct callbackstate *state)
        !          2984: {
        !          2985:        CatalogName *cnp;
        !          2986:        ByteCount utf8chars;
        !          2987:        u_int32_t curID;
        !          2988:        OSErr result;
        !          2989:        struct dirent catent;
        !          2990:        
        !          2991:        if (state->cbs_hfsPlus)
        !          2992:                curID = ckp->hfsPlus.parentID;
        !          2993:        else
        !          2994:                curID = ckp->hfs.parentID;
        !          2995: 
        !          2996:        /* We're done when parent directory changes */
        !          2997:        if (state->cbs_parentID != curID) {
        !          2998: lastitem:
        !          2999: /*
        !          3000:  * The NSDirectoryList class chokes on empty records (it doesnt check d_reclen!)
        !          3001:  * so remove padding for now...
        !          3002:  */
        !          3003: #if 0
        !          3004:                /*
        !          3005:                 * Pad the end of list with an empty record.
        !          3006:                 * This eliminates an extra call by readdir(3c).
        !          3007:                 */
        !          3008:                catent.d_fileno = 0;
        !          3009:                catent.d_reclen = 0;
        !          3010:                catent.d_type = 0;
        !          3011:                catent.d_namlen = 0;
        !          3012:                *(int32_t*)&catent.d_name[0] = 0;
        !          3013: 
        !          3014:                state->cbs_lastoffset = state->cbs_uio->uio_offset;
        !          3015: 
        !          3016:                state->cbs_result = uiomove((caddr_t) &catent, 12, state->cbs_uio);
        !          3017:                if (state->cbs_result == 0)
        !          3018:                        state->cbs_result = ENOENT;
        !          3019: #else
        !          3020:                state->cbs_lastoffset = state->cbs_uio->uio_offset;
        !          3021:                state->cbs_result = ENOENT;
        !          3022: #endif
        !          3023:                return (0);     /* stop */
        !          3024:        }
        !          3025: 
        !          3026:        if (state->cbs_hfsPlus) {
        !          3027:                switch(crp->recordType) {
        !          3028:                case kHFSPlusFolderRecord:
        !          3029:                        catent.d_type = DT_DIR;
        !          3030:                        catent.d_fileno = crp->hfsPlusFolder.folderID;
        !          3031:                        break;
        !          3032:                case kHFSPlusFileRecord:
        !          3033:                        catent.d_type = DT_REG;
        !          3034:                        catent.d_fileno = crp->hfsPlusFile.fileID;
        !          3035:                        break;
        !          3036:                default:
        !          3037:                        return (0);     /* stop */
        !          3038:                };
        !          3039: 
        !          3040:                cnp = (CatalogName*) &ckp->hfsPlus.nodeName;
        !          3041:                /*XXX need to add name mangling for long names */
        !          3042:                result = ConvertUnicodeToUTF8(cnp->ustr.length * sizeof(UniChar),
        !          3043:                            cnp->ustr.unicode, NAME_MAX + 1, &utf8chars, catent.d_name);
        !          3044:        } else { /* hfs */
        !          3045:                switch(crp->recordType) {
        !          3046:                case kHFSFolderRecord:
        !          3047:                        catent.d_type = DT_DIR;
        !          3048:                        catent.d_fileno = crp->hfsFolder.folderID;
        !          3049:                        break;
        !          3050:                case kHFSFileRecord:
        !          3051:                        catent.d_type = DT_REG;
        !          3052:                        catent.d_fileno = crp->hfsFile.fileID;
        !          3053:                        break;
        !          3054:                default:
        !          3055:                        return (0);     /* stop */
        !          3056:                };
        !          3057: 
        !          3058:                cnp = (CatalogName*) ckp->hfs.nodeName;
        !          3059:                result = hfs_to_utf8(state->cbs_vcb, cnp->pstr, NAME_MAX + 1,
        !          3060:                                     &utf8chars, catent.d_name);
        !          3061:        }
        !          3062: 
        !          3063:        catent.d_namlen = utf8chars;
        !          3064:        catent.d_reclen = DIRENTRY_SIZE(utf8chars);
        !          3065:        
        !          3066:        /* hide our private meta data directory */
        !          3067:        if (curID == kRootDirID                         &&
        !          3068:            catent.d_fileno == state->cbs_hiddenDirID   &&
        !          3069:            catent.d_type == DT_DIR)
        !          3070:                goto lastitem;
        !          3071: 
        !          3072:        /* if this entry won't fit then we're done */
        !          3073:        if (catent.d_reclen > state->cbs_uio->uio_resid)
        !          3074:                return (0);     /* stop */
        !          3075: 
        !          3076:        state->cbs_lastoffset = state->cbs_uio->uio_offset;
        !          3077: 
        !          3078:        state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio);
        !          3079: 
        !          3080:        /* continue iteration if there's room */
        !          3081:        return (state->cbs_result == 0  &&
        !          3082:                state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE);
        !          3083: }
        !          3084: 
        !          3085: /*
        !          3086:  * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value
        !          3087:  * returned be stat() call as the block size. This is mentioned in the man page for getdirentries():
        !          3088:  * "Nbytes must be greater than or equal to the block size associated with the file,
        !          3089:  * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough
        !          3090:  * room for the . and .. entries that have to added manually.
        !          3091:  */
        !          3092: 
        !          3093: /*                     
        !          3094: #% readdir     vp      L L L
        !          3095: #
        !          3096: vop_readdir {
        !          3097:     IN struct vnode *vp;
        !          3098:     INOUT struct uio *uio;
        !          3099:     IN struct ucred *cred;
        !          3100:     INOUT int *eofflag;
        !          3101:     OUT int *ncookies;
        !          3102:     INOUT u_long **cookies;
        !          3103:     */
        !          3104: static int
        !          3105: hfs_readdir(ap)
        !          3106: struct vop_readdir_args /* {
        !          3107:     struct vnode *vp;
        !          3108:     struct uio *uio;
        !          3109:     struct ucred *cred;
        !          3110:     int *eofflag;
        !          3111:     int *ncookies;
        !          3112:     u_long **cookies;
        !          3113: } */ *ap;
        !          3114: {
        !          3115:     register struct uio *uio = ap->a_uio;
        !          3116:     struct hfsnode             *hp = VTOH(ap->a_vp);
        !          3117:     struct proc                        *p = current_proc();
        !          3118:     ExtendedVCB                *vcb = HTOVCB(hp);
        !          3119:     off_t                              off = uio->uio_offset;
        !          3120:        u_int32_t dirID = H_FILEID(hp);
        !          3121:        int retval = 0;
        !          3122:     OSErr                              result = noErr;
        !          3123:        u_int32_t diroffset;
        !          3124:        BTreeIterator bi;
        !          3125:        CatalogIterator *cip;
        !          3126:        u_int16_t op;
        !          3127:        struct callbackstate state;
        !          3128:        int eofflag = 0;
        !          3129: 
        !          3130:     DBG_FUNC_NAME("readdir");
        !          3131:     DBG_VOP_LOCKS_DECL(1);
        !          3132: 
        !          3133:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          3134:     DBG_VOP_PRINT_FUNCNAME();
        !          3135:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          3136:     DBG_HFS_NODE_CHECK(ap->a_vp);
        !          3137: 
        !          3138:     /* We assume it's all one big buffer... */
        !          3139:        if (uio->uio_iovcnt > 1 || uio->uio_resid < AVERAGE_HFSDIRENTRY_SIZE) {
        !          3140:                return EINVAL;
        !          3141:        };
        !          3142: 
        !          3143:        /* Create the entries for . and .. */
        !          3144:        if (uio->uio_offset < sizeof(rootdots)) {
        !          3145:                caddr_t dep;
        !          3146:                size_t dotsize;
        !          3147:                
        !          3148:                rootdots[0].d_fileno = dirID;
        !          3149:                rootdots[1].d_fileno = H_DIRID(hp);
        !          3150: 
        !          3151:                if (uio->uio_offset == 0) {
        !          3152:                        dep = (caddr_t) &rootdots[0];
        !          3153:                        dotsize = 2* sizeof(struct hfsdotentry);
        !          3154:                } else if (uio->uio_offset == sizeof(struct hfsdotentry)) {
        !          3155:                        dep = (caddr_t) &rootdots[1];
        !          3156:                        dotsize = sizeof(struct hfsdotentry);
        !          3157:                } else {
        !          3158:                        retval = EINVAL;
        !          3159:                        goto Exit;
        !          3160:                }
        !          3161: 
        !          3162:                retval = uiomove(dep, dotsize, uio);
        !          3163:                if (retval != 0)
        !          3164:                        goto Exit;
        !          3165:        }
        !          3166:        
        !          3167:        diroffset = uio->uio_offset;
        !          3168: 
        !          3169:        /* lock catalog b-tree */
        !          3170:        retval = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p);
        !          3171:        if (retval != E_NONE)
        !          3172:                goto Exit;
        !          3173: 
        !          3174:        /* get an iterator and position it */
        !          3175:        cip = GetCatalogIterator(vcb, dirID, diroffset);
        !          3176: 
        !          3177:        result = PositionIterator(cip, diroffset, &bi, &op);
        !          3178:        if (result == cmNotFound) {
        !          3179:                eofflag = 1;
        !          3180:                retval = 0;
        !          3181:                AgeCatalogIterator(cip);
        !          3182:                goto cleanup;
        !          3183:        } else if ((retval = MacToVFSError(result)))
        !          3184:                goto cleanup;
        !          3185: 
        !          3186:        state.cbs_hiddenDirID = VCBTOHFS(vcb)->hfs_private_metadata_dir;
        !          3187:        state.cbs_lastoffset = cip->currentOffset;
        !          3188:        state.cbs_vcb = vcb;
        !          3189:        state.cbs_uio = uio;
        !          3190:        state.cbs_result = 0;
        !          3191:        state.cbs_parentID = dirID;
        !          3192: 
        !          3193:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          3194:                state.cbs_hfsPlus = 1;
        !          3195:        else
        !          3196:                state.cbs_hfsPlus = 0;
        !          3197: 
        !          3198:        /* process as many entries as possible... */
        !          3199:        result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op, &bi,
        !          3200:                 (IterateCallBackProcPtr)ProcessCatalogEntry, &state);
        !          3201: 
        !          3202:        if (state.cbs_result)
        !          3203:                retval = state.cbs_result;
        !          3204:        else
        !          3205:                retval = MacToVFSError(result);
        !          3206: 
        !          3207:        if (retval == ENOENT) {
        !          3208:                eofflag = 1;
        !          3209:                retval = 0;
        !          3210:        }
        !          3211: 
        !          3212:        if (retval == 0) {
        !          3213:                cip->currentOffset = state.cbs_lastoffset;
        !          3214:                cip->nextOffset = uio->uio_offset;
        !          3215:                UpdateCatalogIterator(&bi, cip);
        !          3216:        }
        !          3217: 
        !          3218: cleanup:
        !          3219:        if (retval) {
        !          3220:                cip->volume = 0;
        !          3221:                cip->folderID = 0;
        !          3222:                AgeCatalogIterator(cip);
        !          3223:        }
        !          3224: 
        !          3225:        (void) ReleaseCatalogIterator(cip);
        !          3226: 
        !          3227:        /* unlock catalog b-tree */
        !          3228:        (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          3229: 
        !          3230:     if (retval != E_NONE) {
        !          3231:         DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval,
        !          3232:                 H_FILEID(hp), H_NAME(hp)));
        !          3233:                goto Exit;
        !          3234: 
        !          3235:        }
        !          3236:        
        !          3237:        /* were we already past eof ? */
        !          3238:        if (uio->uio_offset == off) {
        !          3239:                uio->uio_offset = 0;
        !          3240:                retval = E_NONE;
        !          3241:                goto Exit;
        !          3242:        }
        !          3243:        
        !          3244:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          3245:                hp->h_nodeflags |= IN_ACCESS;
        !          3246: 
        !          3247: #if 0  
        !          3248:     /* Bake any cookies */
        !          3249:     if (!retval && ap->a_ncookies != NULL) {
        !          3250:         struct dirent* dpStart;
        !          3251:         struct dirent* dpEnd;
        !          3252:         struct dirent* dp;
        !          3253:         int ncookies;
        !          3254:         u_long *cookies;
        !          3255:         u_long *cookiep;
        !          3256: 
        !          3257:         /*
        !          3258:         * Only the NFS server uses cookies, and it loads the
        !          3259:         * directory block into system space, so we can just look at
        !          3260:         * it directly.
        !          3261:         */
        !          3262:            if (uio->uio_segflg != UIO_SYSSPACE)
        !          3263:             panic("hfs_readdir: unexpected uio from NFS server");
        !          3264:         dpStart = (struct dirent *)
        !          3265:             (uio->uio_iov->iov_base - (uio->uio_offset - off));
        !          3266:         dpEnd = (struct dirent *) uio->uio_iov->iov_base;
        !          3267:         for (dp = dpStart, ncookies = 0;
        !          3268:             dp < dpEnd && dp->d_reclen != 0;
        !          3269:             dp = (struct dirent *)((caddr_t)dp + dp->d_reclen))
        !          3270:             ncookies++;
        !          3271:         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
        !          3272:             M_WAITOK);
        !          3273:         for (dp = dpStart, cookiep = cookies;
        !          3274:             dp < dpEnd;
        !          3275:             dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
        !          3276:             off += dp->d_reclen;
        !          3277:             *cookiep++ = (u_long) off;
        !          3278:         }
        !          3279:         *ap->a_ncookies = ncookies;
        !          3280:         *ap->a_cookies = cookies;
        !          3281:     }
        !          3282: #endif
        !          3283: 
        !          3284: Exit:;
        !          3285: 
        !          3286:     if (ap->a_eofflag)
        !          3287:            *ap->a_eofflag = eofflag;
        !          3288: 
        !          3289:     DBG_VOP_LOCKS_TEST(retval);
        !          3290:     return (retval);
        !          3291: }
        !          3292: 
        !          3293: 
        !          3294: /*
        !          3295:  * readdirattr operation will return attributes for the items in the
        !          3296:  * directory specified. 
        !          3297:  *
        !          3298:  * It does not do . and .. entries. The problem is if you are at the root of the
        !          3299:  * hfs directory and go to .. you could be crossing a mountpoint into a
        !          3300:  * different (ufs) file system. The attributes that apply for it may not 
        !          3301:  * apply for the file system you are doing the readdirattr on. To make life 
        !          3302:  * simpler, this call will only return entries in its directory, hfs like.
        !          3303:      * TO DO LATER: 
        !          3304:      * 1.getattrlist creates a thread record if the objpermanentid attribute
        !          3305:      *  is requested. Just do EINVAL for now and fix later. 
        !          3306:      * 2. more than one for uiovcnt support.
        !          3307:      * 3. put knohint (hints) in state for next call in
        !          3308:      * 4. credentials checking when rest of hfs does it.
        !          3309:      * 5. Do return permissions concatenation ???
        !          3310:  */
        !          3311: 
        !          3312: /*                     
        !          3313: #
        !          3314: #% readdirattr vp      L L L
        !          3315: #
        !          3316: vop_readdirattr {
        !          3317:        IN struct vnode *vp;
        !          3318:        IN struct attrlist *alist;
        !          3319:        INOUT struct uio *uio;
        !          3320:        IN u_long maxcount:
        !          3321:        IN u_long options;
        !          3322:        OUT u_long *newstate;
        !          3323:        OUT int *eofflag;
        !          3324:        OUT u_long *actualCount;
        !          3325:        OUT u_long **cookies;
        !          3326:        IN struct ucred *cred;
        !          3327: };
        !          3328: */
        !          3329: static int
        !          3330: hfs_readdirattr(ap)
        !          3331: struct vop_readdirattr_args /* {
        !          3332:     struct vnode *vp;
        !          3333:     struct attrlist *alist;
        !          3334:     struct uio *uio;
        !          3335:     u_long maxcount:
        !          3336:     u_long options;
        !          3337:     int *newstate;
        !          3338:     int *eofflag;
        !          3339:     u_long *actualcount;
        !          3340:     u_long **cookies;
        !          3341:     struct ucred *cred;
        !          3342: } */ *ap;
        !          3343: {
        !          3344:     struct vnode       *vp = ap->a_vp;
        !          3345:     struct attrlist    *alist = ap->a_alist;
        !          3346:     register struct    uio *uio = ap->a_uio;
        !          3347:     u_long             maxcount = ap->a_maxcount;
        !          3348:     u_long             ncookies;
        !          3349:     ExtendedVCB        *vcb = HTOVCB(VTOH(vp));
        !          3350:     UInt32             dirID =  H_FILEID(VTOH(vp));
        !          3351:     struct proc                *proc = current_proc(); /* could get this out of uio */
        !          3352:     off_t              startoffset = uio->uio_offset;
        !          3353:     struct hfsCatalogInfo catalogInfo;
        !          3354:     UInt32             index;
        !          3355:     int                        retval = 0;
        !          3356:     u_long             fixedblocksize;
        !          3357:     u_long             maxattrblocksize;
        !          3358:     u_long             currattrbufsize;
        !          3359:     void               *attrbufptr = NULL;
        !          3360:     void               *attrptr;
        !          3361:     void               *varptr;
        !          3362:  
        !          3363: 
        !          3364:     *(ap->a_actualcount) = 0;
        !          3365:     *(ap->a_eofflag) = 0;
        !          3366: 
        !          3367:     /* not using options (don't follow symlinks = 0), check vnode, and buffer space */
        !          3368:     if ((ap->a_options != 0) || (vp == NULL) || 
        !          3369:        (uio->uio_resid <= 0) || (uio->uio_iovcnt > 1))
        !          3370:           return EINVAL;
        !          3371: 
        !          3372:     /* this call doesn't take volume attributes */
        !          3373:     if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
        !          3374:         ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
        !          3375:         (alist->volattr  != 0) ||
        !          3376:         ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
        !          3377:         ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) ||
        !          3378:         ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) 
        !          3379:         return EINVAL;
        !          3380: 
        !          3381:     /* Reject requests for unsupported options for now: */
        !          3382:     if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
        !          3383:         (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST)) ||
        !          3384:        (alist->commonattr & ATTR_CMN_OBJPERMANENTID) ) 
        !          3385:         return EINVAL;
        !          3386: 
        !          3387:     /* getattrlist and searchfs use a secondary buffer to malloc and then use
        !          3388:      * uiomove afterwards. It's an extra copy, but for now leave it alone
        !          3389:     */
        !          3390:     fixedblocksize = (sizeof(u_long) + AttributeBlockSize(alist)); /* u_long for length */
        !          3391:     maxattrblocksize = fixedblocksize;
        !          3392:     if (alist->commonattr & ATTR_CMN_NAME) 
        !          3393:        maxattrblocksize += NAME_MAX + 1;
        !          3394:     MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
        !          3395:     attrptr = attrbufptr;
        !          3396:     varptr = (char *)attrbufptr + fixedblocksize;  /* Point to variable-length storage */
        !          3397: 
        !          3398:     /* Since attributes passed back can contain variable ones (name), we can't just use 
        !          3399:      * uio_offset as is. We thus force it to represent fixed size of hfsdirentries
        !          3400:      * as hfs_readdir was originally doing. If this all we need to represent the current
        !          3401:      * state, then ap->a_state is not needed at all.
        !          3402:     */
        !          3403:     /* index = ap->a_state;  should not be less than 1 */
        !          3404:     index = (uio->uio_offset / sizeof(struct dirent)) + 1;
        !          3405: 
        !          3406:     /* Lock catalog b-tree */  
        !          3407:     if ((retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, proc)) != E_NONE)
        !          3408:         goto exit;
        !          3409: 
        !          3410:     /* HFS Catalog does not have a bulk directory enumeration call. Do it one at
        !          3411:      * time, using hints. GetCatalogOffspring takes care of hfsplus and name issues
        !          3412:      * for us, so that's a win. Later, implement GetCatalogOffspringBulk.
        !          3413:     */
        !          3414:     catalogInfo.hint = kNoHint; /* note, we may want to save the latest in state */
        !          3415:     while ((uio->uio_resid >= 0) && (maxcount !=0 )) {
        !          3416:         /* better to check uio_resid against max or fixedblocksize, but won't work.
        !          3417:          * Depending on if dir or file, the attributes returned will be different.
        !          3418:          * Thus fixedblocksize is too large in some cases.Also, the variable
        !          3419:          * part (like name)  could be between fixedblocksize and the max.
        !          3420:         */
        !          3421:         OSErr result = GetCatalogOffspring(vcb, dirID, index, &catalogInfo.spec,
        !          3422:            &catalogInfo.nodeData, NULL, NULL);
        !          3423:         if (result != noErr) {
        !          3424:             if (result == cmNotFound) {
        !          3425:                 *(ap->a_eofflag) = TRUE;
        !          3426:                 retval = E_NONE;
        !          3427:             }
        !          3428:             else retval = MacToVFSError(result);
        !          3429:             break;
        !          3430:         }
        !          3431: 
        !          3432:        /* hide our private meta data directory as does hfs_readdir */
        !          3433:        if ((dirID == kRootDirID)  &&
        !          3434:            catalogInfo.nodeData.cnd_nodeID == VCBTOHFS(vcb)->hfs_private_metadata_dir  &&
        !          3435:            catalogInfo.nodeData.cnd_type == kCatalogFolderNode) {
        !          3436: 
        !          3437:            ++index;
        !          3438:             continue;
        !          3439:        }
        !          3440: 
        !          3441:         *((u_long *)attrptr)++ = 0; /* move it past length */
        !          3442: 
        !          3443:        /* vp okay to use instead of root vp */
        !          3444:         PackCatalogInfoAttributeBlock(alist, vp, &catalogInfo, &attrptr, &varptr);
        !          3445:         currattrbufsize = *((u_long *)attrbufptr) = ((char *)varptr - (char *)attrbufptr); 
        !          3446: 
        !          3447:         /* now check if we can't fit in the buffer space remaining */
        !          3448:         if (currattrbufsize > uio->uio_resid) 
        !          3449:             break;
        !          3450:        else { 
        !          3451:             retval = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
        !          3452:             if (retval != E_NONE)
        !          3453:                 break; 
        !          3454:             attrptr = attrbufptr;
        !          3455:             index++;
        !          3456:            *ap->a_actualcount += 1;
        !          3457:            maxcount--;
        !          3458:        }
        !          3459:     };
        !          3460:     *ap->a_newstate = VTOH(vp)->h_meta->h_mtime;/* before we unlock, know the mod date */
        !          3461:    /* Unlock catalog b-tree, finally. Ties up the everything during enumeration */
        !          3462:     (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, proc );
        !          3463:     
        !          3464:     if (!retval && ap->a_cookies != NULL) { /* CHECK THAT 0 wasn't passed in */
        !          3465:         void* dpStart;
        !          3466:         void* dpEnd;
        !          3467:         void* dp;
        !          3468:        u_long *cookies;
        !          3469:        u_long *cookiep;
        !          3470: 
        !          3471:         /* Only the NFS server uses cookies, and it loads the
        !          3472:          * directory block into system space, so we can just look at
        !          3473:          * it directly.
        !          3474:         */
        !          3475:         if (uio->uio_segflg != UIO_SYSSPACE) /* || uio->uio_iovcnt != 1 checked earlier */
        !          3476:             panic("hfs_readdirattr: unexpected uio from NFS server");
        !          3477:         dpStart = uio->uio_iov->iov_base - (uio->uio_offset - startoffset);
        !          3478:         dpEnd = uio->uio_iov->iov_base;
        !          3479:         MALLOC(cookies, u_long *, (*ap->a_actualcount)*sizeof(u_long), M_TEMP, M_WAITOK);
        !          3480:         for (dp = dpStart, cookiep = cookies;
        !          3481:             dp < dpEnd;
        !          3482:              dp = ((caddr_t) dp + *((u_long *)dp))) {
        !          3483:                *cookiep++ = (u_long)((caddr_t)dp + sizeof(u_long));
        !          3484:         }
        !          3485:        *ap->a_cookies = cookies;
        !          3486:     }
        !          3487:     
        !          3488:    uio->uio_offset = startoffset + (*ap->a_actualcount)*sizeof(struct dirent);
        !          3489: 
        !          3490: exit:
        !          3491:     if (attrbufptr != NULL)
        !          3492:        FREE(attrbufptr, M_TEMP);
        !          3493:     return (retval);
        !          3494: }
        !          3495: 
        !          3496: 
        !          3497: /*
        !          3498:  * Return target name of a symbolic link
        !          3499: #% readlink    vp      L L L
        !          3500: #
        !          3501:  vop_readlink {
        !          3502:      IN struct vnode *vp;
        !          3503:      INOUT struct uio *uio;
        !          3504:      IN struct ucred *cred;
        !          3505:      */
        !          3506: 
        !          3507: int
        !          3508: hfs_readlink(ap)
        !          3509: struct vop_readlink_args /* {
        !          3510: struct vnode *a_vp;
        !          3511: struct uio *a_uio;
        !          3512: struct ucred *a_cred;
        !          3513: } */ *ap;
        !          3514: {
        !          3515:     int retval;
        !          3516:     DBG_FUNC_NAME("readlink");
        !          3517:     DBG_VOP_LOCKS_DECL(1);
        !          3518:     DBG_VOP_PRINT_FUNCNAME();
        !          3519:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          3520: 
        !          3521:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          3522:     retval = VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
        !          3523:     /* clear IN_ACCESS to prevent needless update of symlink vnode */
        !          3524:     VTOH(ap->a_vp)->h_nodeflags &= ~IN_ACCESS;
        !          3525: 
        !          3526:     DBG_VOP_LOCKS_TEST(retval);
        !          3527:     return (retval);
        !          3528: 
        !          3529: }
        !          3530: 
        !          3531: 
        !          3532: /*
        !          3533:  * hfs abort op, called after namei() when a CREATE/DELETE isn't actually
        !          3534:  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
        !          3535: #% abortop     dvp     = = =
        !          3536: #
        !          3537:  vop_abortop {
        !          3538:      IN struct vnode *dvp;
        !          3539:      IN struct componentname *cnp;
        !          3540: 
        !          3541:      */
        !          3542: 
        !          3543: /* ARGSUSED */
        !          3544: 
        !          3545: static int
        !          3546: hfs_abortop(ap)
        !          3547: struct vop_abortop_args /* {
        !          3548:     struct vnode *a_dvp;
        !          3549:     struct componentname *a_cnp;
        !          3550: } */ *ap;
        !          3551: {
        !          3552:     DBG_FUNC_NAME("abortop");
        !          3553:     DBG_VOP_LOCKS_DECL(1);
        !          3554:     DBG_VOP_PRINT_FUNCNAME();
        !          3555:     DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
        !          3556:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
        !          3557: 
        !          3558: 
        !          3559:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !          3560: 
        !          3561:     if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
        !          3562:         FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
        !          3563:     }
        !          3564:     DBG_VOP_LOCKS_TEST(E_NONE);
        !          3565:     return (E_NONE);
        !          3566: }
        !          3567: 
        !          3568: // int prthfsactive = 0;               /* 1 => print out reclaim of active vnodes */
        !          3569: 
        !          3570: /*
        !          3571: #% inactive    vp      L U U
        !          3572: #
        !          3573:  vop_inactive {
        !          3574:      IN struct vnode *vp;
        !          3575:      IN struct proc *p;
        !          3576: 
        !          3577: */
        !          3578: 
        !          3579: static int
        !          3580: hfs_inactive(ap)
        !          3581: struct vop_inactive_args /* {
        !          3582:     struct vnode *a_vp;
        !          3583: } */ *ap;
        !          3584: {
        !          3585:        struct vnode *vp = ap->a_vp;
        !          3586:        struct hfsnode *hp = VTOH(vp);
        !          3587:        struct proc *p = ap->a_p;
        !          3588:        struct timeval tv;
        !          3589:        int error = 0;
        !          3590:        extern int prtactive;
        !          3591: 
        !          3592:        DBG_FUNC_NAME("inactive");
        !          3593:        DBG_VOP_LOCKS_DECL(1);
        !          3594:        DBG_VOP_PRINT_FUNCNAME();
        !          3595:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          3596: 
        !          3597:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
        !          3598: 
        !          3599: 
        !          3600:        if (prtactive && vp->v_usecount <= 0)
        !          3601:                vprint("hfs_inactive: pushing active", vp);
        !          3602: 
        !          3603:        if (vp->v_usecount != 0)
        !          3604:                DBG_VOP(("%s: bad usecount = %d\n",funcname,vp->v_usecount ));
        !          3605: 
        !          3606:        /*
        !          3607:         * Ignore nodes related to stale file handles.
        !          3608:         */
        !          3609:        if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
        !          3610:                goto out;
        !          3611:        
        !          3612:        /*
        !          3613:         * Check for a postponed deletion
        !          3614:         */
        !          3615:        if (hp->h_meta->h_metaflags & IN_DELETED) {                     
        !          3616:                hp->h_meta->h_metaflags &= ~IN_DELETED;
        !          3617: 
        !          3618:                error = vinvalbuf(vp, 0, NOCRED, p, 0, 0);
        !          3619:                if (error) goto out;
        !          3620: 
        !          3621:                /* Lock both trees
        !          3622:                 * Note: we do not need a lock on the private metadata directory
        !          3623:                 * since it never has a vnode associated with it.
        !          3624:                 */
        !          3625:         error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
        !          3626:         if (error) goto out;
        !          3627:         error = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, p);
        !          3628:         if (error) {
        !          3629:             (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          3630:             goto out;
        !          3631:         }
        !          3632: 
        !          3633:                /* XXX can we leave orphaned sibling? */        
        !          3634:                error = hfsDelete(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp));
        !          3635:                if (error == ENOENT) {
        !          3636:                        /* try by fileID as a backup */
        !          3637:                        error = hfsDelete(HTOVCB(hp), H_FILEID(hp), NULL, TRUE, H_HINT(hp));
        !          3638:                }       
        !          3639:         (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
        !          3640:                (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
        !          3641:                if (error) goto out;
        !          3642: 
        !          3643: #if MACH_NBC
        !          3644:                        if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
        !          3645: #endif /* MACH_NBC */
        !          3646:                        vnode_pager_setsize(vp, 0);
        !          3647: #if MACH_NBC
        !          3648:                        }
        !          3649: #endif /* MACH_NBC */
        !          3650:        
        !          3651:                hp->h_meta->h_mode = 0;
        !          3652:            hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          3653:        }
        !          3654: 
        !          3655:        if (hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
        !          3656:                tv = time;
        !          3657:                VOP_UPDATE(vp, &tv, &tv, 0);
        !          3658:        }
        !          3659: 
        !          3660: out:
        !          3661:        VOP_UNLOCK(vp, 0, p);
        !          3662:        /*
        !          3663:         * If we are done with the inode, reclaim it
        !          3664:         * so that it can be reused immediately.
        !          3665:         */
        !          3666:        if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
        !          3667:                vrecycle(vp, (struct slock *)0, p);
        !          3668:        
        !          3669:        /* XXX SER Here we might want to get rid of any other forks
        !          3670:         * The problem is that if we call vrecycle(), our structure
        !          3671:         * disappear from under us, we would need to remember, and expect
        !          3672:         * things to go to null or to disappear
        !          3673:         * But it stillw would be a good thing to remove vnodes
        !          3674:         * referencing stale data
        !          3675:                 */
        !          3676: 
        !          3677:        DBG_VOP_LOCKS_TEST(E_NONE);
        !          3678:        return (E_NONE);
        !          3679: }
        !          3680: 
        !          3681: /*
        !          3682:  Ignored since the locks are gone......
        !          3683: #% reclaim     vp      U I I
        !          3684: #
        !          3685:  vop_reclaim {
        !          3686:         IN struct vnode *vp;
        !          3687:         IN struct proc *p;
        !          3688: 
        !          3689:         */
        !          3690: 
        !          3691: static int
        !          3692: hfs_reclaim(ap)
        !          3693: struct vop_reclaim_args /* {
        !          3694:        struct vnode *a_vp;
        !          3695: } */ *ap;
        !          3696: {
        !          3697:        struct vnode    *vp = ap->a_vp;
        !          3698:        struct hfsnode  *hp = VTOH(vp);
        !          3699:        void                    *tdata = vp->v_data;
        !          3700:        char                    *tname;
        !          3701:        Boolean                 freeMeta = true;
        !          3702:        struct vnode    *devvp = NULL;
        !          3703:        
        !          3704:        extern int prtactive;
        !          3705:        DBG_FUNC_NAME("reclaim");
        !          3706:        DBG_VOP_LOCKS_DECL(1);
        !          3707:        DBG_VOP_PRINT_FUNCNAME();
        !          3708:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          3709: 
        !          3710:        DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
        !          3711: 
        !          3712:        /*
        !          3713:                NOTE: XXX vnodes need careful handling because fork vnodes that failed to be
        !          3714:                          created in their entirity could be getting cleaned up here, in which
        !          3715:                          case v_type == VNON and h_meta == NULL... (when????)
        !          3716:         */
        !          3717: 
        !          3718:        if (prtactive && vp->v_usecount != 0)
        !          3719:                vprint("hfs_reclaim(): pushing active", vp);
        !          3720: 
        !          3721:        hp->h_nodeflags |= IN_ALLOCATING;       /* Mark this as being incomplete */
        !          3722:                        /*
        !          3723:         * This will remove the entry from the hash AND the sibling list
        !          3724:         * This will make sure everything is in a stable state to see if we can remove the meta
        !          3725:         * i.e. if this is the only fork...the sibling list will be empty
        !          3726:                         */
        !          3727:        hfs_vhashrem(hp);       
        !          3728: 
        !          3729:        DBG_ASSERT(tdata != NULL);
        !          3730:        DBG_ASSERT(hp->h_meta != NULL);
        !          3731:    
        !          3732:        devvp = hp->h_meta->h_devvp;            /* For later releasing */
        !          3733:        hp->h_meta->h_usecount--;       
        !          3734: 
        !          3735:        /* release the file meta if this is the last fork */
        !          3736:     if (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork) {
        !          3737:        if (hp->h_meta->h_siblinghead.cqh_first != (void *) &hp->h_meta->h_siblinghead)
        !          3738:                        freeMeta = false;
        !          3739:        };
        !          3740: 
        !          3741:     if (freeMeta) {
        !          3742:                DBG_ASSERT(hp->h_meta->h_usecount == 0);
        !          3743:                if (hp->h_meta->h_metaflags & IN_LONGNAME) {
        !          3744:                        tname = H_NAME(hp);
        !          3745:                        DBG_ASSERT(tname != NULL);
        !          3746:                        FREE(tname, M_TEMP);
        !          3747:                        }
        !          3748:                  FREE(hp->h_meta, M_HFSFMETA);
        !          3749:                  hp->h_meta = NULL;
        !          3750:            }
        !          3751:        else
        !          3752:                DBG_ASSERT(hp->h_meta->h_usecount == 1);
        !          3753:                
        !          3754:    
        !          3755: 
        !          3756:        /*
        !          3757:         * Purge old data structures associated with the inode.
        !          3758:         */
        !          3759:        cache_purge(vp);
        !          3760:        if ((vp->v_type != VNON) && devvp) {
        !          3761:                VRELE(devvp);
        !          3762:        };
        !          3763: 
        !          3764:        /* Free our data structs */
        !          3765:        if (vp->v_type != VNON) {
        !          3766:                FREE(tdata, M_HFSNODE);
        !          3767:                vp->v_data = NULL;
        !          3768:        };
        !          3769: 
        !          3770:        DBG_VOP_LOCKS_TEST(E_NONE);
        !          3771:        return (E_NONE);
        !          3772: }
        !          3773: 
        !          3774: 
        !          3775: /*
        !          3776:  * Lock an hfsnode. If its already locked, set the WANT bit and sleep.
        !          3777: #% lock                vp      U L U
        !          3778: #
        !          3779:  vop_lock {
        !          3780:      IN struct vnode *vp;
        !          3781:      IN int flags;
        !          3782:      IN struct proc *p;
        !          3783:      */
        !          3784: 
        !          3785: static int
        !          3786: hfs_lock(ap)
        !          3787: struct vop_lock_args /* {
        !          3788:     struct vnode *a_vp;
        !          3789:     int a_flags;
        !          3790:     struct proc *a_p;
        !          3791: } */ *ap;
        !          3792: {
        !          3793:        struct vnode * vp = ap->a_vp;
        !          3794:        struct hfsnode *hp = VTOH(ap->a_vp);
        !          3795:        int                     retval;
        !          3796: 
        !          3797:        DBG_FUNC_NAME("lock");
        !          3798:        DBG_VOP_LOCKS_DECL(1);
        !          3799:        DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" "));
        !          3800:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
        !          3801:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
        !          3802: 
        !          3803:        retval = lockmgr(&hp->h_lock, ap->a_flags, &vp->v_interlock, ap->a_p);
        !          3804:        if (retval != E_NONE) {
        !          3805:                if ((ap->a_flags & LK_NOWAIT) == 0)
        !          3806:                        DBG_ERR(("hfs_lock: error %d trying to lock vnode (flags = 0x%08X).\n", retval, ap->a_flags));
        !          3807:                goto Err_Exit;
        !          3808:        };
        !          3809: 
        !          3810: Err_Exit:;
        !          3811:        DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
        !          3812:        DBG_VOP_LOCKS_TEST(retval);
        !          3813:        return (retval);
        !          3814: }
        !          3815: 
        !          3816: /*
        !          3817:  * Unlock an hfsnode.
        !          3818: #% unlock      vp      L U L
        !          3819: #
        !          3820:  vop_unlock {
        !          3821:      IN struct vnode *vp;
        !          3822:      IN int flags;
        !          3823:      IN struct proc *p;
        !          3824: 
        !          3825:      */
        !          3826: int
        !          3827: hfs_unlock(ap)
        !          3828: struct vop_unlock_args /* {
        !          3829:     struct vnode *a_vp;
        !          3830:     int a_flags;
        !          3831:     struct proc *a_p;
        !          3832: } */ *ap;
        !          3833: {
        !          3834:        struct hfsnode *hp = VTOH(ap->a_vp);
        !          3835:        struct vnode *vp = ap->a_vp;
        !          3836:        int             retval = E_NONE;
        !          3837: 
        !          3838:        DBG_FUNC_NAME("unlock");
        !          3839:        DBG_VOP_LOCKS_DECL(1);
        !          3840:        DBG_VOP_PRINT_FUNCNAME();
        !          3841:        DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
        !          3842:        DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
        !          3843: 
        !          3844: 
        !          3845:        DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0);
        !          3846:        retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p);
        !          3847:        if (retval != E_NONE) {
        !          3848:                DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock vnode (forktype = %d).\n", retval, H_FORKTYPE(hp)));
        !          3849:        };
        !          3850: 
        !          3851:        DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
        !          3852:        DBG_VOP_LOCKS_TEST(retval);
        !          3853:        return (retval);
        !          3854: }
        !          3855: 
        !          3856: 
        !          3857: /*
        !          3858:  * Print out the contents of an hfsnode.
        !          3859: #% print       vp      = = =
        !          3860: #
        !          3861:  vop_print {
        !          3862:      IN struct vnode *vp;
        !          3863:      */
        !          3864: int
        !          3865: hfs_print(ap)
        !          3866: struct vop_print_args /* {
        !          3867:     struct vnode *a_vp;
        !          3868: } */ *ap;
        !          3869: {
        !          3870:        register struct vnode * vp = ap->a_vp;
        !          3871:        register struct hfsnode *hp = VTOH( vp);
        !          3872:        DBG_FUNC_NAME("print");
        !          3873:        DBG_VOP_LOCKS_DECL(1);
        !          3874:        DBG_VOP_PRINT_FUNCNAME();
        !          3875:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
        !          3876: 
        !          3877:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !          3878: 
        !          3879:        printf("tag VT_HFS, dirID %d, on dev %d, %d", H_DIRID(hp),
        !          3880:                   major(H_DEV(hp)), minor(H_DEV(hp)));
        !          3881:        /* lockmgr_printinfo(&hp->h_lock); */
        !          3882:        printf("\n");
        !          3883:        DBG_VOP_LOCKS_TEST(E_NONE);
        !          3884:        return (E_NONE);
        !          3885: }
        !          3886: 
        !          3887: 
        !          3888: /*
        !          3889:  * Check for a locked hfsnode.
        !          3890: #% islocked    vp      = = =
        !          3891: #
        !          3892:  vop_islocked {
        !          3893:      IN struct vnode *vp;
        !          3894: 
        !          3895:      */
        !          3896: int
        !          3897: hfs_islocked(ap)
        !          3898: struct vop_islocked_args /* {
        !          3899:     struct vnode *a_vp;
        !          3900: } */ *ap;
        !          3901: {
        !          3902:     int                lockStatus;
        !          3903:     //DBG_FUNC_NAME("islocked");
        !          3904:     //DBG_VOP_LOCKS_DECL(1);
        !          3905:     //DBG_VOP_PRINT_FUNCNAME();
        !          3906:     //DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
        !          3907: 
        !          3908:     //DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
        !          3909: 
        !          3910:     lockStatus = lockstatus(&VTOH( ap->a_vp)->h_lock);
        !          3911:     //DBG_VOP_LOCKS_TEST(E_NONE);
        !          3912:     return (lockStatus);
        !          3913: }
        !          3914: 
        !          3915: /*
        !          3916: 
        !          3917: #% pathconf    vp      L L L
        !          3918: #
        !          3919:  vop_pathconf {
        !          3920:      IN struct vnode *vp;
        !          3921:      IN int name;
        !          3922:      OUT register_t *retval;
        !          3923: 
        !          3924:      */
        !          3925: static int
        !          3926: hfs_pathconf(ap)
        !          3927: struct vop_pathconf_args /* {
        !          3928:     struct vnode *a_vp;
        !          3929:     int a_name;
        !          3930:     int *a_retval;
        !          3931: } */ *ap;
        !          3932: {
        !          3933:     int retval = E_NONE;
        !          3934:     DBG_FUNC_NAME("pathconf");
        !          3935:     DBG_VOP_LOCKS_DECL(1);
        !          3936:     DBG_VOP_PRINT_FUNCNAME();
        !          3937:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
        !          3938: 
        !          3939:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          3940: 
        !          3941:     DBG_HFS_NODE_CHECK (ap->a_vp);
        !          3942: 
        !          3943:     switch (ap->a_name) {
        !          3944:         case _PC_LINK_MAX:
        !          3945: #if HFS_HARDLINKS
        !          3946:        if (VTOVCB(ap->a_vp)->vcbSigWord == kHFSPlusSigWord)
        !          3947:                *ap->a_retval = HFS_LINK_MAX;
        !          3948:        else
        !          3949:                *ap->a_retval = 1;
        !          3950: #else
        !          3951:        *ap->a_retval = 1;
        !          3952: #endif
        !          3953:             break;
        !          3954:         case _PC_NAME_MAX:
        !          3955:             *ap->a_retval = (kHFSPlusMaxFileNameChars * 3);    /* max # of characters x max utf8 representation */
        !          3956:             break;
        !          3957:         case _PC_PATH_MAX:
        !          3958:             *ap->a_retval = PATH_MAX; /* 1024 */
        !          3959:             break;
        !          3960:         case _PC_CHOWN_RESTRICTED:
        !          3961:             *ap->a_retval = 1;
        !          3962:             break;
        !          3963:         case _PC_NO_TRUNC:
        !          3964:             *ap->a_retval = 0;
        !          3965:             break;
        !          3966:         default:
        !          3967:             retval = EINVAL;
        !          3968:     }
        !          3969: 
        !          3970:     DBG_VOP_LOCKS_TEST(retval);
        !          3971:     return (retval);
        !          3972: }
        !          3973: 
        !          3974: 
        !          3975: 
        !          3976: 
        !          3977: 
        !          3978: /*
        !          3979:  * Advisory record locking support
        !          3980: #% advlock     vp      U U U
        !          3981: #
        !          3982:  vop_advlock {
        !          3983:      IN struct vnode *vp;
        !          3984:      IN caddr_t id;
        !          3985:      IN int op;
        !          3986:      IN struct flock *fl;
        !          3987:      IN int flags;
        !          3988: 
        !          3989:      */
        !          3990: int
        !          3991: hfs_advlock(ap)
        !          3992: struct vop_advlock_args /* {
        !          3993:     struct vnode *a_vp;
        !          3994:     caddr_t  a_id;
        !          3995:     int  a_op;
        !          3996:     struct flock *a_fl;
        !          3997:     int  a_flags;
        !          3998: } */ *ap;
        !          3999: {
        !          4000:     register struct hfsnode *hp = VTOH(ap->a_vp);
        !          4001:     register struct flock *fl = ap->a_fl;
        !          4002:     register struct hfslockf *lock;
        !          4003:     off_t start, end;
        !          4004:     int retval;
        !          4005:     DBG_FUNC_NAME("advlock");
        !          4006:     DBG_VOP_LOCKS_DECL(1);
        !          4007:     DBG_VOP_PRINT_FUNCNAME();
        !          4008:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
        !          4009:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !          4010:     /*
        !          4011:      * Avoid the common case of unlocking when inode has no locks.
        !          4012:      */
        !          4013:     if (hp->h_lockf == (struct hfslockf *)0) {
        !          4014:         if (ap->a_op != F_SETLK) {
        !          4015:             fl->l_type = F_UNLCK;
        !          4016:             return (0);
        !          4017:         }
        !          4018:     }
        !          4019:     /*
        !          4020:      * Convert the flock structure into a start and end.
        !          4021:      */
        !          4022:     start = 0;
        !          4023:     switch (fl->l_whence) {
        !          4024:         case SEEK_SET:
        !          4025:         case SEEK_CUR:
        !          4026:             /*
        !          4027:              * Caller is responsible for adding any necessary offset
        !          4028:              * when SEEK_CUR is used.
        !          4029:              */
        !          4030:             start = fl->l_start;
        !          4031:             break;
        !          4032: 
        !          4033:         case SEEK_END:
        !          4034:             start = HTOFCB(hp)->fcbEOF + fl->l_start;
        !          4035:             break;
        !          4036: 
        !          4037:         default:
        !          4038:             return (EINVAL);
        !          4039:     }
        !          4040: 
        !          4041:     if (start < 0)
        !          4042:         return (EINVAL);
        !          4043:     if (fl->l_len == 0)
        !          4044:         end = -1;
        !          4045:     else
        !          4046:         end = start + fl->l_len - 1;
        !          4047: 
        !          4048:     /*
        !          4049:      * Create the hfslockf structure
        !          4050:      */
        !          4051:     MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK);
        !          4052:     lock->lf_start = start;
        !          4053:     lock->lf_end = end;
        !          4054:     lock->lf_id = ap->a_id;
        !          4055:     lock->lf_hfsnode = hp;
        !          4056:     lock->lf_type = fl->l_type;
        !          4057:     lock->lf_next = (struct hfslockf *)0;
        !          4058:     TAILQ_INIT(&lock->lf_blkhd);
        !          4059:     lock->lf_flags = ap->a_flags;
        !          4060:     /*
        !          4061:      * Do the requested operation.
        !          4062:      */
        !          4063:     switch(ap->a_op) {
        !          4064:         case F_SETLK:
        !          4065:             retval = hfs_setlock(lock);
        !          4066:             break;
        !          4067: 
        !          4068:         case F_UNLCK:
        !          4069:             retval = hfs_clearlock(lock);
        !          4070:             FREE(lock, M_LOCKF);
        !          4071:             break;
        !          4072: 
        !          4073:         case F_GETLK:
        !          4074:             retval = hfs_getlock(lock, fl);
        !          4075:             FREE(lock, M_LOCKF);
        !          4076:             break;
        !          4077: 
        !          4078:         default:
        !          4079:             retval = EINVAL;
        !          4080:             _FREE(lock, M_LOCKF);
        !          4081:             break;
        !          4082:     }
        !          4083: 
        !          4084:     DBG_VOP_LOCKS_TEST(retval);
        !          4085:     return (retval);
        !          4086: }
        !          4087: 
        !          4088: 
        !          4089: 
        !          4090: /*
        !          4091:  * Update the access, modified, and node change times as specified by the
        !          4092:  * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
        !          4093:  * used to specify that the node needs to be updated but that the times have
        !          4094:  * already been set. The access and modified times are taken from the second
        !          4095:  * and third parameters; the node change time is always taken from the current
        !          4096:  * time. If waitfor is set, then wait for the disk write of the node to
        !          4097:  * complete.
        !          4098:  */
        !          4099: /*
        !          4100: #% update      vp      L L L
        !          4101:        IN struct vnode *vp;
        !          4102:        IN struct timeval *access;
        !          4103:        IN struct timeval *modify;
        !          4104:        IN int waitfor;
        !          4105: */
        !          4106: 
        !          4107: int
        !          4108: hfs_update(ap)
        !          4109:        struct vop_update_args /* {
        !          4110:                struct vnode *a_vp;
        !          4111:                struct timeval *a_access;
        !          4112:                struct timeval *a_modify;
        !          4113:                int a_waitfor;
        !          4114:        } */ *ap;
        !          4115: {
        !          4116:        struct hfsnode  *hp;
        !          4117:        struct proc             *p;
        !          4118:        hfsCatalogInfo  catInfo;
        !          4119:        char                    *filename;
        !          4120:        u_int32_t               pid;
        !          4121:        int                             retval;
        !          4122:        ExtendedVCB *vcb;
        !          4123:        DBG_FUNC_NAME("update");
        !          4124:        DBG_VOP_LOCKS_DECL(1);
        !          4125:        DBG_VOP_PRINT_FUNCNAME();
        !          4126:        DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          4127:        DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
        !          4128: 
        !          4129:        hp = VTOH(ap->a_vp);
        !          4130: 
        !          4131:        DBG_ASSERT(hp && hp->h_meta);
        !          4132:        DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
        !          4133: 
        !          4134:        if ((H_FORKTYPE(hp) == kSysFile) ||
        !          4135:            (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) ||
        !          4136:            (hp->h_meta->h_mode == 0)) {
        !          4137:                hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          4138:                DBG_VOP_LOCKS_TEST(0);
        !          4139:                return (0);
        !          4140:        }
        !          4141: 
        !          4142:     if (H_FORKTYPE(hp) == kSysFile) {
        !          4143:         hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          4144:         DBG_VOP_LOCKS_TEST(0);
        !          4145:         return (0);
        !          4146:     }
        !          4147: 
        !          4148:     if (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) {
        !          4149:         hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          4150:         DBG_VOP_LOCKS_TEST(0);
        !          4151:         DBG_VOP(("hfs_update: returning 0 (all flags were cleared because the volume is read-only.\n"));
        !          4152:         return (0);
        !          4153:     }
        !          4154:        
        !          4155:     /* Check to see if MacOS set the fcb to be dirty, if so, translate it to IN_MODIFIED */
        !          4156:     if (HTOFCB(hp)->fcbFlags &fcbModifiedMask)
        !          4157:         hp->h_nodeflags |= IN_MODIFIED;
        !          4158: 
        !          4159:     if ((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) {
        !          4160:         DBG_VOP_LOCKS_TEST(0);
        !          4161:         DBG_VOP(("hfs_update: returning 0 because the metadata is unchanged.\n"));
        !          4162:         return (0);
        !          4163:     };
        !          4164: 
        !          4165:        if (hp->h_nodeflags & IN_ACCESS)
        !          4166:                hp->h_meta->h_atime = ap->a_access->tv_sec;
        !          4167:        if (hp->h_nodeflags & IN_UPDATE)
        !          4168:                hp->h_meta->h_mtime = ap->a_modify->tv_sec;
        !          4169:        if (hp->h_nodeflags & IN_CHANGE) {
        !          4170:                hp->h_meta->h_ctime = time.tv_sec;
        !          4171:                /*
        !          4172:                 * HFS dates that WE set must be adjusted for DST
        !          4173:                 */
        !          4174:                if ((HTOVCB(hp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) {
        !          4175:                        hp->h_meta->h_ctime += 3600;
        !          4176:                        hp->h_meta->h_mtime = hp->h_meta->h_ctime;
        !          4177:                }
        !          4178:        }
        !          4179: 
        !          4180:        p = current_proc();
        !          4181:        /*
        !          4182:         * Since VOP_UPDATE can be called from withing another VOP (eg VOP_RENAME),
        !          4183:         * the Catalog b-tree may aready be locked by the current thread. So we
        !          4184:         * allow recursive locking of the Catalog from within VOP_UPDATE.
        !          4185:         */
        !          4186: 
        !          4187:        /* Lock the Catalog b-tree file */
        !          4188:        retval = hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p);
        !          4189:        if (retval) {
        !          4190:                DBG_ERR(("Could not lock catalog tree"));
        !          4191:         DBG_VOP_LOCKS_TEST(retval);
        !          4192:         DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
        !          4193:         return (retval);
        !          4194:     };
        !          4195:     DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
        !          4196: 
        !          4197:        filename = H_NAME(hp);
        !          4198:        pid = H_DIRID(hp);
        !          4199: 
        !          4200: #if HFS_HARDLINKS
        !          4201:        /*
        !          4202:         * Force an update of the data node instead of the link node
        !          4203:         * by passing the fileID instead of parID and name.
        !          4204:         */
        !          4205:        if (hp->h_meta->h_metaflags & IN_DATANODE) {
        !          4206:                filename = NULL;
        !          4207:                pid = H_FILEID(hp);
        !          4208:        }
        !          4209: #endif
        !          4210:        vcb = HTOVCB(hp);
        !          4211:        catInfo.hint = H_HINT(hp);
        !          4212:        retval = hfsLookup(vcb, pid, filename, -1, &catInfo);
        !          4213: 
        !          4214:        H_HINT(hp) = catInfo.hint;
        !          4215:        if (retval != noErr) {
        !          4216:                DBG_ERR(("hfs_update: error %d on GetCatalogNode...\n", retval));
        !          4217:                goto exit_relse;
        !          4218:        };
        !          4219: 
        !          4220:        CopyVNodeToCatalogNode (HTOV(hp), &catInfo.nodeData);
        !          4221: 
        !          4222:        retval = UpdateCatalogNode(vcb, pid, filename, H_HINT(hp), &catInfo.nodeData);
        !          4223: 
        !          4224:     if (retval != noErr) {
        !          4225:                DBG_ERR(("hfs_update: error %d on UpdateCatalogNode...\n", retval));
        !          4226:         retval = MacToVFSError(retval);
        !          4227:         goto exit_relse;
        !          4228:     };
        !          4229: 
        !          4230:        /* After the updates are finished, clear the flags */
        !          4231:        hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !          4232:        HTOFCB(hp)->fcbFlags &= ~fcbModifiedMask;
        !          4233: 
        !          4234:        /* Update general data */
        !          4235:     if (ap->a_vp->v_type == VDIR) {
        !          4236:                hp->h_meta->h_valence = catInfo.nodeData.cnd_valence;
        !          4237:                hp->h_meta->h_size = sizeof(rootdots) + 
        !          4238:                        (catInfo.nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE);
        !          4239:                if (hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE)
        !          4240:                        hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE;
        !          4241:        } else {
        !          4242:                hp->h_meta->h_size = vcb->blockSize *
        !          4243:                    (catInfo.nodeData.cnd_rsrcfork.totalBlocks +
        !          4244:                     catInfo.nodeData.cnd_datafork.totalBlocks);
        !          4245:        }
        !          4246: 
        !          4247: 
        !          4248: exit_relse:    
        !          4249:         /* unlock the Catalog b-tree file */
        !          4250:        (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p);
        !          4251: 
        !          4252:     DBG_VOP(("hfs_update: returning %d.\n", retval));
        !          4253:     DBG_VOP_LOCKS_TEST(retval);
        !          4254:     DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
        !          4255:        return (retval);
        !          4256: }
        !          4257: 
        !          4258: 
        !          4259: /*
        !          4260:  * Initialize the vnode associated with a new hfsnode, 
        !          4261:  * handle aliased vnodes.
        !          4262:  */
        !          4263: int
        !          4264: hfs_vinit(mntp, specops, fifoops, vpp)
        !          4265:        struct mount *mntp;
        !          4266:        int (**specops)();
        !          4267:        int (**fifoops)();
        !          4268:        struct vnode **vpp;
        !          4269: {
        !          4270:        struct hfsnode *hp;
        !          4271:        struct vnode *vp, *nvp;
        !          4272: 
        !          4273:        vp = *vpp;
        !          4274:        hp = VTOH(vp);
        !          4275:        /* vp->v_type set in CopyCatalogToHFSNode */ 
        !          4276:        switch(vp->v_type) {
        !          4277:        case VCHR:
        !          4278:        case VBLK:
        !          4279:                vp->v_op = specops;
        !          4280:                if ((nvp = checkalias(vp, hp->h_meta->h_rdev, mntp))) {
        !          4281:                        /*
        !          4282:                         * Discard unneeded vnode, but save its hfsnode.
        !          4283:                         * Note that the lock is carried over in the hfsnode
        !          4284:                         * to the replacement vnode.
        !          4285:                         */
        !          4286:                        nvp->v_data = vp->v_data;
        !          4287:                        vp->v_data = NULL;
        !          4288:                        vp->v_op = spec_vnodeop_p;
        !          4289:                        VRELE(vp);
        !          4290:                        vgone(vp);
        !          4291:                        /*
        !          4292:                         * Reinitialize aliased hfsnode.
        !          4293:                         */
        !          4294: 
        !          4295:                        hp->h_vp = nvp;                         
        !          4296:                        vp = nvp;
        !          4297:                }
        !          4298:                break;
        !          4299:        case VFIFO:
        !          4300: #if FIFO
        !          4301:                vp->v_op = fifoops;
        !          4302:                break;
        !          4303: #else
        !          4304:                return (EOPNOTSUPP);
        !          4305: #endif
        !          4306:        default:
        !          4307:                break;
        !          4308:        }
        !          4309:        if (H_FILEID(hp) == kRootDirID)
        !          4310:                 vp->v_flag |= VROOT;
        !          4311: 
        !          4312:        *vpp = vp;
        !          4313:        return (0);
        !          4314: }
        !          4315: 
        !          4316: /*
        !          4317:  * Allocate a new node
        !          4318:  *
        !          4319:  * Assumes that the catalog b-tree is locked
        !          4320:  *
        !          4321:  * Upon leaving, namei buffer must be freed.
        !          4322:  *
        !          4323:  */
        !          4324: static int
        !          4325: hfs_makenode(mode, rawdev, dvp, vpp, cnp)
        !          4326:     int mode;
        !          4327:     dev_t rawdev;
        !          4328:     struct vnode *dvp;
        !          4329:     struct vnode **vpp;
        !          4330:     struct componentname *cnp;
        !          4331: {
        !          4332:     register struct hfsnode *hp, *parhp;
        !          4333:     struct timeval                     tv;
        !          4334:     struct vnode                       *tvp;
        !          4335:     struct hfsCatalogInfo      catInfo;
        !          4336:     ExtendedVCB                                *vcb;
        !          4337:     UInt8                                      forkType;
        !          4338:     int                                        retval;
        !          4339:     DBG_FUNC_NAME("makenode");
        !          4340: 
        !          4341:     parhp      = VTOH(dvp);
        !          4342:     vcb                = HTOVCB(parhp);
        !          4343:     *vpp       = NULL;
        !          4344:        tvp     = NULL;
        !          4345:     if ((mode & IFMT) == 0)
        !          4346:         mode |= IFREG;
        !          4347: 
        !          4348: #if HFS_DIAGNOSTIC
        !          4349:     if ((cnp->cn_flags & HASBUF) == 0)
        !          4350:         panic("hfs_makenode: no name");
        !          4351: #endif
        !          4352: 
        !          4353:     /* Create the Catalog B*-Tree entry */
        !          4354:     retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode);
        !          4355:     if (retval != E_NONE) {
        !          4356:         DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
        !          4357:         goto bad1;
        !          4358:     }
        !          4359: 
        !          4360:     /* Look up the catalog entry just created: */
        !          4361:        catInfo.hint = kNoHint;
        !          4362:     retval = hfsLookup(vcb, H_FILEID(parhp), cnp->cn_nameptr, cnp->cn_namelen, &catInfo);
        !          4363:     if (retval != E_NONE) {
        !          4364:         DBG_ERR(("%s: hfsLookup FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
        !          4365:         goto bad1;
        !          4366:     }
        !          4367: 
        !          4368:        /* hfs plus has additional metadata to initialize */
        !          4369:        if (vcb->vcbSigWord == kHFSPlusSigWord) {
        !          4370:                u_int32_t pflags;
        !          4371:                int catmode;
        !          4372:                
        !          4373:                catmode = mode;
        !          4374:                catInfo.nodeData.cnd_ownerID = cnp->cn_cred->cr_uid;
        !          4375:                catInfo.nodeData.cnd_groupID = parhp->h_meta->h_gid;
        !          4376:                /* XXX should we move this to post hfsGet? */
        !          4377:                catInfo.nodeData.cnd_specialDevice = rawdev;
        !          4378:                
        !          4379:                switch (catmode & IFMT) {
        !          4380:                case IFLNK:
        !          4381:                        catInfo.nodeData.cnd_ownerID = parhp->h_meta->h_uid;
        !          4382:                        break;
        !          4383: 
        !          4384:                case IFCHR:
        !          4385:                case IFBLK:
        !          4386:                        /*
        !          4387:                         * Don't tag as a special file (BLK or CHR) until *after*
        !          4388:                         * hfsGet is called.  This insures that the checkalias call
        !          4389:                         * is defered until hfs_mknod completes.
        !          4390:                         */
        !          4391:                        catmode = (catmode & ~IFMT) | IFREG;
        !          4392:                        break;
        !          4393:                }
        !          4394: 
        !          4395:                if ((catmode & ISGID) && !groupmember(parhp->h_meta->h_gid, cnp->cn_cred) &&
        !          4396:                        suser(cnp->cn_cred, NULL))
        !          4397:                        catmode &= ~ISGID;
        !          4398: 
        !          4399:                if (cnp->cn_flags & ISWHITEOUT)
        !          4400:                        pflags = UF_OPAQUE;
        !          4401:                else
        !          4402:                        pflags = 0;
        !          4403: 
        !          4404:                /*
        !          4405:                 * The 32-bit pflags field has two bytes of significance which are
        !          4406:                 * combined with the mode to yield a 32-bit permissions field as follows:
        !          4407:                 *
        !          4408:                 *              +------------------------------------+
        !          4409:                 * pflags:      |XXXXXXXX|    A    |XXXXXXXX|    B   |
        !          4410:                 *              +------------------------------------+
        !          4411:                 *                                          |
        !          4412:                 *                                          V
        !          4413:                 *              +------------------------------------+
        !          4414:                 * permissions: |    A    |    B   |      mode       |
        !          4415:                 *              +------------------------------------+
        !          4416:                 */
        !          4417:                catInfo.nodeData.cnd_permissions =
        !          4418:                        (((pflags << 8) & 0xFF000000) | /* A */
        !          4419:                        ((pflags << 16) & 0x00FF0000) | /* B */
        !          4420:                        (catmode & 0x0000FFFF));        /* mode */
        !          4421:        }
        !          4422: 
        !          4423:     /* Create a vnode for the object just created: */
        !          4424:     forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
        !          4425:     if ((retval = hfs_vcreate(vcb, &catInfo, forkType, &tvp))) {
        !          4426:         goto bad1;
        !          4427:     }
        !          4428: 
        !          4429:        /* flush out pflags, mode, gid, uid and rdev */
        !          4430:     tv = time;
        !          4431:     if (vcb->vcbSigWord == kHFSPlusSigWord) {
        !          4432:         hp = VTOH(tvp);
        !          4433:                /* reset mode and v_type in case it was BLK/CHR */
        !          4434:                hp->h_meta->h_mode = mode;
        !          4435:                tvp->v_type = IFTOVT(mode);
        !          4436:         hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
        !          4437:         hp->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
        !          4438:         if ((retval = VOP_UPDATE(tvp, &tv, &tv, 1)))
        !          4439:             goto bad2;
        !          4440:     }
        !          4441: 
        !          4442:        VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          4443:     if ((retval = VOP_UPDATE(dvp, &tv, &tv, 1)))
        !          4444:         goto bad2;
        !          4445: 
        !          4446:     if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
        !          4447:         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
        !          4448:     };
        !          4449:     VPUT(dvp);
        !          4450: #if MACH_NBC
        !          4451:     if ((tvp->v_type == VREG)  && !(tvp->v_vm_info)){
        !          4452:         vm_info_init(tvp);
        !          4453:     }
        !          4454: #endif /* MACH_NBC */
        !          4455:     *vpp = tvp;
        !          4456:     return (0);
        !          4457: 
        !          4458: bad2:
        !          4459:     /*
        !          4460:      * Write retval occurred trying to update the node
        !          4461:      * or the directory so must deallocate the node.
        !          4462:     */
        !          4463:     /* XXX SER In the future maybe set *vpp to 0xdeadbeef for testing */
        !          4464:     VPUT(tvp);
        !          4465: 
        !          4466: bad1:
        !          4467:     if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
        !          4468:         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
        !          4469:     };
        !          4470:     VPUT(dvp);
        !          4471: 
        !          4472:     return (retval);
        !          4473: 
        !          4474: }
        !          4475: 
        !          4476: 
        !          4477: #if DBG_VOP_TEST_LOCKS
        !          4478: 
        !          4479: /* XXX SER Add passing in the flags...might not be a serious error if locked */
        !          4480: 
        !          4481: void DbgVopTest( int maxSlots,
        !          4482:                  int retval,
        !          4483:                  VopDbgStoreRec *VopDbgStore,
        !          4484:                  char *funcname)
        !          4485: {
        !          4486:     int index;
        !          4487: 
        !          4488:     for (index = 0; index < maxSlots; index++)
        !          4489:       {
        !          4490:         if (VopDbgStore[index].id != index) {
        !          4491:             DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index));
        !          4492:         };
        !          4493: 
        !          4494:         if ((VopDbgStore[index].vp != NULL) &&
        !          4495:             ((VopDbgStore[index].vp->v_data==NULL) || (VTOH(VopDbgStore[index].vp)->h_valid != HFS_VNODE_MAGIC)))
        !          4496:             continue;
        !          4497: 
        !          4498:         if (VopDbgStore[index].vp != NULL)
        !          4499:             debug_check_vnode(VopDbgStore[index].vp, 0);
        !          4500: 
        !          4501:         switch (VopDbgStore[index].inState)
        !          4502:           {
        !          4503:             case VOPDBG_IGNORE:
        !          4504:             case VOPDBG_SAME:
        !          4505:                 /* Do Nothing !!! */
        !          4506:                 break;
        !          4507:             case VOPDBG_LOCKED:
        !          4508:             case VOPDBG_UNLOCKED:
        !          4509:             case VOPDBG_LOCKNOTNIL:
        !          4510:               {
        !          4511:                   if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
        !          4512:                       DBG_ERR (("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index));
        !          4513:                   } else if (VopDbgStore[index].vp != NULL) {
        !          4514:                       switch (VopDbgStore[index].inState)
        !          4515:                         {
        !          4516:                           case VOPDBG_LOCKED:
        !          4517:                           case VOPDBG_LOCKNOTNIL:
        !          4518:                               if (VopDbgStore[index].inValue == 0)
        !          4519:                                 {
        !          4520:                                   DBG_ERR (("%s: Entry: not LOCKED:", funcname));
        !          4521:                                   DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); 
        !          4522:                                   DBG_ERR (("\n"));
        !          4523:                                 }
        !          4524:                               break;
        !          4525:                           case VOPDBG_UNLOCKED:
        !          4526:                               if (VopDbgStore[index].inValue != 0)
        !          4527:                                 {
        !          4528:                                   DBG_ERR (("%s: Entry: not UNLOCKED:", funcname));
        !          4529:                                   DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
        !          4530:                                   DBG_ERR (("\n"));
        !          4531:                                 }
        !          4532:                               break;
        !          4533:                         }
        !          4534:                   }
        !          4535:                   break;
        !          4536:               }
        !          4537:             default:
        !          4538:                 DBG_ERR (("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
        !          4539:           }
        !          4540: 
        !          4541: 
        !          4542:         if (retval != 0)
        !          4543:           {
        !          4544:             switch (VopDbgStore[index].errState)
        !          4545:               {
        !          4546:                 case VOPDBG_IGNORE:
        !          4547:                     /* Do Nothing !!! */
        !          4548:                     break;
        !          4549:                 case VOPDBG_LOCKED:
        !          4550:                 case VOPDBG_UNLOCKED:
        !          4551:                 case VOPDBG_SAME:
        !          4552:                   {
        !          4553:                       if (VopDbgStore[index].vp == NULL) {
        !          4554:                           DBG_ERR (("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index));
        !          4555:                       } else {
        !          4556:                           VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
        !          4557:                           switch (VopDbgStore[index].errState)
        !          4558:                             {
        !          4559:                               case VOPDBG_LOCKED:
        !          4560:                                   if (VopDbgStore[index].outValue == 0)
        !          4561:                                     {
        !          4562:                                       DBG_ERR (("%s: Error: not LOCKED:", funcname));
        !          4563:                                       DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); 
        !          4564:                                       DBG_ERR(("\n"));
        !          4565:                                    }
        !          4566:                                   break;
        !          4567:                               case VOPDBG_UNLOCKED:
        !          4568:                                   if (VopDbgStore[index].outValue != 0)
        !          4569:                                     {
        !          4570:                                       DBG_ERR (("%s: Error: not UNLOCKED:", funcname));
        !          4571:                                       DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); 
        !          4572:                                       DBG_ERR(("\n"));
        !          4573:                                     }
        !          4574:                                   break;
        !          4575:                               case VOPDBG_SAME:
        !          4576:                                   if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
        !          4577:                                       DBG_ERR (("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue));
        !          4578:                                   break;
        !          4579:                             }
        !          4580:                       }
        !          4581:                       break;
        !          4582:                   }
        !          4583:                 case VOPDBG_LOCKNOTNIL:
        !          4584:                     if (VopDbgStore[index].vp != NULL) {
        !          4585:                         VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
        !          4586:                         if (VopDbgStore[index].outValue == 0)
        !          4587:                             DBG_ERR (("%s: Error: Not LOCKED: 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
        !          4588:                     }
        !          4589:                     break;
        !          4590:                 default:
        !          4591:                     DBG_ERR (("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
        !          4592:               }
        !          4593:           }
        !          4594:         else
        !          4595:           {
        !          4596:             switch (VopDbgStore[index].outState)
        !          4597:               {
        !          4598:                 case VOPDBG_IGNORE:
        !          4599:                     /* Do Nothing !!! */
        !          4600:                     break;
        !          4601:                 case VOPDBG_LOCKED:
        !          4602:                 case VOPDBG_UNLOCKED:
        !          4603:                 case VOPDBG_SAME:
        !          4604:                     if (VopDbgStore[index].vp == NULL) {
        !          4605:                         DBG_ERR (("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index));
        !          4606:                     };
        !          4607:                     if (VopDbgStore[index].vp != NULL)
        !          4608:                       {
        !          4609:                         VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
        !          4610:                         switch (VopDbgStore[index].outState)
        !          4611:                           {
        !          4612:                             case VOPDBG_LOCKED:
        !          4613:                                 if (VopDbgStore[index].outValue == 0)
        !          4614:                                   {
        !          4615:                                     DBG_ERR (("%s: Out: not LOCKED:", funcname));
        !          4616:                                     DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); 
        !          4617:                                     DBG_ERR (("\n"));
        !          4618:                                  }
        !          4619:                                 break;
        !          4620:                             case VOPDBG_UNLOCKED:
        !          4621:                                 if (VopDbgStore[index].outValue != 0)
        !          4622:                                   {
        !          4623:                                     DBG_ERR (("%s: Out: not UNLOCKED:", funcname));
        !          4624:                                     DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); 
        !          4625:                                     DBG_ERR (("\n"));
        !          4626:                                   }
        !          4627:                                 break;
        !          4628:                             case VOPDBG_SAME:
        !          4629:                                 if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
        !          4630:                                     DBG_ERR (("%s: Out: In/Out locks are DIFFERENT: 0x%x, in is %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue));
        !          4631:                                 break;
        !          4632:                           }
        !          4633:                       }
        !          4634:                     break;
        !          4635:                 case VOPDBG_LOCKNOTNIL:
        !          4636:                     if (VopDbgStore[index].vp != NULL) {
        !          4637:                         if (&VTOH(VopDbgStore[index].vp)->h_lock == NULL) {
        !          4638:                             DBG_ERR (("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
        !          4639:                         }
        !          4640:                         else {
        !          4641:                             VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
        !          4642:                             if (VopDbgStore[index].outValue == 0)
        !          4643:                               {
        !          4644:                                 DBG_ERR (("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname));
        !          4645:                                 DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); DBG_ERR (("\n"));
        !          4646:                               }
        !          4647:                         }
        !          4648:                     }
        !          4649:                     break;
        !          4650:                 default:
        !          4651:                     DBG_ERR (("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState));
        !          4652:               }
        !          4653:           }
        !          4654: 
        !          4655:         VopDbgStore[index].id = -1;            /* Invalidate the entry to allow panic-free re-use */
        !          4656:       }        
        !          4657: }
        !          4658: 
        !          4659: #endif /* DBG_VOP_TEST_LOCKS */
        !          4660: 
        !          4661: /*
        !          4662:  * Wrapper for special device reads
        !          4663:  */
        !          4664: int
        !          4665: hfsspec_read(ap)
        !          4666:        struct vop_read_args /* {
        !          4667:                struct vnode *a_vp;
        !          4668:                struct uio *a_uio;
        !          4669:                int  a_ioflag;
        !          4670:                struct ucred *a_cred;
        !          4671:        } */ *ap;
        !          4672: {
        !          4673: 
        !          4674:        /*
        !          4675:         * Set access flag.
        !          4676:         */
        !          4677:        VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS;
        !          4678:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
        !          4679: }
        !          4680: 
        !          4681: /*
        !          4682:  * Wrapper for special device writes
        !          4683:  */
        !          4684: int
        !          4685: hfsspec_write(ap)
        !          4686:        struct vop_write_args /* {
        !          4687:                struct vnode *a_vp;
        !          4688:                struct uio *a_uio;
        !          4689:                int  a_ioflag;
        !          4690:                struct ucred *a_cred;
        !          4691:        } */ *ap;
        !          4692: {
        !          4693: 
        !          4694:        /*
        !          4695:         * Set update and change flags.
        !          4696:         */
        !          4697:        VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          4698:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
        !          4699: }
        !          4700: 
        !          4701: /*
        !          4702:  * Wrapper for special device close
        !          4703:  *
        !          4704:  * Update the times on the hfsnode then do device close.
        !          4705:  */
        !          4706: int
        !          4707: hfsspec_close(ap)
        !          4708:        struct vop_close_args /* {
        !          4709:                struct vnode *a_vp;
        !          4710:                int  a_fflag;
        !          4711:                struct ucred *a_cred;
        !          4712:                struct proc *a_p;
        !          4713:        } */ *ap;
        !          4714: {
        !          4715:        struct vnode *vp = ap->a_vp;
        !          4716:        struct hfsnode *hp = VTOH(vp);
        !          4717: 
        !          4718:        simple_lock(&vp->v_interlock);
        !          4719:        if (ap->a_vp->v_usecount > 1)
        !          4720:                HFSTIMES(hp, &time, &time);
        !          4721:        simple_unlock(&vp->v_interlock);
        !          4722:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
        !          4723: }
        !          4724: 
        !          4725: #if FIFO
        !          4726: /*
        !          4727:  * Wrapper for fifo reads
        !          4728:  */
        !          4729: int
        !          4730: hfsfifo_read(ap)
        !          4731:        struct vop_read_args /* {
        !          4732:                struct vnode *a_vp;
        !          4733:                struct uio *a_uio;
        !          4734:                int  a_ioflag;
        !          4735:                struct ucred *a_cred;
        !          4736:        } */ *ap;
        !          4737: {
        !          4738:        extern int (**fifo_vnodeop_p)();
        !          4739: 
        !          4740:        /*
        !          4741:         * Set access flag.
        !          4742:         */
        !          4743:        VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS;
        !          4744:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
        !          4745: }
        !          4746: 
        !          4747: /*
        !          4748:  * Wrapper for fifo writes
        !          4749:  */
        !          4750: int
        !          4751: hfsfifo_write(ap)
        !          4752:        struct vop_write_args /* {
        !          4753:                struct vnode *a_vp;
        !          4754:                struct uio *a_uio;
        !          4755:                int  a_ioflag;
        !          4756:                struct ucred *a_cred;
        !          4757:        } */ *ap;
        !          4758: {
        !          4759:        extern int (**fifo_vnodeop_p)();
        !          4760: 
        !          4761:        /*
        !          4762:         * Set update and change flags.
        !          4763:         */
        !          4764:        VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          4765:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
        !          4766: }
        !          4767: 
        !          4768: /*
        !          4769:  * Wrapper for fifo close
        !          4770:  *
        !          4771:  * Update the times on the hfsnode then do device close.
        !          4772:  */
        !          4773: int
        !          4774: hfsfifo_close(ap)
        !          4775:        struct vop_close_args /* {
        !          4776:                struct vnode *a_vp;
        !          4777:                int  a_fflag;
        !          4778:                struct ucred *a_cred;
        !          4779:                struct proc *a_p;
        !          4780:        } */ *ap;
        !          4781: {
        !          4782:        extern int (**fifo_vnodeop_p)();
        !          4783:        struct vnode *vp = ap->a_vp;
        !          4784:        struct hfsnode *hp = VTOH(vp);
        !          4785: 
        !          4786:        simple_lock(&vp->v_interlock);
        !          4787:        if (ap->a_vp->v_usecount > 1)
        !          4788:                HFSTIMES(hp, &time, &time);
        !          4789:        simple_unlock(&vp->v_interlock);
        !          4790:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
        !          4791: }
        !          4792: #endif /* FIFO */
        !          4793: 
        !          4794: 
        !          4795: /*****************************************************************************
        !          4796: *
        !          4797: *      VOP Tables
        !          4798: *
        !          4799: *****************************************************************************/
        !          4800: 
        !          4801: struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
        !          4802:     { &vop_default_desc, vn_default_error },
        !          4803:     { &vop_lookup_desc, hfs_cache_lookup },                    /* lookup */
        !          4804:     { &vop_create_desc, hfs_create },                  /* create */
        !          4805:     { &vop_mknod_desc, hfs_mknod },                            /* mknod */
        !          4806:     { &vop_open_desc, hfs_open },                              /* open */
        !          4807:     { &vop_close_desc, hfs_close },                            /* close */
        !          4808:     { &vop_access_desc, hfs_access },                  /* access */
        !          4809:     { &vop_getattr_desc, hfs_getattr },                        /* getattr */
        !          4810:     { &vop_setattr_desc, hfs_setattr },                        /* setattr */
        !          4811:     { &vop_read_desc, hfs_read },                              /* read */
        !          4812:     { &vop_write_desc, hfs_write },                            /* write */
        !          4813:     { &vop_ioctl_desc, hfs_ioctl },                            /* ioctl */
        !          4814:     { &vop_select_desc, hfs_select },                  /* select */
        !          4815:     { &vop_exchange_desc, hfs_exchange },              /* exchange */
        !          4816:     { &vop_mmap_desc, hfs_mmap },                              /* mmap */
        !          4817:     { &vop_fsync_desc, hfs_fsync },                            /* fsync */
        !          4818:     { &vop_seek_desc, hfs_seek },                              /* seek */
        !          4819:     { &vop_remove_desc, hfs_remove },                  /* remove */
        !          4820: #if HFS_HARDLINKS
        !          4821:     { &vop_link_desc, hfs_link },                      /* link */
        !          4822: #else
        !          4823:     { &vop_link_desc, err_link },                      /* link (NOT SUPPORTED) */
        !          4824: #endif
        !          4825:     { &vop_rename_desc, hfs_rename },                  /* rename */
        !          4826:     { &vop_mkdir_desc, hfs_mkdir },                            /* mkdir */
        !          4827:     { &vop_rmdir_desc, hfs_rmdir },                            /* rmdir */
        !          4828:     { &vop_mkcomplex_desc,hfs_mkcomplex },             /* mkcomplex */
        !          4829:     { &vop_getattrlist_desc,hfs_getattrlist },  /* getattrlist */
        !          4830:     { &vop_setattrlist_desc,hfs_setattrlist },  /* setattrlist */
        !          4831:     { &vop_symlink_desc, hfs_symlink },                        /* symlink */
        !          4832:     { &vop_readdir_desc, hfs_readdir },                        /* readdir */
        !          4833:     { &vop_readdirattr_desc, hfs_readdirattr },        /* readdirattr */
        !          4834:     { &vop_readlink_desc, hfs_readlink },              /* readlink */
        !          4835:     { &vop_abortop_desc, hfs_abortop },                        /* abortop */
        !          4836:     { &vop_inactive_desc, hfs_inactive },              /* inactive */
        !          4837:     { &vop_reclaim_desc, hfs_reclaim },                        /* reclaim */
        !          4838:     { &vop_lock_desc, hfs_lock },                              /* lock */
        !          4839:     { &vop_unlock_desc, hfs_unlock },                  /* unlock */
        !          4840:     { &vop_bmap_desc, hfs_bmap },                              /* bmap */
        !          4841:     { &vop_strategy_desc, hfs_strategy },              /* strategy */
        !          4842:     { &vop_print_desc, hfs_print },                            /* print */
        !          4843:     { &vop_islocked_desc, hfs_islocked },              /* islocked */
        !          4844:     { &vop_pathconf_desc, hfs_pathconf },              /* pathconf */
        !          4845:     { &vop_advlock_desc, hfs_advlock },                        /* advlock */
        !          4846:     { &vop_reallocblks_desc, hfs_reallocblks },        /* reallocblks */
        !          4847:     { &vop_truncate_desc, hfs_truncate },              /* truncate */
        !          4848:     { &vop_allocate_desc, hfs_allocate },              /* allocate */
        !          4849:     { &vop_update_desc, hfs_update },                  /* update */
        !          4850:     { &vop_searchfs_desc,hfs_search },                 /* search fs */
        !          4851:     { &vop_bwrite_desc, vn_bwrite },                   /* bwrite */
        !          4852:     { &vop_pagein_desc, hfs_pagein },           /* pagein */
        !          4853:     { &vop_pageout_desc, hfs_pageout },         /* pageout */
        !          4854:     { &vop_copyfile_desc, err_copyfile },         /* copyfile */
        !          4855:     { NULL, NULL }
        !          4856: };
        !          4857: 
        !          4858: struct vnodeopv_desc hfs_vnodeop_opv_desc =
        !          4859: { &hfs_vnodeop_p, hfs_vnodeop_entries };
        !          4860: 
        !          4861: int (**hfs_specop_p)();
        !          4862: struct vnodeopv_entry_desc hfs_specop_entries[] = {
        !          4863:        { &vop_default_desc, vn_default_error },
        !          4864:        { &vop_lookup_desc, spec_lookup },              /* lookup */
        !          4865:        { &vop_create_desc, spec_create },              /* create */
        !          4866:        { &vop_mknod_desc, spec_mknod },                /* mknod */
        !          4867:        { &vop_open_desc, spec_open },                  /* open */
        !          4868:        { &vop_close_desc, hfsspec_close },             /* close */
        !          4869:        { &vop_access_desc, hfs_access },               /* access */
        !          4870:        { &vop_getattr_desc, hfs_getattr },             /* getattr */
        !          4871:        { &vop_setattr_desc, hfs_setattr },             /* setattr */
        !          4872:        { &vop_read_desc, hfsspec_read },               /* read */
        !          4873:        { &vop_write_desc, hfsspec_write },             /* write */
        !          4874:        { &vop_lease_desc, spec_lease_check },          /* lease */
        !          4875:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
        !          4876:        { &vop_select_desc, spec_select },              /* select */
        !          4877:        { &vop_revoke_desc, spec_revoke },              /* revoke */
        !          4878:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
        !          4879:        { &vop_fsync_desc, hfs_fsync },                 /* fsync */
        !          4880:        { &vop_seek_desc, spec_seek },                  /* seek */
        !          4881:        { &vop_remove_desc, spec_remove },              /* remove */
        !          4882:        { &vop_link_desc, spec_link },                  /* link */
        !          4883:        { &vop_rename_desc, spec_rename },              /* rename */
        !          4884:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
        !          4885:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
        !          4886:        { &vop_symlink_desc, spec_symlink },            /* symlink */
        !          4887:        { &vop_readdir_desc, spec_readdir },            /* readdir */
        !          4888:        { &vop_readlink_desc, spec_readlink },          /* readlink */
        !          4889:        { &vop_abortop_desc, spec_abortop },            /* abortop */
        !          4890:        { &vop_inactive_desc, hfs_inactive },           /* inactive */
        !          4891:        { &vop_reclaim_desc, hfs_reclaim },             /* reclaim */
        !          4892:        { &vop_lock_desc, hfs_lock },                   /* lock */
        !          4893:        { &vop_unlock_desc, hfs_unlock },               /* unlock */
        !          4894:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
        !          4895:        { &vop_strategy_desc, spec_strategy },          /* strategy */
        !          4896:        { &vop_print_desc, hfs_print },                 /* print */
        !          4897:        { &vop_islocked_desc, hfs_islocked },           /* islocked */
        !          4898:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
        !          4899:        { &vop_advlock_desc, spec_advlock },            /* advlock */
        !          4900:        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
        !          4901:        { &vop_valloc_desc, spec_valloc },              /* valloc */
        !          4902:        { &vop_reallocblks_desc, spec_reallocblks },    /* reallocblks */
        !          4903:        { &vop_vfree_desc, err_vfree },                 /* vfree */
        !          4904:        { &vop_truncate_desc, spec_truncate },          /* truncate */
        !          4905:        { &vop_update_desc, hfs_update },               /* update */
        !          4906:        { &vop_bwrite_desc, vn_bwrite },
        !          4907: #ifdef NeXT
        !          4908:        { &vop_devblocksize_desc, spec_devblocksize },  /* devblocksize */
        !          4909: #endif /* NeXT */
        !          4910:        { &vop_pagein_desc, hfs_pagein },               /* Pagein */
        !          4911:        { &vop_pageout_desc, hfs_pageout },             /* Pageout */
        !          4912:         { &vop_copyfile_desc, err_copyfile },         /* copyfile */
        !          4913:        { (struct vnodeop_desc*)NULL, (int(*)())NULL }
        !          4914: };
        !          4915: struct vnodeopv_desc hfs_specop_opv_desc =
        !          4916:        { &hfs_specop_p, hfs_specop_entries };
        !          4917: 
        !          4918: #if FIFO
        !          4919: int (**hfs_fifoop_p)();
        !          4920: struct vnodeopv_entry_desc hfs_fifoop_entries[] = {
        !          4921:        { &vop_default_desc, vn_default_error },
        !          4922:        { &vop_lookup_desc, fifo_lookup },              /* lookup */
        !          4923:        { &vop_create_desc, fifo_create },              /* create */
        !          4924:        { &vop_mknod_desc, fifo_mknod },                /* mknod */
        !          4925:        { &vop_open_desc, fifo_open },                  /* open */
        !          4926:        { &vop_close_desc, hfsfifo_close },             /* close */
        !          4927:        { &vop_access_desc, hfs_access },               /* access */
        !          4928:        { &vop_getattr_desc, hfs_getattr },             /* getattr */
        !          4929:        { &vop_setattr_desc, hfs_setattr },             /* setattr */
        !          4930:        { &vop_read_desc, hfsfifo_read },               /* read */
        !          4931:        { &vop_write_desc, hfsfifo_write },             /* write */
        !          4932:        { &vop_lease_desc, fifo_lease_check },          /* lease */
        !          4933:        { &vop_ioctl_desc, fifo_ioctl },                /* ioctl */
        !          4934:        { &vop_select_desc, fifo_select },              /* select */
        !          4935:        { &vop_revoke_desc, fifo_revoke },              /* revoke */
        !          4936:        { &vop_mmap_desc, fifo_mmap },                  /* mmap */
        !          4937:        { &vop_fsync_desc, hfs_fsync },                 /* fsync */
        !          4938:        { &vop_seek_desc, fifo_seek },                  /* seek */
        !          4939:        { &vop_remove_desc, fifo_remove },              /* remove */
        !          4940:        { &vop_link_desc, fifo_link },                  /* link */
        !          4941:        { &vop_rename_desc, fifo_rename },              /* rename */
        !          4942:        { &vop_mkdir_desc, fifo_mkdir },                /* mkdir */
        !          4943:        { &vop_rmdir_desc, fifo_rmdir },                /* rmdir */
        !          4944:        { &vop_symlink_desc, fifo_symlink },            /* symlink */
        !          4945:        { &vop_readdir_desc, fifo_readdir },            /* readdir */
        !          4946:        { &vop_readlink_desc, fifo_readlink },          /* readlink */
        !          4947:        { &vop_abortop_desc, fifo_abortop },            /* abortop */
        !          4948:        { &vop_inactive_desc, hfs_inactive },           /* inactive */
        !          4949:        { &vop_reclaim_desc, hfs_reclaim },             /* reclaim */
        !          4950:        { &vop_lock_desc, hfs_lock },                   /* lock */
        !          4951:        { &vop_unlock_desc, hfs_unlock },               /* unlock */
        !          4952:        { &vop_bmap_desc, fifo_bmap },                  /* bmap */
        !          4953:        { &vop_strategy_desc, fifo_strategy },          /* strategy */
        !          4954:        { &vop_print_desc, hfs_print },                 /* print */
        !          4955:        { &vop_islocked_desc, hfs_islocked },           /* islocked */
        !          4956:        { &vop_pathconf_desc, fifo_pathconf },          /* pathconf */
        !          4957:        { &vop_advlock_desc, fifo_advlock },            /* advlock */
        !          4958:        { &vop_blkatoff_desc, fifo_blkatoff },          /* blkatoff */
        !          4959:        { &vop_valloc_desc, fifo_valloc },              /* valloc */
        !          4960:        { &vop_reallocblks_desc, fifo_reallocblks },    /* reallocblks */
        !          4961:        { &vop_vfree_desc, err_vfree },                 /* vfree */
        !          4962:        { &vop_truncate_desc, fifo_truncate },          /* truncate */
        !          4963:        { &vop_update_desc, hfs_update },               /* update */
        !          4964:        { &vop_bwrite_desc, vn_bwrite },
        !          4965:        { &vop_pagein_desc, hfs_pagein },               /* Pagein */
        !          4966:        { &vop_pageout_desc, hfs_pageout },             /* Pageout */
        !          4967:         { &vop_copyfile_desc, err_copyfile },         /* copyfile */
        !          4968:        { (struct vnodeop_desc*)NULL, (int(*)())NULL }
        !          4969: };
        !          4970: struct vnodeopv_desc hfs_fifoop_opv_desc =
        !          4971:        { &hfs_fifoop_p, hfs_fifoop_entries };
        !          4972: #endif /* FIFO */
        !          4973: 
        !          4974: 
        !          4975: 

unix.superglobalmegacorp.com

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