Annotation of kernel/bsd/hfs/hfs_vnodeops.c, revision 1.1

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

unix.superglobalmegacorp.com

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