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