Annotation of XNU/bsd/hfs/hfs_vnodeops.c, revision 1.1.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.